summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk3
-rw-r--r--CleanSpec.mk1
-rw-r--r--core/java/android/accounts/AccountAuthenticatorCache.java38
-rw-r--r--core/java/android/accounts/AccountManager.java18
-rw-r--r--core/java/android/accounts/AccountManagerService.java166
-rw-r--r--core/java/android/accounts/AuthenticatorDescription.java20
-rw-r--r--core/java/android/app/ContextImpl.java16
-rw-r--r--core/java/android/app/Dialog.java2
-rw-r--r--core/java/android/content/Context.java11
-rw-r--r--core/java/android/content/SyncManager.java7
-rw-r--r--core/java/android/content/SyncStorageEngine.java26
-rw-r--r--core/java/android/content/pm/PackageManager.java7
-rw-r--r--core/java/android/content/res/AssetManager.java1
-rw-r--r--core/java/android/hardware/SensorManager.java7
-rw-r--r--core/java/android/hardware/Usb.java99
-rw-r--r--core/java/android/hardware/usb/IUsbManager.aidl58
-rw-r--r--core/java/android/hardware/usb/UsbAccessory.aidl19
-rw-r--r--core/java/android/hardware/usb/UsbAccessory.java192
-rw-r--r--core/java/android/hardware/usb/UsbManager.java295
-rw-r--r--core/java/android/net/ConnectivityManager.java4
-rw-r--r--core/java/android/net/InterfaceConfiguration.java18
-rw-r--r--core/java/android/net/MobileDataStateTracker.java4
-rw-r--r--core/java/android/net/NetworkStateTracker.java4
-rw-r--r--core/java/android/net/NetworkUtils.java12
-rw-r--r--core/java/android/net/wimax/WimaxManagerConstants.java103
-rw-r--r--core/java/android/nfc/ApduList.aidl19
-rw-r--r--core/java/android/nfc/ApduList.java68
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl11
-rwxr-xr-xcore/java/android/nfc/INfcAdapterExtras.aidl34
-rw-r--r--core/java/android/nfc/NfcAdapter.java41
-rwxr-xr-xcore/java/android/nfc/NfcSecureElement.java138
-rw-r--r--core/java/android/nfc/tech/Ndef.java9
-rw-r--r--core/java/android/nfc/tech/package.html13
-rw-r--r--core/java/android/os/BatteryStats.java44
-rw-r--r--core/java/android/os/Looper.java19
-rw-r--r--core/java/android/os/Process.java2
-rw-r--r--core/java/android/os/RecoverySystem.java25
-rw-r--r--core/java/android/pim/ICalendar.java17
-rw-r--r--core/java/android/provider/Settings.java20
-rwxr-xr-xcore/java/android/provider/Telephony.java15
-rw-r--r--core/java/android/speech/RecognitionService.java14
-rwxr-xr-xcore/java/android/text/Layout.java2
-rw-r--r--core/java/android/text/TextUtils.java12
-rw-r--r--core/java/android/text/method/MultiTapKeyListener.java8
-rw-r--r--core/java/android/text/style/DrawableMarginSpan.java3
-rw-r--r--core/java/android/util/SparseArray.java11
-rw-r--r--core/java/android/view/ViewRoot.java9
-rw-r--r--core/java/android/webkit/FrameLoader.java3
-rw-r--r--core/java/android/webkit/WebSettings.java23
-rw-r--r--core/java/android/widget/DatePicker.java39
-rw-r--r--core/java/android/widget/PopupWindow.java4
-rw-r--r--core/java/android/widget/TextView.java31
-rw-r--r--core/java/com/android/internal/app/ResolverActivity.java21
-rw-r--r--core/java/com/android/internal/os/BatteryStatsImpl.java126
-rw-r--r--core/java/com/android/internal/os/ZygoteInit.java2
-rwxr-xr-x[-rw-r--r--]core/java/com/google/android/mms/pdu/PduParser.java74
-rw-r--r--core/jni/android/graphics/Movie.cpp5
-rw-r--r--core/jni/android_net_NetUtils.cpp32
-rw-r--r--core/jni/android_util_Binder.cpp9
-rw-r--r--core/res/AndroidManifest.xml45
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.pngbin0 -> 1767 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_inandout_4g.pngbin0 -> 1817 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.pngbin0 -> 2219 bytes
-rw-r--r--core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.pngbin0 -> 1807 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.pngbin0 -> 1444 bytes
-rw-r--r--core/res/res/drawable-mdpi/stat_sys_data_inandout_4g.pngbin0 -> 1468 bytes
-rw-r--r--core/res/res/layout/contact_header.xml1
-rw-r--r--core/res/res/values-ar/strings.xml9
-rw-r--r--core/res/res/values-bg/strings.xml9
-rw-r--r--core/res/res/values-ca/strings.xml19
-rw-r--r--core/res/res/values-cs/strings.xml9
-rw-r--r--core/res/res/values-da/strings.xml9
-rw-r--r--core/res/res/values-de/strings.xml209
-rw-r--r--core/res/res/values-el/strings.xml9
-rw-r--r--core/res/res/values-en-rGB/strings.xml11
-rw-r--r--core/res/res/values-es-rUS/strings.xml47
-rw-r--r--core/res/res/values-es/strings.xml9
-rw-r--r--core/res/res/values-fa/strings.xml9
-rw-r--r--core/res/res/values-fi/strings.xml9
-rw-r--r--core/res/res/values-fr/strings.xml83
-rw-r--r--core/res/res/values-hr/strings.xml11
-rw-r--r--core/res/res/values-hu/strings.xml9
-rw-r--r--core/res/res/values-in/strings.xml13
-rw-r--r--core/res/res/values-it/strings.xml11
-rw-r--r--core/res/res/values-iw/strings.xml27
-rw-r--r--core/res/res/values-ja/strings.xml15
-rw-r--r--core/res/res/values-ko/strings.xml11
-rw-r--r--core/res/res/values-lt/strings.xml9
-rw-r--r--core/res/res/values-lv/strings.xml9
-rw-r--r--core/res/res/values-nb/strings.xml15
-rw-r--r--core/res/res/values-nl/strings.xml273
-rw-r--r--core/res/res/values-pl/strings.xml21
-rw-r--r--core/res/res/values-pt-rPT/strings.xml9
-rw-r--r--core/res/res/values-pt/strings.xml9
-rw-r--r--core/res/res/values-rm/strings.xml16
-rw-r--r--core/res/res/values-ro/strings.xml9
-rw-r--r--core/res/res/values-ru/strings.xml31
-rw-r--r--core/res/res/values-sk/strings.xml9
-rw-r--r--core/res/res/values-sl/strings.xml9
-rw-r--r--core/res/res/values-sr/strings.xml9
-rw-r--r--core/res/res/values-sv/strings.xml55
-rw-r--r--core/res/res/values-th/strings.xml9
-rw-r--r--core/res/res/values-tl/strings.xml9
-rw-r--r--core/res/res/values-tr/strings.xml13
-rw-r--r--core/res/res/values-uk/strings.xml9
-rw-r--r--core/res/res/values-vi/strings.xml9
-rw-r--r--core/res/res/values-zh-rCN/strings.xml9
-rw-r--r--core/res/res/values-zh-rTW/strings.xml51
-rwxr-xr-x[-rw-r--r--]core/res/res/values/config.xml39
-rwxr-xr-xcore/res/res/values/strings.xml18
-rw-r--r--core/tests/ConnectivityManagerTest/Android.mk2
-rw-r--r--core/tests/ConnectivityManagerTest/AndroidManifest.xml7
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java54
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java144
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java49
-rw-r--r--core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java285
-rw-r--r--core/tests/coretests/AndroidManifest.xml6
-rw-r--r--core/tests/coretests/res/layout/attach_view_test.xml12
-rw-r--r--core/tests/coretests/src/android/text/TextUtilsTest.java46
-rw-r--r--core/tests/coretests/src/android/view/ViewAttachTest.java54
-rw-r--r--core/tests/coretests/src/android/view/ViewAttachTestActivity.java31
-rw-r--r--core/tests/coretests/src/android/view/ViewAttachView.java80
-rw-r--r--core/tests/overlaytests/Android.mk4
-rw-r--r--core/tests/overlaytests/OverlayTest/Android.mk10
-rw-r--r--core/tests/overlaytests/OverlayTest/AndroidManifest.xml10
-rw-r--r--core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java118
-rw-r--r--core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java7
-rw-r--r--core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java7
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/Android.mk14
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml6
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpgbin0 -> 399 bytes
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml4
-rw-r--r--core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml13
-rw-r--r--core/tests/overlaytests/README15
-rwxr-xr-xcore/tests/overlaytests/runtests.sh89
-rw-r--r--data/etc/android.hardware.usb.accessory.xml22
-rw-r--r--data/fonts/DroidSans-Bold.ttfbin191032 -> 194488 bytes
-rw-r--r--data/fonts/DroidSans.ttfbin190044 -> 190776 bytes
-rw-r--r--data/fonts/DroidSansArabic.ttfbin35908 -> 35880 bytes
-rw-r--r--data/fonts/DroidSansFallback.ttfbin3640264 -> 3725920 bytes
-rw-r--r--data/fonts/DroidSansMono.ttfbin117072 -> 119380 bytes
-rw-r--r--data/fonts/DroidSerif-Bold.ttfbin184836 -> 185228 bytes
-rw-r--r--data/fonts/DroidSerif-BoldItalic.ttfbin189916 -> 190304 bytes
-rw-r--r--data/fonts/DroidSerif-Italic.ttfbin177176 -> 177560 bytes
-rw-r--r--data/fonts/DroidSerif-Regular.ttfbin172532 -> 172916 bytes
-rw-r--r--docs/html/guide/developing/tools/traceview.jd4
-rwxr-xr-xdocs/html/guide/market/billing/billing_integrate.jd2
-rw-r--r--docs/html/guide/topics/nfc/index.jd111
-rw-r--r--docs/html/sdk/index.jd2
-rw-r--r--graphics/java/android/graphics/Movie.java11
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java4
-rw-r--r--include/utils/AssetManager.h11
-rw-r--r--include/utils/RefBase.h62
-rw-r--r--include/utils/ResourceTypes.h26
-rw-r--r--libs/ui/GraphicBufferAllocator.cpp2
-rw-r--r--libs/ui/InputDispatcher.cpp32
-rw-r--r--libs/ui/InputReader.cpp12
-rw-r--r--libs/usb/Android.mk27
-rw-r--r--libs/usb/src/com/android/future/usb/UsbAccessory.java136
-rw-r--r--libs/usb/src/com/android/future/usb/UsbManager.java186
-rw-r--r--libs/usb/tests/AccessoryChat/Android.mk31
-rw-r--r--libs/usb/tests/AccessoryChat/AndroidManifest.xml39
-rw-r--r--libs/usb/tests/AccessoryChat/README.txt10
-rw-r--r--libs/usb/tests/AccessoryChat/accessorychat/Android.mk21
-rw-r--r--libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c196
-rw-r--r--libs/usb/tests/AccessoryChat/accessorychat/usbhost.c574
-rw-r--r--libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h219
-rw-r--r--libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml47
-rw-r--r--libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml18
-rw-r--r--libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java199
-rw-r--r--libs/utils/AssetManager.cpp237
-rw-r--r--libs/utils/README275
-rw-r--r--libs/utils/RefBase.cpp2
-rw-r--r--libs/utils/ResourceTypes.cpp404
-rw-r--r--media/java/android/media/ExifInterface.java32
-rw-r--r--media/libstagefright/AudioSource.cpp5
-rw-r--r--media/libstagefright/AwesomePlayer.cpp2
-rw-r--r--media/libstagefright/HTTPStream.cpp56
-rw-r--r--media/libstagefright/MP3Extractor.cpp49
-rw-r--r--media/libstagefright/NuCachedSource2.cpp34
-rw-r--r--media/libstagefright/NuHTTPDataSource.cpp16
-rw-r--r--media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp6
-rw-r--r--media/libstagefright/include/NuCachedSource2.h2
-rw-r--r--media/libstagefright/include/NuHTTPDataSource.h16
-rw-r--r--media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp2
-rw-r--r--media/libstagefright/rtsp/APacketSource.cpp2
-rw-r--r--media/libstagefright/rtsp/ARTPConnection.cpp4
-rw-r--r--media/libstagefright/rtsp/ARTPSource.cpp2
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.cpp88
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.h2
-rw-r--r--media/libstagefright/rtsp/ASessionDescription.cpp5
-rw-r--r--media/libstagefright/rtsp/MyHandler.h118
-rw-r--r--nfc-extras/Android.mk14
-rw-r--r--nfc-extras/com.android.nfc_extras.xml20
-rw-r--r--nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java204
-rw-r--r--nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java125
-rw-r--r--obex/javax/obex/ClientSession.java4
-rw-r--r--obex/javax/obex/ObexHelper.java6
-rw-r--r--packages/SystemUI/AndroidManifest.xml36
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.pngbin0 -> 1698 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.pngbin0 -> 1635 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.pngbin0 -> 1745 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.pngbin0 -> 1767 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.pngbin0 -> 1759 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_inadnout_e.pngbin0 -> 1051 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_out_4g.pngbin0 -> 1796 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.pngbin0 -> 2060 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.pngbin0 -> 2050 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.pngbin0 -> 2156 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.pngbin0 -> 2118 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.pngbin0 -> 2220 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.pngbin0 -> 2202 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.pngbin0 -> 2346 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.pngbin0 -> 2219 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.pngbin0 -> 1807 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.pngbin0 -> 1663 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.pngbin443 -> 1491 bytes
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.pngbin443 -> 1491 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.pngbin719 -> 1412 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.pngbin765 -> 1419 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.pngbin0 -> 1381 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.pngbin673 -> 1324 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.pngbin688 -> 1334 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.pngbin649 -> 1329 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.pngbin712 -> 1380 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.pngbin743 -> 1415 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.pngbin0 -> 1545 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.pngbin660 -> 1329 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.pngbin663 -> 1327 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.pngbin650 -> 1327 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.pngbin792 -> 1465 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.pngbin809 -> 1472 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.pngbin0 -> 1439 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.pngbin736 -> 1383 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.pngbin736 -> 1387 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.pngbin731 -> 1394 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.pngbin795 -> 1475 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.pngbin830 -> 1464 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.pngbin0 -> 1444 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.pngbin746 -> 1413 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.pngbin753 -> 1405 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.pngbin739 -> 1409 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.pngbin799 -> 1450 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.pngbin836 -> 1441 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.pngbin0 -> 1419 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.pngbin759 -> 1381 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.pngbin765 -> 1379 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.pngbin747 -> 1379 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.pngbin767 -> 1486 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.pngbin809 -> 1478 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.pngbin0 -> 1440 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.pngbin753 -> 1398 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.pngbin748 -> 1404 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.pngbin736 -> 1402 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.pngbin0 -> 1429 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.pngbin773 -> 1504 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.pngbin832 -> 1498 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.pngbin0 -> 1468 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.pngbin776 -> 1436 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.pngbin761 -> 1430 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.pngbin754 -> 1481 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.pngbin832 -> 1482 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.pngbin0 -> 1448 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.pngbin746 -> 1408 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.pngbin757 -> 1419 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.pngbin733 -> 1411 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.pngbin377 -> 1284 bytes
-rwxr-xr-xpackages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.pngbin377 -> 1284 bytes
-rw-r--r--packages/SystemUI/res/values-ar/strings.xml10
-rw-r--r--packages/SystemUI/res/values-bg/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ca/strings.xml10
-rw-r--r--packages/SystemUI/res/values-cs/strings.xml10
-rw-r--r--packages/SystemUI/res/values-da/strings.xml10
-rw-r--r--packages/SystemUI/res/values-de/strings.xml10
-rw-r--r--packages/SystemUI/res/values-el/strings.xml10
-rw-r--r--packages/SystemUI/res/values-en-rGB/strings.xml10
-rw-r--r--packages/SystemUI/res/values-es-rUS/strings.xml10
-rw-r--r--packages/SystemUI/res/values-es/strings.xml10
-rw-r--r--packages/SystemUI/res/values-fa/strings.xml10
-rw-r--r--packages/SystemUI/res/values-fi/strings.xml10
-rw-r--r--packages/SystemUI/res/values-fr/strings.xml10
-rw-r--r--packages/SystemUI/res/values-hr/strings.xml10
-rw-r--r--packages/SystemUI/res/values-hu/strings.xml10
-rw-r--r--packages/SystemUI/res/values-in/strings.xml10
-rw-r--r--packages/SystemUI/res/values-it/strings.xml10
-rw-r--r--packages/SystemUI/res/values-iw/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ja/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ko/strings.xml12
-rw-r--r--packages/SystemUI/res/values-lt/strings.xml10
-rw-r--r--packages/SystemUI/res/values-lv/strings.xml10
-rw-r--r--packages/SystemUI/res/values-nb/strings.xml10
-rw-r--r--packages/SystemUI/res/values-nl/strings.xml10
-rw-r--r--packages/SystemUI/res/values-pl/strings.xml10
-rw-r--r--packages/SystemUI/res/values-pt-rPT/strings.xml10
-rw-r--r--packages/SystemUI/res/values-pt/strings.xml10
-rw-r--r--packages/SystemUI/res/values-rm/strings.xml14
-rw-r--r--packages/SystemUI/res/values-ro/strings.xml10
-rw-r--r--packages/SystemUI/res/values-ru/strings.xml10
-rw-r--r--packages/SystemUI/res/values-sk/strings.xml10
-rw-r--r--packages/SystemUI/res/values-sl/strings.xml10
-rw-r--r--packages/SystemUI/res/values-sr/strings.xml10
-rw-r--r--packages/SystemUI/res/values-sv/strings.xml10
-rw-r--r--packages/SystemUI/res/values-th/strings.xml10
-rw-r--r--packages/SystemUI/res/values-tl/strings.xml10
-rw-r--r--packages/SystemUI/res/values-tr/strings.xml10
-rw-r--r--packages/SystemUI/res/values-uk/strings.xml10
-rw-r--r--packages/SystemUI/res/values-vi/strings.xml10
-rw-r--r--packages/SystemUI/res/values-zh-rCN/strings.xml10
-rw-r--r--packages/SystemUI/res/values-zh-rTW/strings.xml10
-rw-r--r--packages/SystemUI/res/values/strings.xml21
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java255
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java100
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java143
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java52
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java153
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java108
-rw-r--r--packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java8
-rw-r--r--policy/src/com/android/internal/policy/impl/GlobalActions.java7
-rw-r--r--services/audioflinger/AudioResampler.cpp8
-rw-r--r--services/java/com/android/server/ConnectivityService.java249
-rwxr-xr-xservices/java/com/android/server/NotificationManagerService.java14
-rw-r--r--services/java/com/android/server/SystemServer.java12
-rw-r--r--services/java/com/android/server/UsbObserver.java207
-rw-r--r--services/java/com/android/server/WindowManagerService.java4
-rw-r--r--[-rwxr-xr-x]services/java/com/android/server/am/ActivityManagerService.java20
-rw-r--r--services/java/com/android/server/connectivity/Tethering.java39
-rwxr-xr-xservices/java/com/android/server/location/GpsLocationProvider.java2
-rw-r--r--services/java/com/android/server/usb/UsbDeviceSettingsManager.java671
-rw-r--r--services/java/com/android/server/usb/UsbService.java480
-rw-r--r--services/jni/Android.mk1
-rw-r--r--services/jni/com_android_server_UsbService.cpp141
-rw-r--r--services/jni/onload.cpp2
-rw-r--r--services/surfaceflinger/Layer.cpp12
-rw-r--r--services/surfaceflinger/LayerBase.cpp12
-rw-r--r--services/surfaceflinger/LayerBase.h2
-rw-r--r--services/surfaceflinger/LayerBuffer.cpp3
-rw-r--r--services/surfaceflinger/SurfaceFlinger.cpp47
-rw-r--r--services/surfaceflinger/SurfaceFlinger.h1
-rw-r--r--services/surfaceflinger/TextureManager.cpp2
-rw-r--r--telephony/java/android/telephony/JapanesePhoneNumberFormatter.java8
-rw-r--r--telephony/java/com/android/internal/telephony/CommandsInterface.java8
-rw-r--r--telephony/java/com/android/internal/telephony/IccUtils.java1
-rw-r--r--telephony/java/com/android/internal/telephony/RIL.java22
-rw-r--r--telephony/java/com/android/internal/telephony/RILConstants.java5
-rwxr-xr-xtelephony/java/com/android/internal/telephony/cdma/CDMAPhone.java9
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java9
-rw-r--r--telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java3
-rwxr-xr-x[-rw-r--r--]telephony/java/com/android/internal/telephony/cdma/RuimRecords.java44
-rwxr-xr-x[-rw-r--r--]telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java33
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/ApnSetting.java103
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java16
-rw-r--r--telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java11
-rwxr-xr-xtelephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java9
-rw-r--r--telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java2
-rw-r--r--telephony/java/com/android/internal/telephony/test/SimulatedCommands.java5
-rw-r--r--telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/ApnSettingTest.java108
-rw-r--r--tools/aapt/Bundle.h4
-rw-r--r--tools/aapt/Main.cpp5
-rw-r--r--tools/aapt/ResourceTable.cpp4
-rw-r--r--tools/aapt/XMLNode.cpp3
-rw-r--r--tools/layoutlib/.gitignore3
-rw-r--r--tools/layoutlib/README4
-rw-r--r--tools/layoutlib/bridge/.classpath11
-rw-r--r--tools/layoutlib/bridge/Android.mk11
-rw-r--r--tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_wifi_signal_4_fully.pngbin0 -> 1195 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/hdpi/status_bar_background.9.pngbin0 -> 3233 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.pngbin0 -> 885 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/mdpi/status_bar_background.9.pngbin0 -> 204 bytes
-rw-r--r--tools/layoutlib/bridge/resources/bars/phone_system_bar.xml15
-rw-r--r--tools/layoutlib/bridge/resources/bars/title_bar.xml6
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java67
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java70
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap.java278
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java566
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java159
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapShader.java48
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java240
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java542
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas.java1279
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java1357
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ComposeShader.java53
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java83
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/DashPathEffect.java54
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java89
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java65
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java (renamed from tools/layoutlib/bridge/src/android/graphics/GradientShader.java)52
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java69
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LinearGradient.java173
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java219
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix.java1032
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java1129
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java225
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint.java1211
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java1163
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Path.java611
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java72
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java69
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java815
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java70
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java140
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/RadialGradient.java132
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java197
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java474
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Shader.java83
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java137
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java (renamed from tools/layoutlib/bridge/src/android/graphics/SweepGradient.java)126
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Typeface.java190
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java191
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java69
-rw-r--r--tools/layoutlib/bridge/src/android/os/Build_Delegate.java48
-rw-r--r--tools/layoutlib/bridge/src/android/os/Handler_Delegate.java57
-rw-r--r--tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java (renamed from tools/layoutlib/bridge/src/android/util/FloatMath.java)36
-rw-r--r--tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java165
-rw-r--r--tools/layoutlib/bridge/src/android/view/View_Delegate.java (renamed from tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode.java)34
-rw-r--r--tools/layoutlib/bridge/src/com/android/internal/util/XmlUtils_Delegate.java74
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java1174
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java18
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java190
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java212
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/LayoutResult.java126
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java107
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceValue.java67
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeAssetManager.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java)8
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java122
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java105
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java)692
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java (renamed from tools/layoutlib/bridge/src/android/view/BridgeInflater.java)110
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java142
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java)214
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java)304
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java92
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java116
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java)69
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlPullAttributes.java)24
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java263
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java53
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java46
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java146
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java)13
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java806
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java285
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java140
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java1059
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java (renamed from tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java)245
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Stack.java70
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/Debug.java23
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java376
-rw-r--r--tools/layoutlib/bridge/tests/.classpath10
-rw-r--r--tools/layoutlib/bridge/tests/.project17
-rw-r--r--tools/layoutlib/bridge/tests/Android.mk30
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java52
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java139
-rw-r--r--tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/button.9.pngbin3750 -> 0 bytes
-rw-r--r--tools/layoutlib/bridge/tests/src/android/graphics/Matrix_DelegateTest.java (renamed from tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java)27
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java197
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java (renamed from tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java)4
-rw-r--r--tools/layoutlib/bridge/tests/src/com/android/layoutlib/testdata/layout1.xml (renamed from tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/layout1.xml)0
-rw-r--r--tools/layoutlib/create/README.txt17
-rw-r--r--[-rwxr-xr-x]tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/LayoutlibDelegate.java (renamed from core/java/android/nfc/INfcSecureElement.aidl)17
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java155
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java163
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java94
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java358
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java65
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java34
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java26
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java21
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java53
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java12
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java409
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/LogTest.java27
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/MockLog.java43
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative.java45
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative_Delegate.java34
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java48
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_Delegate.java30
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_InnerClass_Delegate.java30
-rw-r--r--voip/jni/rtp/AudioGroup.cpp9
494 files changed, 26217 insertions, 10070 deletions
diff --git a/Android.mk b/Android.mk
index 7bf5db5..e727130 100644
--- a/Android.mk
+++ b/Android.mk
@@ -113,6 +113,7 @@ LOCAL_SRC_FILES += \
core/java/android/content/pm/IPackageMoveObserver.aidl \
core/java/android/content/pm/IPackageStatsObserver.aidl \
core/java/android/database/IContentObserver.aidl \
+ core/java/android/hardware/usb/IUsbManager.aidl \
core/java/android/net/IConnectivityManager.aidl \
core/java/android/net/INetworkManagementEventObserver.aidl \
core/java/android/net/IThrottleManager.aidl \
@@ -120,10 +121,10 @@ LOCAL_SRC_FILES += \
core/java/android/nfc/ILlcpServiceSocket.aidl \
core/java/android/nfc/ILlcpSocket.aidl \
core/java/android/nfc/INfcAdapter.aidl \
+ core/java/android/nfc/INfcAdapterExtras.aidl \
core/java/android/nfc/INfcTag.aidl \
core/java/android/nfc/IP2pInitiator.aidl \
core/java/android/nfc/IP2pTarget.aidl \
- core/java/android/nfc/INfcSecureElement.aidl \
core/java/android/os/IHardwareService.aidl \
core/java/android/os/IMessenger.aidl \
core/java/android/os/INetworkManagementService.aidl \
diff --git a/CleanSpec.mk b/CleanSpec.mk
index 2ee8f31..8c3b17e 100644
--- a/CleanSpec.mk
+++ b/CleanSpec.mk
@@ -73,6 +73,7 @@ $(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/androi
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/com/trustedlogic)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/android_stubs_current_intermediates/src/com/trustedlogic)
$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc/INdefTag.java)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/nfc)
# ************************************************
# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST
diff --git a/core/java/android/accounts/AccountAuthenticatorCache.java b/core/java/android/accounts/AccountAuthenticatorCache.java
index d2b3bc7..5ee1f60 100644
--- a/core/java/android/accounts/AccountAuthenticatorCache.java
+++ b/core/java/android/accounts/AccountAuthenticatorCache.java
@@ -18,17 +18,22 @@ package android.accounts;
import android.content.pm.PackageManager;
import android.content.pm.RegisteredServicesCache;
+import android.content.pm.ResolveInfo;
import android.content.pm.XmlSerializerAndParser;
import android.content.res.Resources;
import android.content.res.TypedArray;
+import android.content.ComponentName;
import android.content.Context;
+import android.content.Intent;
import android.util.AttributeSet;
+import android.util.Log;
import android.text.TextUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlSerializer;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
+import java.util.List;
/**
* A cache of services that export the {@link IAccountAuthenticator} interface. This cache
@@ -63,11 +68,40 @@ import java.io.IOException;
com.android.internal.R.styleable.AccountAuthenticator_smallIcon, 0);
final int prefId = sa.getResourceId(
com.android.internal.R.styleable.AccountAuthenticator_accountPreferences, 0);
+
+ boolean customTokens = false;
+ try {
+ // In HC this will be an attribute in authenticator.xml, this is a workaround
+ // using meta-data to avoid changes to the API.
+ // If meta-data is absent the old behavior is preserved.
+ // Authenticator will know if AccountManager supports customTokens or not.
+ PackageManager pm = mContext.getPackageManager();
+ List<ResolveInfo> resolveInfos = pm.queryIntentServices(
+ new Intent(AccountManager.ACTION_AUTHENTICATOR_INTENT),
+ PackageManager.GET_META_DATA);
+ for (ResolveInfo resolveInfo: resolveInfos) {
+ android.content.pm.ServiceInfo si = resolveInfo.serviceInfo;
+ if (!packageName.equals(si.packageName)) {
+ continue;
+ }
+ Object ctString = si.metaData.get(AccountManager.ACTION_AUTHENTICATOR_INTENT
+ + ".customTokens");
+ if (ctString != null) {
+ customTokens = true;
+ }
+ }
+ } catch (Throwable t) {
+ // Protected against invalid data in meta or unexpected
+ // conditions - the authenticator will not have the new
+ // features.
+ Log.e(TAG, "Error getting customTokens metadata " + t);
+ }
+
if (TextUtils.isEmpty(accountType)) {
return null;
}
- return new AuthenticatorDescription(accountType, packageName, labelId, iconId,
- smallIconId, prefId);
+ return new AuthenticatorDescription(accountType, packageName, labelId, iconId,
+ smallIconId, prefId, customTokens);
} finally {
sa.recycle();
}
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index fd3a0d0..677b959 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -188,6 +188,24 @@ public class AccountManager {
public static final String KEY_ERROR_CODE = "errorCode";
public static final String KEY_ERROR_MESSAGE = "errorMessage";
public static final String KEY_USERDATA = "userdata";
+ /**
+ * Authenticators using 'customTokens' option will also get the UID of the
+ * caller
+ * @hide
+ */
+ public static final String KEY_CALLER_UID = "callerUid";
+
+ /**
+ * @hide
+ */
+ public static final String KEY_CALLER_PID = "callerPid";
+
+ /**
+ * Boolean, if set and 'customTokens' the authenticator is responsible for
+ * notifications.
+ * @hide
+ */
+ public static final String KEY_NOTIFY_ON_FAILURE = "notifyOnAuthFailure";
public static final String ACTION_AUTHENTICATOR_INTENT =
"android.accounts.AccountAuthenticator";
diff --git a/core/java/android/accounts/AccountManagerService.java b/core/java/android/accounts/AccountManagerService.java
index 9a8cc15..5796042 100644
--- a/core/java/android/accounts/AccountManagerService.java
+++ b/core/java/android/accounts/AccountManagerService.java
@@ -91,6 +91,8 @@ public class AccountManagerService
private final Context mContext;
+ private final PackageManager mPackageManager;
+
private HandlerThread mMessageThread;
private final MessageHandler mMessageHandler;
@@ -99,7 +101,6 @@ public class AccountManagerService
private final AccountAuthenticatorCache mAuthenticatorCache;
private final DatabaseHelper mOpenHelper;
- private final SimWatcher mSimWatcher;
private static final String TABLE_ACCOUNTS = "accounts";
private static final String ACCOUNTS_ID = "_id";
@@ -214,6 +215,7 @@ public class AccountManagerService
public AccountManagerService(Context context) {
mContext = context;
+ mPackageManager = context.getPackageManager();
mOpenHelper = new DatabaseHelper(mContext);
@@ -224,7 +226,6 @@ public class AccountManagerService
mAuthenticatorCache = new AccountAuthenticatorCache(mContext);
mAuthenticatorCache.setListener(this, null /* Handler */);
- mSimWatcher = new SimWatcher(mContext);
sThis.set(this);
validateAccounts();
@@ -520,6 +521,18 @@ public class AccountManagerService
if (account == null) throw new IllegalArgumentException("account is null");
checkManageAccountsPermission();
long identityToken = clearCallingIdentity();
+
+ cancelNotification(getSigninRequiredNotificationId(account));
+ synchronized(mCredentialsPermissionNotificationIds) {
+ for (Pair<Pair<Account, String>, Integer> pair:
+ mCredentialsPermissionNotificationIds.keySet()) {
+ if (account.equals(pair.first.first)) {
+ int id = mCredentialsPermissionNotificationIds.get(pair);
+ cancelNotification(id);
+ }
+ }
+ }
+
try {
new RemoveAccountSession(response, account).bind();
} finally {
@@ -842,19 +855,49 @@ public class AccountManagerService
public void getAuthToken(IAccountManagerResponse response, final Account account,
final String authTokenType, final boolean notifyOnAuthFailure,
- final boolean expectActivityLaunch, final Bundle loginOptions) {
+ final boolean expectActivityLaunch, Bundle loginOptionsIn) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "getAuthToken: " + account
+ + ", response " + response
+ + ", authTokenType " + authTokenType
+ + ", notifyOnAuthFailure " + notifyOnAuthFailure
+ + ", expectActivityLaunch " + expectActivityLaunch
+ + ", caller's uid " + Binder.getCallingUid()
+ + ", pid " + Binder.getCallingPid());
+ }
if (response == null) throw new IllegalArgumentException("response is null");
if (account == null) throw new IllegalArgumentException("account is null");
if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
final int callerUid = Binder.getCallingUid();
- final boolean permissionGranted = permissionIsGranted(account, authTokenType, callerUid);
+ final int callerPid = Binder.getCallingPid();
+
+ AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
+ mAuthenticatorCache.getServiceInfo(
+ AuthenticatorDescription.newKey(account.type));
+ final boolean customTokens =
+ authenticatorInfo != null && authenticatorInfo.type.customTokens;
+
+ // skip the check if customTokens
+ final boolean permissionGranted = customTokens ||
+ permissionIsGranted(account, authTokenType, callerUid);
+
+ final Bundle loginOptions = (loginOptionsIn == null) ? new Bundle() :
+ loginOptionsIn;
+ if (customTokens) {
+ // let authenticator know the identity of the caller
+ loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
+ loginOptions.putInt(AccountManager.KEY_CALLER_PID, callerPid);
+ if (notifyOnAuthFailure) {
+ loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
+ }
+ }
long identityToken = clearCallingIdentity();
try {
// if the caller has permission, do the peek. otherwise go the more expensive
// route of starting a Session
- if (permissionGranted) {
+ if (!customTokens && permissionGranted) {
String authToken = readAuthTokenFromDatabase(account, authTokenType);
if (authToken != null) {
Bundle result = new Bundle();
@@ -908,12 +951,14 @@ public class AccountManagerService
"the type and name should not be empty");
return;
}
- saveAuthTokenToDatabase(new Account(name, type),
- authTokenType, authToken);
+ if (!customTokens) {
+ saveAuthTokenToDatabase(new Account(name, type),
+ authTokenType, authToken);
+ }
}
Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
- if (intent != null && notifyOnAuthFailure) {
+ if (intent != null && notifyOnAuthFailure && !customTokens) {
doNotification(
account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
intent);
@@ -972,6 +1017,10 @@ public class AccountManagerService
AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
+ // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
+ // Since it was set in Eclair+ we can't change it without breaking apps using
+ // the intent from a non-Activity context.
+ intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addCategory(
String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
@@ -1640,95 +1689,6 @@ public class AccountManagerService
}
}
- private class SimWatcher extends BroadcastReceiver {
- public SimWatcher(Context context) {
- // Re-scan the SIM card when the SIM state changes, and also if
- // the disk recovers from a full state (we may have failed to handle
- // things properly while the disk was full).
- final IntentFilter filter = new IntentFilter();
- filter.addAction(TelephonyIntents.ACTION_SIM_STATE_CHANGED);
- filter.addAction(Intent.ACTION_DEVICE_STORAGE_OK);
- context.registerReceiver(this, filter);
- }
-
- /**
- * Compare the IMSI to the one stored in the login service's
- * database. If they differ, erase all passwords and
- * authtokens (and store the new IMSI).
- */
- @Override
- public void onReceive(Context context, Intent intent) {
- // Check IMSI on every update; nothing happens if the IMSI
- // is missing or unchanged.
- TelephonyManager telephonyManager =
- (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
- if (telephonyManager == null) {
- Log.w(TAG, "failed to get TelephonyManager");
- return;
- }
- String imsi = telephonyManager.getSubscriberId();
-
- // If the subscriber ID is an empty string, don't do anything.
- if (TextUtils.isEmpty(imsi)) return;
-
- // If the current IMSI matches what's stored, don't do anything.
- String storedImsi = getMetaValue("imsi");
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "current IMSI=" + imsi + "; stored IMSI=" + storedImsi);
- }
- if (imsi.equals(storedImsi)) return;
-
- // If a CDMA phone is unprovisioned, getSubscriberId()
- // will return a different value, but we *don't* erase the
- // passwords. We only erase them if it has a different
- // subscriber ID once it's provisioned.
- if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
- IBinder service = ServiceManager.checkService(Context.TELEPHONY_SERVICE);
- if (service == null) {
- Log.w(TAG, "call to checkService(TELEPHONY_SERVICE) failed");
- return;
- }
- ITelephony telephony = ITelephony.Stub.asInterface(service);
- if (telephony == null) {
- Log.w(TAG, "failed to get ITelephony interface");
- return;
- }
- boolean needsProvisioning;
- try {
- needsProvisioning = telephony.getCdmaNeedsProvisioning();
- } catch (RemoteException e) {
- Log.w(TAG, "exception while checking provisioning", e);
- // default to NOT wiping out the passwords
- needsProvisioning = true;
- }
- if (needsProvisioning) {
- // if the phone needs re-provisioning, don't do anything.
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Log.v(TAG, "current IMSI=" + imsi + " (needs provisioning); stored IMSI=" +
- storedImsi);
- }
- return;
- }
- }
-
- if (!imsi.equals(storedImsi) && !TextUtils.isEmpty(storedImsi)) {
- Log.w(TAG, "wiping all passwords and authtokens because IMSI changed ("
- + "stored=" + storedImsi + ", current=" + imsi + ")");
- SQLiteDatabase db = mOpenHelper.getWritableDatabase();
- db.beginTransaction();
- try {
- db.execSQL("DELETE from " + TABLE_AUTHTOKENS);
- db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_PASSWORD + " = ''");
- sendAccountsChangedBroadcast();
- db.setTransactionSuccessful();
- } finally {
- db.endTransaction();
- }
- }
- setMetaValue("imsi", imsi);
- }
- }
-
public IBinder onBind(Intent intent) {
return asBinder();
}
@@ -1849,12 +1809,12 @@ public class AccountManagerService
}
private boolean inSystemImage(int callerUid) {
- String[] packages = mContext.getPackageManager().getPackagesForUid(callerUid);
+ String[] packages = mPackageManager.getPackagesForUid(callerUid);
for (String name : packages) {
try {
- PackageInfo packageInfo =
- mContext.getPackageManager().getPackageInfo(name, 0 /* flags */);
- if ((packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
+ if (packageInfo != null
+ && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
}
} catch (PackageManager.NameNotFoundException e) {
@@ -1872,7 +1832,7 @@ public class AccountManagerService
&& hasExplicitlyGrantedPermission(account, authTokenType);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
- + callerUid + ", account " + account
+ + callerUid + ", " + account
+ ": is authenticator? " + fromAuthenticator
+ ", has explicit permission? " + hasExplicitGrants);
}
@@ -1884,7 +1844,7 @@ public class AccountManagerService
mAuthenticatorCache.getAllServices()) {
if (serviceInfo.type.type.equals(accountType)) {
return (serviceInfo.uid == callingUid) ||
- (mContext.getPackageManager().checkSignatures(serviceInfo.uid, callingUid)
+ (mPackageManager.checkSignatures(serviceInfo.uid, callingUid)
== PackageManager.SIGNATURE_MATCH);
}
}
diff --git a/core/java/android/accounts/AuthenticatorDescription.java b/core/java/android/accounts/AuthenticatorDescription.java
index c651567..4d3769a 100644
--- a/core/java/android/accounts/AuthenticatorDescription.java
+++ b/core/java/android/accounts/AuthenticatorDescription.java
@@ -44,9 +44,16 @@ public class AuthenticatorDescription implements Parcelable {
/** The package name that can be used to lookup the resources from above. */
final public String packageName;
- /** A constructor for a full AuthenticatorDescription */
+ /** Authenticator handles its own token caching and permission screen
+ * @hide
+ */
+ final public boolean customTokens;
+
+ /** A constructor for a full AuthenticatorDescription
+ * @hide
+ */
public AuthenticatorDescription(String type, String packageName, int labelId, int iconId,
- int smallIconId, int prefId) {
+ int smallIconId, int prefId, boolean customTokens) {
if (type == null) throw new IllegalArgumentException("type cannot be null");
if (packageName == null) throw new IllegalArgumentException("packageName cannot be null");
this.type = type;
@@ -55,6 +62,12 @@ public class AuthenticatorDescription implements Parcelable {
this.iconId = iconId;
this.smallIconId = smallIconId;
this.accountPreferencesId = prefId;
+ this.customTokens = customTokens;
+ }
+
+ public AuthenticatorDescription(String type, String packageName, int labelId, int iconId,
+ int smallIconId, int prefId) {
+ this(type, packageName, labelId, iconId, smallIconId, prefId, false);
}
/**
@@ -74,6 +87,7 @@ public class AuthenticatorDescription implements Parcelable {
this.iconId = 0;
this.smallIconId = 0;
this.accountPreferencesId = 0;
+ this.customTokens = false;
}
private AuthenticatorDescription(Parcel source) {
@@ -83,6 +97,7 @@ public class AuthenticatorDescription implements Parcelable {
this.iconId = source.readInt();
this.smallIconId = source.readInt();
this.accountPreferencesId = source.readInt();
+ this.customTokens = source.readByte() == 1;
}
/** @inheritDoc */
@@ -115,6 +130,7 @@ public class AuthenticatorDescription implements Parcelable {
dest.writeInt(iconId);
dest.writeInt(smallIconId);
dest.writeInt(accountPreferencesId);
+ dest.writeByte((byte) (customTokens ? 1 : 0));
}
/** Used to create the object from a parcel. */
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index f535d61..0e473c9 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -61,6 +61,8 @@ import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
import android.graphics.drawable.Drawable;
import android.hardware.SensorManager;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbManager;
import android.location.ILocationManager;
import android.location.LocationManager;
import android.media.AudioManager;
@@ -188,6 +190,7 @@ class ContextImpl extends Context {
private SearchManager mSearchManager = null;
private SensorManager mSensorManager = null;
private StorageManager mStorageManager = null;
+ private UsbManager mUsbManager = null;
private Vibrator mVibrator = null;
private LayoutInflater mLayoutInflater = null;
private StatusBarManager mStatusBarManager = null;
@@ -951,6 +954,8 @@ class ContextImpl extends Context {
return getSensorManager();
} else if (STORAGE_SERVICE.equals(name)) {
return getStorageManager();
+ } else if (USB_SERVICE.equals(name)) {
+ return getUsbManager();
} else if (VIBRATOR_SERVICE.equals(name)) {
return getVibrator();
} else if (STATUS_BAR_SERVICE.equals(name)) {
@@ -1145,6 +1150,17 @@ class ContextImpl extends Context {
return mStorageManager;
}
+ private UsbManager getUsbManager() {
+ synchronized (mSync) {
+ if (mUsbManager == null) {
+ IBinder b = ServiceManager.getService(USB_SERVICE);
+ IUsbManager service = IUsbManager.Stub.asInterface(b);
+ mUsbManager = new UsbManager(this, service);
+ }
+ }
+ return mUsbManager;
+ }
+
private Vibrator getVibrator() {
synchronized (mSync) {
if (mVibrator == null) {
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index da8c9e5..d70ec0b 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -823,7 +823,7 @@ public class Dialog implements DialogInterface, Window.Callback,
// associate search with owner activity
final ComponentName appName = getAssociatedActivity();
- if (appName != null) {
+ if (appName != null && searchManager.getSearchableInfo(appName) != null) {
searchManager.startSearch(null, false, appName, null, false);
dismiss();
return true;
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 85c29b8..ec2d640 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -1567,6 +1567,17 @@ public abstract class Context {
public static final String SIP_SERVICE = "sip";
/**
+ * Use with {@link #getSystemService} to retrieve a {@link
+ * android.hardware.usb.UsbManager} for access to USB devices (as a USB host)
+ * and for controlling this device's behavior as a USB device.
+ *
+ * @see #getSystemService
+ * @see android.harware.usb.UsbManager
+ * @hide
+ */
+ public static final String USB_SERVICE = "usb";
+
+ /**
* Determine whether the given permission is allowed for a particular
* process and user ID running in the system.
*
diff --git a/core/java/android/content/SyncManager.java b/core/java/android/content/SyncManager.java
index 26b6ad7..5a83604 100644
--- a/core/java/android/content/SyncManager.java
+++ b/core/java/android/content/SyncManager.java
@@ -258,6 +258,7 @@ public class SyncManager implements OnAccountsUpdateListener {
// DISCONNECTED for GPRS in any order. if we receive the CONNECTED first, and then
// a DISCONNECTED, we want to make sure we set mDataConnectionIsConnected to true
// since we still have a WiFi connection.
+ final boolean wasConnected = mDataConnectionIsConnected;
switch (state) {
case CONNECTED:
mDataConnectionIsConnected = true;
@@ -273,6 +274,12 @@ public class SyncManager implements OnAccountsUpdateListener {
// ignore the rest of the states -- leave our boolean alone.
}
if (mDataConnectionIsConnected) {
+ if (!wasConnected) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "Reconnection detected: clearing all backoffs");
+ }
+ mSyncStorageEngine.clearAllBackoffs();
+ }
sendCheckAlarmsMessage();
}
}
diff --git a/core/java/android/content/SyncStorageEngine.java b/core/java/android/content/SyncStorageEngine.java
index e1a9dbb..faf1365 100644
--- a/core/java/android/content/SyncStorageEngine.java
+++ b/core/java/android/content/SyncStorageEngine.java
@@ -525,6 +525,32 @@ public class SyncStorageEngine extends Handler {
}
}
+ public void clearAllBackoffs() {
+ boolean changed = false;
+ synchronized (mAuthorities) {
+ for (AccountInfo accountInfo : mAccounts.values()) {
+ for (AuthorityInfo authorityInfo : accountInfo.authorities.values()) {
+ if (authorityInfo.backoffTime != NOT_IN_BACKOFF_MODE
+ || authorityInfo.backoffDelay != NOT_IN_BACKOFF_MODE) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Log.v(TAG, "clearAllBackoffs:"
+ + " authority:" + authorityInfo.authority
+ + " account:" + accountInfo.account.name
+ + " backoffTime was: " + authorityInfo.backoffTime
+ + " backoffDelay was: " + authorityInfo.backoffDelay);
+ }
+ authorityInfo.backoffTime = NOT_IN_BACKOFF_MODE;
+ authorityInfo.backoffDelay = NOT_IN_BACKOFF_MODE;
+ changed = true;
+ }
+ }
+ }
+ }
+
+ if (changed) {
+ reportChange(ContentResolver.SYNC_OBSERVER_TYPE_SETTINGS);
+ }
+ }
public void setDelayUntilTime(Account account, String providerName, long delayUntil) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "setDelayUntil: " + account + ", provider " + providerName
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 922f8cd..a779925 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -785,6 +785,13 @@ public abstract class PackageManager {
/**
* Feature for {@link #getSystemAvailableFeatures} and
+ * {@link #hasSystemFeature}: The device supports connecting to USB accessories.
+ * @hide
+ */
+ public static final String FEATURE_USB_ACCESSORY = "android.hardware.usb.accessory";
+
+ /**
+ * Feature for {@link #getSystemAvailableFeatures} and
* {@link #hasSystemFeature}: The SIP API is enabled on the device.
*/
@SdkConstant(SdkConstantType.FEATURE)
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 73d9458..4702327 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -234,6 +234,7 @@ public final class AssetManager {
StringBlock[] blocks = mStringBlocks;
if (blocks == null) {
ensureStringBlocks();
+ blocks = mStringBlocks;
}
outValue.string = blocks[block].get(outValue.data);
return true;
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index f079e42..b1a9349 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -1970,7 +1970,8 @@ public class SensorManager
if (rotationVector.length == 4) {
q0 = rotationVector[3];
} else {
- q0 = (float)Math.sqrt(1 - q1*q1 - q2*q2 - q3*q3);
+ q0 = 1 - q1*q1 - q2*q2 - q3*q3;
+ q0 = (q0 > 0) ? (float)Math.sqrt(q0) : 0;
}
float sq_q1 = 2 * q1 * q1;
@@ -2026,8 +2027,8 @@ public class SensorManager
if (rv.length == 4) {
Q[0] = rv[3];
} else {
- //In this case, the w component of the quaternion is known to be a positive number
- Q[0] = (float)Math.sqrt(1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2]);
+ Q[0] = 1 - rv[0]*rv[0] - rv[1]*rv[1] - rv[2]*rv[2];
+ Q[0] = (Q[0] > 0) ? (float)Math.sqrt(Q[0]) : 0;
}
Q[1] = rv[0];
Q[2] = rv[1];
diff --git a/core/java/android/hardware/Usb.java b/core/java/android/hardware/Usb.java
deleted file mode 100644
index 57271d4..0000000
--- a/core/java/android/hardware/Usb.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-package android.hardware;
-
-/**
- * Class for accessing USB state information.
- * @hide
- */
-public class Usb {
- /**
- * Broadcast Action: A broadcast for USB connected events.
- *
- * The extras bundle will name/value pairs with the name of the function
- * and a value of either {@link #USB_FUNCTION_ENABLED} or {@link #USB_FUNCTION_DISABLED}.
- * Possible USB function names include {@link #USB_FUNCTION_MASS_STORAGE},
- * {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS} and {@link #USB_FUNCTION_MTP}.
- */
- public static final String ACTION_USB_CONNECTED =
- "android.hardware.action.USB_CONNECTED";
-
- /**
- * Broadcast Action: A broadcast for USB disconnected events.
- */
- public static final String ACTION_USB_DISCONNECTED =
- "android.hardware.action.USB_DISCONNECTED";
-
- /**
- * Broadcast Action: A sticky broadcast for USB state change events.
- *
- * This is a sticky broadcast for clients that are interested in both USB connect and
- * disconnect events. If you are only concerned with one or the other, you can use
- * {@link #ACTION_USB_CONNECTED} or {@link #ACTION_USB_DISCONNECTED} to avoid receiving
- * unnecessary broadcasts. The boolean {@link #USB_CONNECTED} extra indicates whether
- * USB is connected or disconnected.
- * The extras bundle will also contain name/value pairs with the name of the function
- * and a value of either {@link #USB_FUNCTION_ENABLED} or {@link #USB_FUNCTION_DISABLED}.
- * Possible USB function names include {@link #USB_FUNCTION_MASS_STORAGE},
- * {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS} and {@link #USB_FUNCTION_MTP}.
- */
- public static final String ACTION_USB_STATE =
- "android.hardware.action.USB_STATE";
-
- /**
- * Boolean extra indicating whether USB is connected or disconnected.
- * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
- */
- public static final String USB_CONNECTED = "connected";
-
- /**
- * Name of the USB mass storage USB function.
- * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
- */
- public static final String USB_FUNCTION_MASS_STORAGE = "mass_storage";
-
- /**
- * Name of the adb USB function.
- * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
- */
- public static final String USB_FUNCTION_ADB = "adb";
-
- /**
- * Name of the RNDIS ethernet USB function.
- * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
- */
- public static final String USB_FUNCTION_RNDIS = "rndis";
-
- /**
- * Name of the MTP USB function.
- * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
- */
- public static final String USB_FUNCTION_MTP = "mtp";
-
- /**
- * Value indicating that a USB function is enabled.
- * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
- */
- public static final String USB_FUNCTION_ENABLED = "enabled";
-
- /**
- * Value indicating that a USB function is disabled.
- * Used in extras for the {@link #ACTION_USB_CONNECTED} broadcast
- */
- public static final String USB_FUNCTION_DISABLED = "disabled";
-}
diff --git a/core/java/android/hardware/usb/IUsbManager.aidl b/core/java/android/hardware/usb/IUsbManager.aidl
new file mode 100644
index 0000000..ffe557c
--- /dev/null
+++ b/core/java/android/hardware/usb/IUsbManager.aidl
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+import android.app.PendingIntent;
+import android.hardware.usb.UsbAccessory;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+
+/** @hide */
+interface IUsbManager
+{
+ /* Returns the currently attached USB accessory */
+ UsbAccessory getCurrentAccessory();
+
+ /* Returns a file descriptor for communicating with the USB accessory.
+ * This file descriptor can be used with standard Java file operations.
+ */
+ ParcelFileDescriptor openAccessory(in UsbAccessory accessory);
+
+ /* Sets the default package for a USB accessory
+ * (or clears it if the package name is null)
+ */
+ void setAccessoryPackage(in UsbAccessory accessory, String packageName);
+
+ /* Returns true if the caller has permission to access the accessory. */
+ boolean hasAccessoryPermission(in UsbAccessory accessory);
+
+ /* Requests permission for the given package to access the accessory.
+ * Will display a system dialog to query the user if permission
+ * had not already been given. Result is returned via pi.
+ */
+ void requestAccessoryPermission(in UsbAccessory accessory, String packageName,
+ in PendingIntent pi);
+
+ /* Grants permission for the given UID to access the accessory */
+ void grantAccessoryPermission(in UsbAccessory accessory, int uid);
+
+ /* Returns true if the USB manager has default preferences or permissions for the package */
+ boolean hasDefaults(String packageName);
+
+ /* Clears default preferences and permissions for the package */
+ void clearDefaults(String packageName);
+}
diff --git a/core/java/android/hardware/usb/UsbAccessory.aidl b/core/java/android/hardware/usb/UsbAccessory.aidl
new file mode 100644
index 0000000..1c15f1c
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbAccessory.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.usb;
+
+parcelable UsbAccessory;
diff --git a/core/java/android/hardware/usb/UsbAccessory.java b/core/java/android/hardware/usb/UsbAccessory.java
new file mode 100644
index 0000000..8938463
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbAccessory.java
@@ -0,0 +1,192 @@
+/*
+ * 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.hardware.usb;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class representing a USB accessory.
+ * @hide
+ */
+public class UsbAccessory implements Parcelable {
+
+ private static final String TAG = "UsbAccessory";
+
+ private final String mManufacturer;
+ private final String mModel;
+ private final String mDescription;
+ private final String mVersion;
+ private final String mUri;
+ private final String mSerial;
+
+ /**
+ * UsbAccessory should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbAccessory(String manufacturer, String model, String description,
+ String version, String uri, String serial) {
+ mManufacturer = manufacturer;
+ mModel = model;
+ mDescription = description;
+ mVersion = version;
+ mUri = uri;
+ mSerial = serial;
+ }
+
+ /**
+ * UsbAccessory should only be instantiated by UsbService implementation
+ * @hide
+ */
+ public UsbAccessory(String[] strings) {
+ mManufacturer = strings[0];
+ mModel = strings[1];
+ mDescription = strings[2];
+ mVersion = strings[3];
+ mUri = strings[4];
+ mSerial = strings[5];
+ }
+
+ /**
+ * Returns the manufacturer of the accessory.
+ *
+ * @return the accessory manufacturer
+ */
+ public String getManufacturer() {
+ return mManufacturer;
+ }
+
+ /**
+ * Returns the model name of the accessory.
+ *
+ * @return the accessory model
+ */
+ public String getModel() {
+ return mModel;
+ }
+
+ /**
+ * Returns a user visible description of the accessory.
+ *
+ * @return the accessory description
+ */
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /**
+ * Returns the version of the accessory.
+ *
+ * @return the accessory version
+ */
+ public String getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Returns the URI for the accessory.
+ * This is an optional URI that might show information about the accessory
+ * or provide the option to download an application for the accessory
+ *
+ * @return the accessory URI
+ */
+ public String getUri() {
+ return mUri;
+ }
+
+ /**
+ * Returns the unique serial number for the accessory.
+ * This is an optional serial number that can be used to differentiate
+ * between individual accessories of the same model and manufacturer
+ *
+ * @return the unique serial number
+ */
+ public String getSerial() {
+ return mSerial;
+ }
+
+ private static boolean compare(String s1, String s2) {
+ if (s1 == null) return (s2 == null);
+ return s1.equals(s2);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof UsbAccessory) {
+ UsbAccessory accessory = (UsbAccessory)obj;
+ return (compare(mManufacturer, accessory.getManufacturer()) &&
+ compare(mModel, accessory.getModel()) &&
+ compare(mDescription, accessory.getDescription()) &&
+ compare(mVersion, accessory.getVersion()) &&
+ compare(mUri, accessory.getUri()) &&
+ compare(mSerial, accessory.getSerial()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+ (mModel == null ? 0 : mModel.hashCode()) ^
+ (mDescription == null ? 0 : mDescription.hashCode()) ^
+ (mVersion == null ? 0 : mVersion.hashCode()) ^
+ (mUri == null ? 0 : mUri.hashCode()) ^
+ (mSerial == null ? 0 : mSerial.hashCode()));
+ }
+
+ @Override
+ public String toString() {
+ return "UsbAccessory[mManufacturer=" + mManufacturer +
+ ", mModel=" + mModel +
+ ", mDescription=" + mDescription +
+ ", mVersion=" + mVersion +
+ ", mUri=" + mUri +
+ ", mSerial=" + mSerial + "]";
+ }
+
+ public static final Parcelable.Creator<UsbAccessory> CREATOR =
+ new Parcelable.Creator<UsbAccessory>() {
+ public UsbAccessory createFromParcel(Parcel in) {
+ String manufacturer = in.readString();
+ String model = in.readString();
+ String description = in.readString();
+ String version = in.readString();
+ String uri = in.readString();
+ String serial = in.readString();
+ return new UsbAccessory(manufacturer, model, description, version, uri, serial);
+ }
+
+ public UsbAccessory[] newArray(int size) {
+ return new UsbAccessory[size];
+ }
+ };
+
+ public int describeContents() {
+ return 0;
+ }
+
+ public void writeToParcel(Parcel parcel, int flags) {
+ parcel.writeString(mManufacturer);
+ parcel.writeString(mModel);
+ parcel.writeString(mDescription);
+ parcel.writeString(mVersion);
+ parcel.writeString(mUri);
+ parcel.writeString(mSerial);
+ }
+}
diff --git a/core/java/android/hardware/usb/UsbManager.java b/core/java/android/hardware/usb/UsbManager.java
new file mode 100644
index 0000000..ea820f9
--- /dev/null
+++ b/core/java/android/hardware/usb/UsbManager.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+package android.hardware.usb;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.os.Bundle;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.HashMap;
+
+/**
+ * This class allows you to access the state of USB.
+ *
+ * <p>You can obtain an instance of this class by calling
+ * {@link android.content.Context#getSystemService(java.lang.String) Context.getSystemService()}.
+ *
+ * {@samplecode
+ * UsbManager manager = (UsbManager) getSystemService(Context.USB_SERVICE);
+ * }
+ * @hide
+ */
+public class UsbManager {
+ private static final String TAG = "UsbManager";
+
+ /**
+ * Broadcast Action: A sticky broadcast for USB state change events when in device mode.
+ *
+ * This is a sticky broadcast for clients that includes USB connected/disconnected state,
+ * <ul>
+ * <li> {@link #USB_CONNECTED} boolean indicating whether USB is connected or disconnected.
+ * <li> {@link #USB_CONFIGURATION} a Bundle containing name/value pairs where the name
+ * is the name of a USB function and the value is either {@link #USB_FUNCTION_ENABLED}
+ * or {@link #USB_FUNCTION_DISABLED}. The possible function names include
+ * {@link #USB_FUNCTION_MASS_STORAGE}, {@link #USB_FUNCTION_ADB}, {@link #USB_FUNCTION_RNDIS},
+ * {@link #USB_FUNCTION_MTP} and {@link #USB_FUNCTION_ACCESSORY}.
+ * </ul>
+ */
+ public static final String ACTION_USB_STATE =
+ "android.hardware.usb.action.USB_STATE";
+
+ /**
+ * Broadcast Action: A broadcast for USB accessory attached event.
+ *
+ * This intent is sent when a USB accessory is attached.
+ * <ul>
+ * <li> {@link #EXTRA_ACCESSORY} containing the {@link android.hardware.usb.UsbAccessory}
+ * for the attached accessory
+ * </ul>
+ */
+ public static final String ACTION_USB_ACCESSORY_ATTACHED =
+ "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
+
+ /**
+ * Broadcast Action: A broadcast for USB accessory detached event.
+ *
+ * This intent is sent when a USB accessory is detached.
+ * <ul>
+ * <li> {@link #EXTRA_ACCESSORY} containing the {@link UsbAccessory}
+ * for the attached accessory that was detached
+ * </ul>
+ */
+ public static final String ACTION_USB_ACCESSORY_DETACHED =
+ "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
+
+ /**
+ * Boolean extra indicating whether USB is connected or disconnected.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+ */
+ public static final String USB_CONNECTED = "connected";
+
+ /**
+ * Integer extra containing currently set USB configuration.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast.
+ */
+ public static final String USB_CONFIGURATION = "configuration";
+
+ /**
+ * Name of the USB mass storage USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ */
+ public static final String USB_FUNCTION_MASS_STORAGE = "mass_storage";
+
+ /**
+ * Name of the adb USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ */
+ public static final String USB_FUNCTION_ADB = "adb";
+
+ /**
+ * Name of the RNDIS ethernet USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ */
+ public static final String USB_FUNCTION_RNDIS = "rndis";
+
+ /**
+ * Name of the MTP USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ */
+ public static final String USB_FUNCTION_MTP = "mtp";
+
+ /**
+ * Name of the Accessory USB function.
+ * Used in extras for the {@link #ACTION_USB_STATE} broadcast
+ */
+ public static final String USB_FUNCTION_ACCESSORY = "accessory";
+
+ /**
+ * Value indicating that a USB function is enabled.
+ * Used in {@link #USB_CONFIGURATION} extras bundle for the
+ * {@link #ACTION_USB_STATE} broadcast
+ */
+ public static final String USB_FUNCTION_ENABLED = "enabled";
+
+ /**
+ * Value indicating that a USB function is disabled.
+ * Used in {@link #USB_CONFIGURATION} extras bundle for the
+ * {@link #ACTION_USB_STATE} broadcast
+ */
+ public static final String USB_FUNCTION_DISABLED = "disabled";
+
+ /**
+ * Name of extra for {@link #ACTION_USB_ACCESSORY_ATTACHED} and
+ * {@link #ACTION_USB_ACCESSORY_DETACHED} broadcasts
+ * containing the UsbAccessory object for the accessory.
+ */
+ public static final String EXTRA_ACCESSORY = "accessory";
+
+ /**
+ * Name of extra added to the {@link android.app.PendingIntent}
+ * passed into {@link #requestPermission(UsbDevice, PendingIntent)}
+ * or {@link #requestPermission(UsbAccessory, PendingIntent)}
+ * containing a boolean value indicating whether the user granted permission or not.
+ */
+ public static final String EXTRA_PERMISSION_GRANTED = "permission";
+
+ private final Context mContext;
+ private final IUsbManager mService;
+
+ /**
+ * {@hide}
+ */
+ public UsbManager(Context context, IUsbManager service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Returns a list of currently attached USB accessories.
+ * (in the current implementation there can be at most one)
+ *
+ * @return list of USB accessories, or null if none are attached.
+ */
+ public UsbAccessory[] getAccessoryList() {
+ try {
+ UsbAccessory accessory = mService.getCurrentAccessory();
+ if (accessory == null) {
+ return null;
+ } else {
+ return new UsbAccessory[] { accessory };
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getAccessoryList", e);
+ return null;
+ }
+ }
+
+ /**
+ * Opens a file descriptor for reading and writing data to the USB accessory.
+ *
+ * @param accessory the USB accessory to open
+ * @return file descriptor, or null if the accessor could not be opened.
+ */
+ public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
+ try {
+ return mService.openAccessory(accessory);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in openAccessory", e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns true if the caller has permission to access the accessory.
+ * Permission might have been granted temporarily via
+ * {@link #requestPermission(UsbAccessory, PendingIntent)} or
+ * by the user choosing the caller as the default application for the accessory.
+ *
+ * @param accessory to check permissions for
+ * @return true if caller has permission
+ */
+ public boolean hasPermission(UsbAccessory accessory) {
+ try {
+ return mService.hasAccessoryPermission(accessory);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in hasPermission", e);
+ return false;
+ }
+ }
+
+ /**
+ * Requests temporary permission for the given package to access the accessory.
+ * This may result in a system dialog being displayed to the user
+ * if permission had not already been granted.
+ * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+ * If successful, this grants the caller permission to access the accessory only
+ * until the device is disconnected.
+ *
+ * The following extras will be added to pi:
+ * <ul>
+ * <li> {@link #EXTRA_ACCESSORY} containing the accessory passed into this call
+ * <li> {@link #EXTRA_PERMISSION_GRANTED} containing boolean indicating whether
+ * permission was granted by the user
+ * </ul>
+ *
+ * @param accessory to request permissions for
+ * @param pi PendingIntent for returning result
+ */
+ public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
+ try {
+ mService.requestAccessoryPermission(accessory, mContext.getPackageName(), pi);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in requestPermission", e);
+ }
+ }
+
+ private static File getFunctionEnableFile(String function) {
+ return new File("/sys/class/usb_composite/" + function + "/enable");
+ }
+
+ /**
+ * Returns true if the specified USB function is supported by the kernel.
+ * Note that a USB function maybe supported but disabled.
+ *
+ * @param function name of the USB function
+ * @return true if the USB function is supported.
+ */
+ public static boolean isFunctionSupported(String function) {
+ return getFunctionEnableFile(function).exists();
+ }
+
+ /**
+ * Returns true if the specified USB function is currently enabled.
+ *
+ * @param function name of the USB function
+ * @return true if the USB function is enabled.
+ */
+ public static boolean isFunctionEnabled(String function) {
+ try {
+ FileInputStream stream = new FileInputStream(getFunctionEnableFile(function));
+ boolean enabled = (stream.read() == '1');
+ stream.close();
+ return enabled;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Enables or disables a USB function.
+ *
+ * @hide
+ */
+ public static boolean setFunctionEnabled(String function, boolean enable) {
+ try {
+ FileOutputStream stream = new FileOutputStream(getFunctionEnableFile(function));
+ stream.write(enable ? '1' : '0');
+ stream.close();
+ return true;
+ } catch (IOException e) {
+ return false;
+ }
+ }
+}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index a43914a..494e922 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -222,9 +222,9 @@ public class ConnectivityManager
/** {@hide} */
public static final int TYPE_ETHERNET = 9;
/** {@hide} TODO: Need to adjust this for WiMAX. */
- public static final int MAX_RADIO_TYPE = TYPE_WIFI;
+ public static final int MAX_RADIO_TYPE = TYPE_ETHERNET;
/** {@hide} TODO: Need to adjust this for WiMAX. */
- public static final int MAX_NETWORK_TYPE = TYPE_MOBILE_HIPRI;
+ public static final int MAX_NETWORK_TYPE = TYPE_ETHERNET;
public static final int DEFAULT_NETWORK_PREFERENCE = TYPE_WIFI;
diff --git a/core/java/android/net/InterfaceConfiguration.java b/core/java/android/net/InterfaceConfiguration.java
index 915c5d7..dcea3af 100644
--- a/core/java/android/net/InterfaceConfiguration.java
+++ b/core/java/android/net/InterfaceConfiguration.java
@@ -51,6 +51,24 @@ public class InterfaceConfiguration implements Parcelable {
append(addr & 0xff);
}
+ /**
+ * This function determines if the interface is up and has a valid IP
+ * configuration (IP address has a non zero octet).
+ *
+ * Note: It is supposed to be quick and hence should not initiate
+ * any network activity
+ */
+ public boolean isActive() {
+ try {
+ if(interfaceFlags.contains("up")) {
+ if (ipAddr != 0) return true;
+ }
+ } catch (NullPointerException e) {
+ return false;
+ }
+ return false;
+ }
+
/** Implement the Parcelable interface {@hide} */
public int describeContents() {
return 0;
diff --git a/core/java/android/net/MobileDataStateTracker.java b/core/java/android/net/MobileDataStateTracker.java
index 32c2d64..04b0f12 100644
--- a/core/java/android/net/MobileDataStateTracker.java
+++ b/core/java/android/net/MobileDataStateTracker.java
@@ -247,6 +247,9 @@ public class MobileDataStateTracker extends NetworkStateTracker {
Log.d(TAG, "CONNECTED event did not supply interface name.");
}
mDefaultGatewayAddr = intent.getIntExtra(Phone.DATA_GATEWAY_KEY, 0);
+ if (mDefaultGatewayAddr == 0) {
+ Log.d(TAG, "CONNECTED event did not supply a default gateway.");
+ }
setDetailedState(DetailedState.CONNECTED, reason, apnName);
break;
}
@@ -385,6 +388,7 @@ public class MobileDataStateTracker extends NetworkStateTracker {
intent.putExtra(Phone.DATA_APN_KEY, mApnName);
intent.putExtra(Phone.DATA_IFACE_NAME_KEY, mInterfaceName);
intent.putExtra(Phone.NETWORK_UNAVAILABLE_KEY, false);
+ intent.putExtra(Phone.DATA_GATEWAY_KEY, mDefaultGatewayAddr);
if (mStateReceiver != null) mStateReceiver.onReceive(mContext, intent);
break;
case Phone.APN_REQUEST_STARTED:
diff --git a/core/java/android/net/NetworkStateTracker.java b/core/java/android/net/NetworkStateTracker.java
index 9140dc9..233ad21 100644
--- a/core/java/android/net/NetworkStateTracker.java
+++ b/core/java/android/net/NetworkStateTracker.java
@@ -172,6 +172,7 @@ public abstract class NetworkStateTracker extends Handler {
if (inetAddress == null) {
if (DBG) Log.d(TAG, " Unable to add default route. mDefaultGatewayAddr Error");
} else {
+ NetworkUtils.addHostRoute(mInterfaceName, inetAddress, null);
if (!NetworkUtils.addDefaultRoute(mInterfaceName, inetAddress) && DBG) {
Log.d(TAG, " Unable to add default route.");
}
@@ -423,4 +424,7 @@ public abstract class NetworkStateTracker extends Handler {
public void interpretScanResultsAvailable() {
}
+ public String getInterfaceName() {
+ return mInterfaceName;
+ }
}
diff --git a/core/java/android/net/NetworkUtils.java b/core/java/android/net/NetworkUtils.java
index 5d4b099..8bdfdf9 100644
--- a/core/java/android/net/NetworkUtils.java
+++ b/core/java/android/net/NetworkUtils.java
@@ -209,4 +209,16 @@ public class NetworkUtils {
}
return result;
}
+
+ /**
+ * Start the DHCP renew service for wimax,
+ * This call blocks until it obtains a result (either success
+ * or failure) from the daemon.
+ * @param interfaceName the name of the interface to configure
+ * @param ipInfo if the request succeeds, this object is filled in with
+ * the IP address information.
+ * @return {@code true} for success, {@code false} for failure
+ * {@hide}
+ */
+ public native static boolean runDhcpRenew(String interfaceName, DhcpInfo ipInfo);
}
diff --git a/core/java/android/net/wimax/WimaxManagerConstants.java b/core/java/android/net/wimax/WimaxManagerConstants.java
new file mode 100644
index 0000000..5ec4e96
--- /dev/null
+++ b/core/java/android/net/wimax/WimaxManagerConstants.java
@@ -0,0 +1,103 @@
+package android.net.wimax;
+
+/**
+ * {@hide}
+ */
+public class WimaxManagerConstants
+{
+
+ /**
+ * Used by android.net.wimax.WimaxManager for handling management of
+ * Wimax access.
+ */
+ public static final String WIMAX_SERVICE = "WiMax";
+
+ /**
+ * Broadcast intent action indicating that Wimax has been enabled, disabled,
+ * enabling, disabling, or unknown. One extra provides this state as an int.
+ * Another extra provides the previous state, if available.
+ */
+ public static final String WIMAX_ENABLED_STATUS_CHANGED =
+ "android.net.wimax.WIMAX_STATUS_CHANGED";
+
+ /**
+ * The lookup key for an int that indicates whether Wimax is enabled,
+ * disabled, enabling, disabling, or unknown.
+ */
+ public static final String EXTRA_WIMAX_STATUS = "wimax_status";
+
+ /**
+ * Broadcast intent action indicating that Wimax state has been changed
+ * state could be scanning, connecting, connected, disconnecting, disconnected
+ * initializing, initialized, unknown and ready. One extra provides this state as an int.
+ * Another extra provides the previous state, if available.
+ */
+ public static final String WIMAX_STATE_CHANGED_ACTION =
+ "android.net.wimax.WIMAX_STATE_CHANGE";
+
+ /**
+ * Broadcast intent action indicating that Wimax signal level has been changed.
+ * Level varies from 0 to 3.
+ */
+ public static final String SIGNAL_LEVEL_CHANGED_ACTION =
+ "android.net.wimax.SIGNAL_LEVEL_CHANGED";
+
+ /**
+ * The lookup key for an int that indicates whether Wimax state is
+ * scanning, connecting, connected, disconnecting, disconnected
+ * initializing, initialized, unknown and ready.
+ */
+ public static final String EXTRA_WIMAX_STATE = "WimaxState";
+
+ /**
+ * The lookup key for an int that indicates whether state of Wimax
+ * is idle.
+ */
+ public static final String EXTRA_WIMAX_STATE_DETAIL = "WimaxStateDetail";
+
+ /**
+ * The lookup key for an int that indicates Wimax signal level.
+ */
+ public static final String EXTRA_NEW_SIGNAL_LEVEL = "newSignalLevel";
+
+ /**
+ * Indicatates Wimax is disabled.
+ */
+ public static final int WIMAX_STATUS_DISABLED = 1;
+
+ /**
+ * Indicatates Wimax is enabled.
+ */
+ public static final int WIMAX_STATUS_ENABLED = 3;
+
+ /**
+ * Indicatates Wimax status is known.
+ */
+ public static final int WIMAX_STATUS_UNKNOWN = 4;
+
+ /**
+ * Indicatates Wimax is in idle state.
+ */
+ public static final int WIMAX_IDLE = 6;
+
+ /**
+ * Indicatates Wimax is being deregistered.
+ */
+ public static final int WIMAX_DEREGISTRATION = 8;
+
+ /**
+ * Indicatates wimax state is unknown.
+ */
+ public static final int WIMAX_STATE_UNKNOWN = 0;
+
+ /**
+ * Indicatates wimax state is connected.
+ */
+ public static final int WIMAX_STATE_CONNECTED = 7;
+
+ /**
+ * Indicatates wimax state is disconnected.
+ */
+ public static final int WIMAX_STATE_DISCONNECTED = 9;
+
+}
diff --git a/core/java/android/nfc/ApduList.aidl b/core/java/android/nfc/ApduList.aidl
new file mode 100644
index 0000000..f6236b2
--- /dev/null
+++ b/core/java/android/nfc/ApduList.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+parcelable ApduList; \ No newline at end of file
diff --git a/core/java/android/nfc/ApduList.java b/core/java/android/nfc/ApduList.java
new file mode 100644
index 0000000..85b0547
--- /dev/null
+++ b/core/java/android/nfc/ApduList.java
@@ -0,0 +1,68 @@
+package android.nfc;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @hide
+ */
+public class ApduList implements Parcelable {
+
+ private ArrayList<byte[]> commands = new ArrayList<byte[]>();
+
+ public ApduList() {
+ }
+
+ public void add(byte[] command) {
+ commands.add(command);
+ }
+
+ public List<byte[]> get() {
+ return commands;
+ }
+
+ public static final Parcelable.Creator<ApduList> CREATOR =
+ new Parcelable.Creator<ApduList>() {
+ @Override
+ public ApduList createFromParcel(Parcel in) {
+ return new ApduList(in);
+ }
+
+ @Override
+ public ApduList[] newArray(int size) {
+ return new ApduList[size];
+ }
+ };
+
+ private ApduList(Parcel in) {
+ int count = in.readInt();
+
+ for (int i = 0 ; i < count ; i++) {
+
+ int length = in.readInt();
+ byte[] cmd = new byte[length];
+ in.readByteArray(cmd);
+ commands.add(cmd);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ dest.writeInt(commands.size());
+
+ for (byte[] cmd : commands) {
+ dest.writeInt(cmd.length);
+ dest.writeByteArray(cmd);
+ }
+ }
+}
+
+
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index d439a48..870127c 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -28,7 +28,7 @@ import android.nfc.ILlcpConnectionlessSocket;
import android.nfc.INfcTag;
import android.nfc.IP2pTarget;
import android.nfc.IP2pInitiator;
-import android.nfc.INfcSecureElement;
+import android.nfc.INfcAdapterExtras;
/**
* @hide
@@ -41,13 +41,12 @@ interface INfcAdapter
INfcTag getNfcTagInterface();
IP2pTarget getP2pTargetInterface();
IP2pInitiator getP2pInitiatorInterface();
- INfcSecureElement getNfcSecureElementInterface();
+ INfcAdapterExtras getNfcAdapterExtrasInterface();
// NfcAdapter-class related methods
boolean isEnabled();
NdefMessage localGet();
void localSet(in NdefMessage message);
- void openTagConnection(in Tag tag);
void enableForegroundDispatch(in ComponentName activity, in PendingIntent intent,
in IntentFilter[] filters, in TechListParcel techLists);
void disableForegroundDispatch(in ComponentName activity);
@@ -59,12 +58,8 @@ interface INfcAdapter
int createLlcpConnectionlessSocket(int sap);
int createLlcpServiceSocket(int sap, String sn, int miu, int rw, int linearBufferLength);
int createLlcpSocket(int sap, int miu, int rw, int linearBufferLength);
- int deselectSecureElement();
boolean disable();
boolean enable();
String getProperties(String param);
- int[] getSecureElementList();
- int getSelectedSecureElement();
- int selectSecureElement(int seId);
int setProperties(String param, String value);
-} \ No newline at end of file
+}
diff --git a/core/java/android/nfc/INfcAdapterExtras.aidl b/core/java/android/nfc/INfcAdapterExtras.aidl
new file mode 100755
index 0000000..8677a50
--- /dev/null
+++ b/core/java/android/nfc/INfcAdapterExtras.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.nfc;
+
+import android.nfc.ApduList;
+import android.os.Bundle;
+
+
+/**
+ * {@hide}
+ */
+interface INfcAdapterExtras {
+ Bundle open(IBinder b);
+ Bundle close();
+ Bundle transceive(in byte[] data_in);
+ int getCardEmulationRoute();
+ void setCardEmulationRoute(int route);
+ void registerTearDownApdus(String packageName, in ApduList apdu);
+ void unregisterTearDownApdus(String packageName);
+}
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 622bcdb..4689804 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -157,31 +157,6 @@ public final class NfcAdapter {
public static final String EXTRA_ID = "android.nfc.extra.ID";
/**
- * Broadcast Action: a transaction with a secure element has been detected.
- * <p>
- * Always contains the extra field
- * {@link android.nfc.NfcAdapter#EXTRA_AID}
- * @hide
- */
- @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
- public static final String ACTION_TRANSACTION_DETECTED =
- "android.nfc.action.TRANSACTION_DETECTED";
-
- /**
- * Broadcast Action: an RF field ON has been detected.
- * @hide
- */
- public static final String ACTION_RF_FIELD_ON_DETECTED =
- "android.nfc.action.RF_FIELD_ON_DETECTED";
-
- /**
- * Broadcast Action: an RF Field OFF has been detected.
- * @hide
- */
- public static final String ACTION_RF_FIELD_OFF_DETECTED =
- "android.nfc.action.RF_FIELD_OFF_DETECTED";
-
- /**
* Broadcast Action: an adapter's state changed between enabled and disabled.
*
* The new value is stored in the extra EXTRA_NEW_BOOLEAN_STATE and just contains
@@ -201,15 +176,6 @@ public final class NfcAdapter {
public static final String EXTRA_NEW_BOOLEAN_STATE = "android.nfc.isEnabled";
/**
- * Mandatory byte array extra field in
- * {@link android.nfc.NfcAdapter#ACTION_TRANSACTION_DETECTED}.
- * <p>
- * Contains the AID of the applet involved in the transaction.
- * @hide
- */
- public static final String EXTRA_AID = "android.nfc.extra.AID";
-
- /**
* LLCP link status: The LLCP link is activated.
* @hide
*/
@@ -691,14 +657,13 @@ public final class NfcAdapter {
}
/**
- * Create an Nfc Secure Element Connection
* @hide
*/
- public NfcSecureElement createNfcSecureElementConnection() {
+ public INfcAdapterExtras getNfcAdapterExtrasInterface() {
try {
- return new NfcSecureElement(sService.getNfcSecureElementInterface());
+ return sService.getNfcAdapterExtrasInterface();
} catch (RemoteException e) {
- Log.e(TAG, "createNfcSecureElementConnection failed", e);
+ attemptDeadServiceRecovery(e);
return null;
}
}
diff --git a/core/java/android/nfc/NfcSecureElement.java b/core/java/android/nfc/NfcSecureElement.java
deleted file mode 100755
index 3b5f39e..0000000
--- a/core/java/android/nfc/NfcSecureElement.java
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.nfc;
-
-import android.nfc.tech.TagTechnology;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.io.IOException;
-
-//import android.util.Log;
-
-/**
- * This class provides the primary API for managing all aspects Secure Element.
- * Get an instance of this class by calling
- * Context.getSystemService(Context.NFC_SERVICE).
- * @hide
- */
-public final class NfcSecureElement {
-
- private static final String TAG = "NfcSecureElement";
-
- private INfcSecureElement mService;
-
-
- /**
- * @hide
- */
- public NfcSecureElement(INfcSecureElement mSecureElementService) {
- mService = mSecureElementService;
- }
-
- public int openSecureElementConnection(String seType) throws IOException {
- if (seType.equals("SmartMX")) {
- try {
- int handle = mService.openSecureElementConnection();
- // Handle potential errors
- if (handle != 0) {
- return handle;
- } else {
- throw new IOException("SmartMX connection not allowed");
- }
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in openSecureElementConnection(): ", e);
- return 0;
- }
-
- } else if (seType.equals("UICC")) {
- return 0;
- } else {
- throw new IOException("Wrong Secure Element type");
- }
- }
-
-
- public byte [] exchangeAPDU(int handle,byte [] data) throws IOException {
-
-
- // Perform exchange APDU
- try {
- byte[] response = mService.exchangeAPDU(handle, data);
- // Handle potential errors
- if (response == null) {
- throw new IOException("Exchange APDU failed");
- }
- return response;
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in exchangeAPDU(): ", e);
- return null;
- }
- }
-
- public void closeSecureElementConnection(int handle) throws IOException {
-
- try {
- int status = mService.closeSecureElementConnection(handle);
- // Handle potential errors
- if (ErrorCodes.isError(status)) {
- throw new IOException("Error during the conection close");
- };
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in closeSecureElement(): ", e);
- }
- }
-
-
- /**
- * Returns target type. constants.
- *
- * @return Secure Element technology type. The possible values are defined in
- * {@link TagTechnology}
- *
- */
- public int[] getSecureElementTechList(int handle) throws IOException {
- try {
- return mService.getSecureElementTechList(handle);
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getType(): ", e);
- return null;
- }
- }
-
- /**
- * Returns Secure Element UID.
- *
- * @return Secure Element UID.
- */
- public byte[] getSecureElementUid(int handle) throws IOException {
-
- byte[] uid = null;
- try {
- uid = mService.getSecureElementUid(handle);
- // Handle potential errors
- if (uid == null) {
- throw new IOException("Get Secure Element UID failed");
- }
- return uid;
- } catch (RemoteException e) {
- Log.e(TAG, "RemoteException in getType(): ", e);
- return null;
- }
- }
-
-}
diff --git a/core/java/android/nfc/tech/Ndef.java b/core/java/android/nfc/tech/Ndef.java
index 6727d6a..e4daa57 100644
--- a/core/java/android/nfc/tech/Ndef.java
+++ b/core/java/android/nfc/tech/Ndef.java
@@ -103,6 +103,8 @@ public final class Ndef extends BasicTagTechnology {
public static final int TYPE_4 = 4;
/** @hide */
public static final int TYPE_MIFARE_CLASSIC = 101;
+ /** @hide */
+ public static final int TYPE_ICODE_SLI = 102;
/** @hide */
public static final String UNKNOWN = "android.ndef.unknown";
@@ -117,6 +119,11 @@ public final class Ndef extends BasicTagTechnology {
public static final String NFC_FORUM_TYPE_4 = "org.nfcforum.ndef.type4";
/** NDEF on MIFARE Classic */
public static final String MIFARE_CLASSIC = "com.nxp.ndef.mifareclassic";
+ /**
+ * NDEF on iCODE SLI
+ * @hide
+ */
+ public static final String ICODE_SLI = "com.nxp.ndef.icodesli";
private final int mMaxNdefSize;
private final int mCardState;
@@ -200,6 +207,8 @@ public final class Ndef extends BasicTagTechnology {
return NFC_FORUM_TYPE_4;
case TYPE_MIFARE_CLASSIC:
return MIFARE_CLASSIC;
+ case TYPE_ICODE_SLI:
+ return ICODE_SLI;
default:
return UNKNOWN;
}
diff --git a/core/java/android/nfc/tech/package.html b/core/java/android/nfc/tech/package.html
new file mode 100644
index 0000000..a99828f
--- /dev/null
+++ b/core/java/android/nfc/tech/package.html
@@ -0,0 +1,13 @@
+<HTML>
+<BODY>
+<p>
+These classes provide access to a tag technology's features, which vary by the type
+of tag that is scanned. A scanned tag can support multiple technologies, and you can find
+out what they are by calling {@link android.nfc.Tag#getTechList getTechList()}.</p>
+
+<p>For more information on dealing with tag technologies and handling the ones that you care about, see
+<a href="{@docRoot}guide/topics/nfc/index.html#dispatch">The Tag Dispatch System</a>.
+The {@link android.nfc.tech.TagTechnology} interface provides an overview of the
+supported technologies.</p>
+</BODY>
+</HTML>
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index e4485d1..5de76ff 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -132,6 +132,7 @@ public abstract class BatteryStats implements Parcelable {
private static final String NETWORK_DATA = "nt";
private static final String USER_ACTIVITY_DATA = "ua";
private static final String BATTERY_DATA = "bt";
+ private static final String BATTERY_DISCHARGE_DATA = "dc";
private static final String BATTERY_LEVEL_DATA = "lv";
private static final String WIFI_LOCK_DATA = "wfl";
private static final String MISC_DATA = "m";
@@ -801,6 +802,30 @@ public abstract class BatteryStats implements Parcelable {
public abstract int getHighDischargeAmountSinceCharge();
/**
+ * Get the amount the battery has discharged while the screen was on,
+ * since the last time power was unplugged.
+ */
+ public abstract int getDischargeAmountScreenOn();
+
+ /**
+ * Get the amount the battery has discharged while the screen was on,
+ * since the last time the device was charged.
+ */
+ public abstract int getDischargeAmountScreenOnSinceCharge();
+
+ /**
+ * Get the amount the battery has discharged while the screen was off,
+ * since the last time power was unplugged.
+ */
+ public abstract int getDischargeAmountScreenOff();
+
+ /**
+ * Get the amount the battery has discharged while the screen was off,
+ * since the last time the device was charged.
+ */
+ public abstract int getDischargeAmountScreenOffSinceCharge();
+
+ /**
* Returns the total, last, or current battery uptime in microseconds.
*
* @param curTime the elapsed realtime in microseconds.
@@ -1095,6 +1120,17 @@ public abstract class BatteryStats implements Parcelable {
getDischargeCurrentLevel());
}
+ if (which == STATS_SINCE_UNPLUGGED) {
+ dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
+ getDischargeStartLevel()-getDischargeCurrentLevel(),
+ getDischargeStartLevel()-getDischargeCurrentLevel(),
+ getDischargeAmountScreenOn(), getDischargeAmountScreenOff());
+ } else {
+ dumpLine(pw, 0 /* uid */, category, BATTERY_DISCHARGE_DATA,
+ getLowDischargeAmountSinceCharge(), getHighDischargeAmountSinceCharge(),
+ getDischargeAmountScreenOn(), getDischargeAmountScreenOff());
+ }
+
if (reqUid < 0) {
Map<String, ? extends BatteryStats.Timer> kernelWakelocks = getKernelWakelockStats();
if (kernelWakelocks.size() > 0) {
@@ -1451,6 +1487,10 @@ public abstract class BatteryStats implements Parcelable {
pw.print(prefix); pw.print(" Last discharge cycle end level: ");
pw.println(getDischargeCurrentLevel());
}
+ pw.print(prefix); pw.print(" Amount discharged while screen on: ");
+ pw.println(getDischargeAmountScreenOn());
+ pw.print(prefix); pw.print(" Amount discharged while screen off: ");
+ pw.println(getDischargeAmountScreenOff());
pw.println(" ");
} else {
pw.print(prefix); pw.println(" Device battery use since last full charge");
@@ -1458,6 +1498,10 @@ public abstract class BatteryStats implements Parcelable {
pw.println(getLowDischargeAmountSinceCharge());
pw.print(prefix); pw.print(" Amount discharged (upper bound): ");
pw.println(getHighDischargeAmountSinceCharge());
+ pw.print(prefix); pw.print(" Amount discharged while screen on: ");
+ pw.println(getDischargeAmountScreenOnSinceCharge());
+ pw.print(prefix); pw.print(" Amount discharged while screen off: ");
+ pw.println(getDischargeAmountScreenOffSinceCharge());
pw.println(" ");
}
diff --git a/core/java/android/os/Looper.java b/core/java/android/os/Looper.java
index d360140..2a66616 100644
--- a/core/java/android/os/Looper.java
+++ b/core/java/android/os/Looper.java
@@ -17,6 +17,7 @@
package android.os;
import android.util.Config;
+import android.util.Log;
import android.util.Printer;
/**
@@ -106,6 +107,12 @@ public class Looper {
public static final void loop() {
Looper me = myLooper();
MessageQueue queue = me.mQueue;
+
+ // Make sure the identity of this thread is that of the local process,
+ // and keep track of what that identity token actually is.
+ Binder.clearCallingIdentity();
+ final long ident = Binder.clearCallingIdentity();
+
while (true) {
Message msg = queue.next(); // might block
//if (!me.mRun) {
@@ -124,6 +131,18 @@ public class Looper {
if (me.mLogging!= null) me.mLogging.println(
"<<<<< Finished to " + msg.target + " "
+ msg.callback);
+
+ // Make sure that during the course of dispatching the
+ // identity of the thread wasn't corrupted.
+ final long newIdent = Binder.clearCallingIdentity();
+ if (ident != newIdent) {
+ Log.wtf("Looper", "Thread identity changed from 0x"
+ + Long.toHexString(ident) + " to 0x"
+ + Long.toHexString(newIdent) + " while dispatching to "
+ + msg.target.getClass().getName() + " "
+ + msg.callback + " what=" + msg.what);
+ }
+
msg.recycle();
}
}
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index a718fc6..e1fdfb6 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -89,7 +89,7 @@ public class Process {
* Defines the UID/GID for the NFC service process.
* @hide
*/
- public static final int NFC_UID = 1022;
+ public static final int NFC_UID = 1025;
/**
* Defines the start of a range of UIDs (and GIDs), going from this
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index 6d19f41..74b4fcb 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -16,6 +16,11 @@
package android.os;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileNotFoundException;
@@ -37,9 +42,6 @@ import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
-import android.content.Context;
-import android.util.Log;
-
import org.apache.harmony.security.asn1.BerInputStream;
import org.apache.harmony.security.pkcs7.ContentInfo;
import org.apache.harmony.security.pkcs7.SignedData;
@@ -336,8 +338,21 @@ public class RecoverySystem {
* @throws IOException if writing the recovery command file
* fails, or if the reboot itself fails.
*/
- public static void rebootWipeUserData(Context context)
- throws IOException {
+ public static void rebootWipeUserData(Context context) throws IOException {
+ final ConditionVariable condition = new ConditionVariable();
+
+ Intent intent = new Intent("android.intent.action.MASTER_CLEAR_NOTIFICATION");
+ context.sendOrderedBroadcast(intent, android.Manifest.permission.MASTER_CLEAR,
+ new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ condition.open();
+ }
+ }, null, 0, null, null);
+
+ // Block until the ordered broadcast has completed.
+ condition.block();
+
bootCommand(context, "--wipe_data");
}
diff --git a/core/java/android/pim/ICalendar.java b/core/java/android/pim/ICalendar.java
index cc0f45e..9c4eaf4 100644
--- a/core/java/android/pim/ICalendar.java
+++ b/core/java/android/pim/ICalendar.java
@@ -578,6 +578,23 @@ public class ICalendar {
+ text);
}
parameter.name = text.substring(startIndex + 1, equalIndex);
+ } else if (c == '"') {
+ if (parameter == null) {
+ throw new FormatException("Expected parameter before '\"' in " + text);
+ }
+ if (equalIndex == -1) {
+ throw new FormatException("Expected '=' within parameter in " + text);
+ }
+ if (state.index > equalIndex + 1) {
+ throw new FormatException("Parameter value cannot contain a '\"' in " + text);
+ }
+ final int endQuote = text.indexOf('"', state.index + 1);
+ if (endQuote < 0) {
+ throw new FormatException("Expected closing '\"' in " + text);
+ }
+ parameter.value = text.substring(state.index + 1, endQuote);
+ state.index = endQuote + 1;
+ return parameter;
}
++state.index;
}
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 2a13d520..38c5dc4 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -1101,6 +1101,12 @@ public final class Settings {
public static final String RADIO_CELL = "cell";
/**
+ * Constant for use in AIRPLANE_MODE_RADIOS to specify WiMAX radio.
+ * @hide
+ */
+ public static final String RADIO_WIMAX = "wimax";
+
+ /**
* A comma separated list of radios that need to be disabled when airplane mode
* is on. This overrides WIFI_ON and BLUETOOTH_ON, if Wi-Fi and bluetooth are
* included in the comma separated list.
@@ -2559,6 +2565,14 @@ public final class Settings {
"wifi_networks_available_repeat_delay";
/**
+ * Whether to nofity the user of WiMAX network.
+ * If WiMAX is connected or disconnected, we will put this notification up.
+ * @hide
+ */
+ public static final String WIMAX_NETWORKS_AVAILABLE_NOTIFICATION_ON =
+ "wimax_networks_available_notification_on";
+
+ /**
* The number of radio channels that are allowed in the local
* 802.11 regulatory domain.
* @hide
@@ -2695,6 +2709,12 @@ public final class Settings {
"wifi_mobile_data_transition_wakelock_timeout_ms";
/**
+ * Whether the Wimax should be on. Only the WiMAX service should touch this.
+ * @hide
+ */
+ public static final String WIMAX_ON = "wimax_on";
+
+ /**
* Whether background data usage is allowed by the user. See
* ConnectivityManager for more info.
*/
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index 1a35112..62f66b6 100755
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -1723,6 +1723,21 @@ public final class Telephony {
public static final String TYPE = "type";
+ /**
+ * The protocol to be used to connect to this APN.
+ *
+ * One of the PDP_type values in TS 27.007 section 10.1.1.
+ * For example, "IP", "IPV6", "IPV4V6", or "PPP".
+ */
+ public static final String PROTOCOL = "protocol";
+
+ /**
+ * The protocol to be used to connect to this APN when roaming.
+ *
+ * The syntax is the same as protocol.
+ */
+ public static final String ROAMING_PROTOCOL = "roaming_protocol";
+
public static final String CURRENT = "current";
}
diff --git a/core/java/android/speech/RecognitionService.java b/core/java/android/speech/RecognitionService.java
index 75a5ed5..32b2d8f 100644
--- a/core/java/android/speech/RecognitionService.java
+++ b/core/java/android/speech/RecognitionService.java
@@ -68,6 +68,8 @@ public abstract class RecognitionService extends Service {
private static final int MSG_CANCEL = 3;
+ private static final int MSG_RESET = 4;
+
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
@@ -81,6 +83,10 @@ public abstract class RecognitionService extends Service {
break;
case MSG_CANCEL:
dispatchCancel((IRecognitionListener) msg.obj);
+ break;
+ case MSG_RESET:
+ dispatchClearCallback();
+ break;
}
}
};
@@ -128,6 +134,10 @@ public abstract class RecognitionService extends Service {
}
}
+ private void dispatchClearCallback() {
+ mCurrentCallback = null;
+ }
+
private class StartListeningArgs {
public final Intent mIntent;
@@ -241,7 +251,7 @@ public abstract class RecognitionService extends Service {
* @param error code is defined in {@link SpeechRecognizer}
*/
public void error(int error) throws RemoteException {
- mCurrentCallback = null;
+ Message.obtain(mHandler, MSG_RESET).sendToTarget();
mListener.onError(error);
}
@@ -278,7 +288,7 @@ public abstract class RecognitionService extends Service {
* {@link SpeechRecognizer#RESULTS_RECOGNITION} as a parameter
*/
public void results(Bundle results) throws RemoteException {
- mCurrentCallback = null;
+ Message.obtain(mHandler, MSG_RESET).sendToTarget();
mListener.onResults(results);
}
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 4e197cd..b62aa40 100755
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1154,7 +1154,7 @@ public abstract class Layout {
if (h2 < 0.5f)
h2 = 0.5f;
- if (h1 == h2) {
+ if (Float.compare(h1, h2) == 0) {
dest.moveTo(h1, top);
dest.lineTo(h1, bottom);
} else {
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 8675d05..0d7aa02 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -627,10 +627,16 @@ public class TextUtils {
public CharSequence createFromParcel(Parcel p) {
int kind = p.readInt();
- if (kind == 1)
- return p.readString();
+ String string = p.readString();
+ if (string == null) {
+ return null;
+ }
+
+ if (kind == 1) {
+ return string;
+ }
- SpannableString sp = new SpannableString(p.readString());
+ SpannableString sp = new SpannableString(string);
while (true) {
kind = p.readInt();
diff --git a/core/java/android/text/method/MultiTapKeyListener.java b/core/java/android/text/method/MultiTapKeyListener.java
index 6d94788..2a739fa 100644
--- a/core/java/android/text/method/MultiTapKeyListener.java
+++ b/core/java/android/text/method/MultiTapKeyListener.java
@@ -116,7 +116,7 @@ public class MultiTapKeyListener extends BaseKeyListener
content.replace(selStart, selEnd,
String.valueOf(current).toUpperCase());
removeTimeouts(content);
- Timeout t = new Timeout(content);
+ new Timeout(content); // for its side effects
return true;
}
@@ -124,7 +124,7 @@ public class MultiTapKeyListener extends BaseKeyListener
content.replace(selStart, selEnd,
String.valueOf(current).toLowerCase());
removeTimeouts(content);
- Timeout t = new Timeout(content);
+ new Timeout(content); // for its side effects
return true;
}
@@ -140,7 +140,7 @@ public class MultiTapKeyListener extends BaseKeyListener
content.replace(selStart, selEnd, val, ix, ix + 1);
removeTimeouts(content);
- Timeout t = new Timeout(content);
+ new Timeout(content); // for its side effects
return true;
}
@@ -206,7 +206,7 @@ public class MultiTapKeyListener extends BaseKeyListener
}
removeTimeouts(content);
- Timeout t = new Timeout(content);
+ new Timeout(content); // for its side effects
// Set up the callback so we can remove the timeout if the
// cursor moves.
diff --git a/core/java/android/text/style/DrawableMarginSpan.java b/core/java/android/text/style/DrawableMarginSpan.java
index 3c471a5..c2564d5 100644
--- a/core/java/android/text/style/DrawableMarginSpan.java
+++ b/core/java/android/text/style/DrawableMarginSpan.java
@@ -50,9 +50,6 @@ implements LeadingMarginSpan, LineHeightSpan
int dw = mDrawable.getIntrinsicWidth();
int dh = mDrawable.getIntrinsicHeight();
- if (dir < 0)
- x -= dw;
-
// XXX What to do about Paint?
mDrawable.setBounds(ix, itop, ix+dw, itop+dh);
mDrawable.draw(c);
diff --git a/core/java/android/util/SparseArray.java b/core/java/android/util/SparseArray.java
index 1c8b330..4c13460 100644
--- a/core/java/android/util/SparseArray.java
+++ b/core/java/android/util/SparseArray.java
@@ -90,6 +90,17 @@ public class SparseArray<E> {
delete(key);
}
+ /**
+ * Removes the mapping at the specified index.
+ * @hide
+ */
+ public void removeAt(int index) {
+ if (mValues[index] != DELETED) {
+ mValues[index] = DELETED;
+ mGarbage = true;
+ }
+ }
+
private void gc() {
// Log.e("SparseArray", "gc start with " + mSize);
diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java
index ccaef40..afec1c3 100644
--- a/core/java/android/view/ViewRoot.java
+++ b/core/java/android/view/ViewRoot.java
@@ -176,6 +176,7 @@ public final class ViewRoot extends Handler implements ViewParent,
private final Surface mSurface = new Surface();
boolean mAdded;
+ private boolean mAttached;
boolean mAddedTouchMode;
/*package*/ int mAddNesting;
@@ -762,7 +763,10 @@ public final class ViewRoot extends Handler implements ViewParent,
attachInfo.mKeepScreenOn = false;
viewVisibilityChanged = false;
mLastConfiguration.setTo(host.getResources().getConfiguration());
- host.dispatchAttachedToWindow(attachInfo, 0);
+ if (!mAttached) {
+ host.dispatchAttachedToWindow(attachInfo, 0);
+ mAttached = true;
+ }
//Log.i(TAG, "Screen on initialized: " + attachInfo.mKeepScreenOn);
} else {
@@ -1743,8 +1747,9 @@ public final class ViewRoot extends Handler implements ViewParent,
void dispatchDetachedFromWindow() {
if (Config.LOGV) Log.v(TAG, "Detaching in " + this + " of " + mSurface);
- if (mView != null) {
+ if (mView != null && mAttached) {
mView.dispatchDetachedFromWindow();
+ mAttached = false;
}
mView = null;
diff --git a/core/java/android/webkit/FrameLoader.java b/core/java/android/webkit/FrameLoader.java
index 021b53c..4bc12d4 100644
--- a/core/java/android/webkit/FrameLoader.java
+++ b/core/java/android/webkit/FrameLoader.java
@@ -186,7 +186,8 @@ class FrameLoader {
settings.getAllowFileAccess())).sendToTarget();
}
return true;
- } else if (URLUtil.isContentUrl(url)) {
+ } else if (settings.getAllowContentAccess() &&
+ URLUtil.isContentUrl(url)) {
// Send the raw url to the ContentLoader because it will do a
// permission check and the url has to match.
if (loadListener.isSynchronous()) {
diff --git a/core/java/android/webkit/WebSettings.java b/core/java/android/webkit/WebSettings.java
index 4d70e7c..89e25e8 100644
--- a/core/java/android/webkit/WebSettings.java
+++ b/core/java/android/webkit/WebSettings.java
@@ -206,6 +206,7 @@ public class WebSettings {
private boolean mSupportZoom = true;
private boolean mBuiltInZoomControls = false;
private boolean mAllowFileAccess = true;
+ private boolean mAllowContentAccess = true;
private boolean mLoadWithOverviewMode = false;
private boolean mUseWebViewBackgroundOverscrollBackground = true;
@@ -458,7 +459,9 @@ public class WebSettings {
/**
* Enable or disable file access within WebView. File access is enabled by
- * default.
+ * default. Note that this enables or disables file system access only.
+ * Assets and resources are still accessible using file:///android_asset and
+ * file:///android_res.
*/
public void setAllowFileAccess(boolean allow) {
mAllowFileAccess = allow;
@@ -472,6 +475,24 @@ public class WebSettings {
}
/**
+ * Enable or disable content url access within WebView. Content url access
+ * allows WebView to load content from a content provider installed in the
+ * system. The default is enabled.
+ * @hide
+ */
+ public void setAllowContentAccess(boolean allow) {
+ mAllowContentAccess = allow;
+ }
+
+ /**
+ * Returns true if this WebView supports content url access.
+ * @hide
+ */
+ public boolean getAllowContentAccess() {
+ return mAllowContentAccess;
+ }
+
+ /**
* Set whether the WebView loads a page with overview mode.
*/
public void setLoadWithOverviewMode(boolean overview) {
diff --git a/core/java/android/widget/DatePicker.java b/core/java/android/widget/DatePicker.java
index a371290..595b487 100644
--- a/core/java/android/widget/DatePicker.java
+++ b/core/java/android/widget/DatePicker.java
@@ -22,6 +22,7 @@ import android.content.res.TypedArray;
import android.os.Parcel;
import android.os.Parcelable;
import android.text.format.DateFormat;
+import android.text.format.DateUtils;
import android.util.AttributeSet;
import android.util.SparseArray;
import android.view.LayoutInflater;
@@ -33,6 +34,7 @@ import com.android.internal.R;
import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Calendar;
+import java.util.Locale;
/**
* A view for selecting a month / year / day based on a calendar like layout.
@@ -47,7 +49,10 @@ public class DatePicker extends FrameLayout {
private static final int DEFAULT_START_YEAR = 1900;
private static final int DEFAULT_END_YEAR = 2100;
-
+
+ // This ignores Undecimber, but we only support real Gregorian calendars.
+ private static final int NUMBER_OF_MONTHS = 12;
+
/* UI Components */
private final NumberPicker mDayPicker;
private final NumberPicker mMonthPicker;
@@ -62,6 +67,10 @@ public class DatePicker extends FrameLayout {
private int mMonth;
private int mYear;
+ private Object mMonthUpdateLock = new Object();
+ private volatile Locale mMonthLocale;
+ private String[] mShortMonths;
+
/**
* The callback used to indicate the user changes the date.
*/
@@ -102,8 +111,7 @@ public class DatePicker extends FrameLayout {
});
mMonthPicker = (NumberPicker) findViewById(R.id.month);
mMonthPicker.setFormatter(NumberPicker.TWO_DIGIT_FORMATTER);
- DateFormatSymbols dfs = new DateFormatSymbols();
- String[] months = dfs.getShortMonths();
+ final String[] months = getShortMonths();
/*
* If the user is in a locale where the month names are numeric,
@@ -114,9 +122,9 @@ public class DatePicker extends FrameLayout {
for (int i = 0; i < months.length; i++) {
months[i] = String.valueOf(i + 1);
}
- mMonthPicker.setRange(1, 12);
+ mMonthPicker.setRange(1, NUMBER_OF_MONTHS);
} else {
- mMonthPicker.setRange(1, 12, months);
+ mMonthPicker.setRange(1, NUMBER_OF_MONTHS, months);
}
mMonthPicker.setSpeed(200);
@@ -246,11 +254,30 @@ public class DatePicker extends FrameLayout {
mMonth = monthOfYear;
mDay = dayOfMonth;
updateSpinners();
- reorderPickers(new DateFormatSymbols().getShortMonths());
+ reorderPickers(getShortMonths());
notifyDateChanged();
}
}
+ private String[] getShortMonths() {
+ final Locale currentLocale = Locale.getDefault();
+ if (currentLocale.equals(mMonthLocale) && mShortMonths != null) {
+ return mShortMonths;
+ } else {
+ synchronized (mMonthUpdateLock) {
+ if (!currentLocale.equals(mMonthLocale)) {
+ mShortMonths = new String[NUMBER_OF_MONTHS];
+ for (int i = 0; i < NUMBER_OF_MONTHS; i++) {
+ mShortMonths[i] = DateUtils.getMonthString(Calendar.JANUARY + i,
+ DateUtils.LENGTH_MEDIUM);
+ }
+ mMonthLocale = currentLocale;
+ }
+ }
+ return mShortMonths;
+ }
+ }
+
private static class SavedState extends BaseSavedState {
private final int mYear;
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 76755de..66524ab 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1421,6 +1421,10 @@ public class PopupWindow {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
+ if (getKeyDispatcherState() == null) {
+ return super.dispatchKeyEvent(event);
+ }
+
if (event.getAction() == KeyEvent.ACTION_DOWN
&& event.getRepeatCount() == 0) {
getKeyDispatcherState().startTracking(event, this);
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 97b05af..68600cf 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -301,6 +301,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Set when this TextView gained focus with some text selected. Will start selection mode.
private boolean mCreatedWithASelection = false;
+ private boolean mNoContextMenuOnUp = false;
+
/*
* Kick-start the font cache for the zygote process (to pay the cost of
* initializing freetype for our default font only once).
@@ -6798,8 +6800,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
// Restore previous selection
Selection.setSelection((Spannable)mText, prevStart, prevEnd);
- // Tapping inside the selection displays the cut/copy/paste context menu
- showContextMenu();
+ // Tapping inside the selection displays the cut/copy/paste context menu, unless
+ // this is a double tap that should simply trigger text selection mode.
+ if (!mNoContextMenuOnUp) showContextMenu();
} else {
// Tapping outside stops selection mode, if any
stopTextSelectionMode();
@@ -6857,7 +6860,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
mScrolled = false;
}
- final boolean superResult = super.onTouchEvent(event);
+ boolean result = super.onTouchEvent(event);
/*
* Don't handle the release after a long press, because it will
@@ -6866,11 +6869,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
*/
if (mEatTouchRelease && action == MotionEvent.ACTION_UP) {
mEatTouchRelease = false;
- return superResult;
- }
-
- if ((mMovement != null || onCheckIsTextEditor()) && isEnabled() &&
- mText instanceof Spannable && mLayout != null) {
+ } else if ((mMovement != null || onCheckIsTextEditor()) && mText instanceof Spannable &&
+ mLayout != null) {
boolean handled = false;
// Save previous selection, in case this event is used to show the IME.
@@ -6911,12 +6911,14 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
}
}
- if (handled) {
- return true;
- }
+ if (handled) result = true;
+ }
+
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ mNoContextMenuOnUp = false;
}
- return superResult;
+ return result;
}
private void prepareCursorControllers() {
@@ -8200,9 +8202,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
final int slopSquared = doubleTapSlop * doubleTapSlop;
if (distanceSquared < slopSquared) {
startTextSelectionMode();
- // Hacky: onTapUpEvent will open a context menu with cut/copy
- // Prevent this by hiding handles which will be revived instead.
- hide();
+ // prevents onTapUpEvent from opening a context menu with cut/copy
+ mNoContextMenuOnUp = true;
}
}
mPreviousTapPositionX = x;
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 841de06..fb2a72b 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -68,7 +68,7 @@ public class ResolverActivity extends AlertActivity implements
protected void onCreate(Bundle savedInstanceState, Intent intent,
CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
- boolean alwaysUseOption) {
+ boolean alwaysUseOption, boolean alwaysChoose) {
super.onCreate(savedInstanceState);
mPm = getPackageManager();
intent.setComponent(null);
@@ -90,9 +90,10 @@ public class ResolverActivity extends AlertActivity implements
mClearDefaultHint.setVisibility(View.GONE);
}
mAdapter = new ResolveListAdapter(this, intent, initialIntents, rList);
- if (mAdapter.getCount() > 1) {
+ int count = mAdapter.getCount();
+ if (count > 1 || (count == 1 && alwaysChoose)) {
ap.mAdapter = mAdapter;
- } else if (mAdapter.getCount() == 1) {
+ } else if (count == 1) {
startActivity(mAdapter.intentForPosition(0));
finish();
return;
@@ -103,11 +104,22 @@ public class ResolverActivity extends AlertActivity implements
setupAlert();
}
+ protected void onCreate(Bundle savedInstanceState, Intent intent,
+ CharSequence title, Intent[] initialIntents, List<ResolveInfo> rList,
+ boolean alwaysUseOption) {
+ onCreate(savedInstanceState, intent, title, initialIntents, rList, alwaysUseOption, false);
+ }
+
public void onClick(DialogInterface dialog, int which) {
ResolveInfo ri = mAdapter.resolveInfoForPosition(which);
Intent intent = mAdapter.intentForPosition(which);
+ boolean alwaysCheck = (mAlwaysCheck != null && mAlwaysCheck.isChecked());
+ onIntentSelected(ri, intent, alwaysCheck);
+ finish();
+ }
- if ((mAlwaysCheck != null) && mAlwaysCheck.isChecked()) {
+ protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
+ if (alwaysCheck) {
// Build a reasonable intent filter, based on what matched.
IntentFilter filter = new IntentFilter();
@@ -190,7 +202,6 @@ public class ResolverActivity extends AlertActivity implements
if (intent != null) {
startActivity(intent);
}
- finish();
}
private final class DisplayResolveInfo {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 9ec9610..7220983 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -68,7 +68,7 @@ public final class BatteryStatsImpl extends BatteryStats {
private static final int MAGIC = 0xBA757475; // 'BATSTATS'
// Current on-disk Parcel version
- private static final int VERSION = 52;
+ private static final int VERSION = 53;
// Maximum number of items we will record in the history.
private static final int MAX_HISTORY_ITEMS = 2000;
@@ -235,6 +235,12 @@ public final class BatteryStatsImpl extends BatteryStats {
int mDischargeCurrentLevel;
int mLowDischargeAmountSinceCharge;
int mHighDischargeAmountSinceCharge;
+ int mDischargeScreenOnUnplugLevel;
+ int mDischargeScreenOffUnplugLevel;
+ int mDischargeAmountScreenOn;
+ int mDischargeAmountScreenOnSinceCharge;
+ int mDischargeAmountScreenOff;
+ int mDischargeAmountScreenOffSinceCharge;
long mLastWriteTime = 0; // Milliseconds
@@ -1567,6 +1573,11 @@ public final class BatteryStatsImpl extends BatteryStats {
// Fake a wake lock, so we consider the device waked as long
// as the screen is on.
noteStartWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
+
+ // Update discharge amounts.
+ if (mOnBatteryInternal) {
+ updateDischargeScreenLevels(false, true);
+ }
}
}
@@ -1583,6 +1594,11 @@ public final class BatteryStatsImpl extends BatteryStats {
}
noteStopWakeLocked(-1, -1, "dummy", WAKE_TYPE_PARTIAL);
+
+ // Update discharge amounts.
+ if (mOnBatteryInternal) {
+ updateDischargeScreenLevels(true, false);
+ }
}
}
@@ -3899,8 +3915,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mDischargeStartLevel = 0;
mDischargeUnplugLevel = 0;
mDischargeCurrentLevel = 0;
- mLowDischargeAmountSinceCharge = 0;
- mHighDischargeAmountSinceCharge = 0;
+ initDischarge();
}
public BatteryStatsImpl(Parcel p) {
@@ -3970,6 +3985,15 @@ public final class BatteryStatsImpl extends BatteryStats {
mUnpluggedBatteryUptime = getBatteryUptimeLocked(mUptimeStart);
mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(mRealtimeStart);
}
+
+ void initDischarge() {
+ mLowDischargeAmountSinceCharge = 0;
+ mHighDischargeAmountSinceCharge = 0;
+ mDischargeAmountScreenOn = 0;
+ mDischargeAmountScreenOnSinceCharge = 0;
+ mDischargeAmountScreenOff = 0;
+ mDischargeAmountScreenOffSinceCharge = 0;
+ }
public void resetAllStatsLocked() {
mStartCount = 0;
@@ -4007,11 +4031,33 @@ public final class BatteryStatsImpl extends BatteryStats {
mKernelWakelockStats.clear();
}
- mLowDischargeAmountSinceCharge = 0;
- mHighDischargeAmountSinceCharge = 0;
+ initDischarge();
clearHistoryLocked();
}
+
+ void updateDischargeScreenLevels(boolean oldScreenOn, boolean newScreenOn) {
+ if (oldScreenOn) {
+ int diff = mDischargeScreenOnUnplugLevel - mDischargeCurrentLevel;
+ if (diff > 0) {
+ mDischargeAmountScreenOn += diff;
+ mDischargeAmountScreenOnSinceCharge += diff;
+ }
+ } else {
+ int diff = mDischargeScreenOffUnplugLevel - mDischargeCurrentLevel;
+ if (diff > 0) {
+ mDischargeAmountScreenOff += diff;
+ mDischargeAmountScreenOffSinceCharge += diff;
+ }
+ }
+ if (newScreenOn) {
+ mDischargeScreenOnUnplugLevel = mDischargeCurrentLevel;
+ mDischargeScreenOffUnplugLevel = 0;
+ } else {
+ mDischargeScreenOnUnplugLevel = 0;
+ mDischargeScreenOffUnplugLevel = mDischargeCurrentLevel;
+ }
+ }
void setOnBattery(boolean onBattery, int oldStatus, int level) {
synchronized(this) {
@@ -4047,6 +4093,15 @@ public final class BatteryStatsImpl extends BatteryStats {
mUnpluggedBatteryUptime = getBatteryUptimeLocked(uptime);
mUnpluggedBatteryRealtime = getBatteryRealtimeLocked(realtime);
mDischargeCurrentLevel = mDischargeUnplugLevel = level;
+ if (mScreenOn) {
+ mDischargeScreenOnUnplugLevel = level;
+ mDischargeScreenOffUnplugLevel = 0;
+ } else {
+ mDischargeScreenOnUnplugLevel = 0;
+ mDischargeScreenOffUnplugLevel = level;
+ }
+ mDischargeAmountScreenOn = 0;
+ mDischargeAmountScreenOff = 0;
doUnplugLocked(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime);
} else {
updateKernelWakelocksLocked();
@@ -4062,6 +4117,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mLowDischargeAmountSinceCharge += mDischargeUnplugLevel-level-1;
mHighDischargeAmountSinceCharge += mDischargeUnplugLevel-level;
}
+ updateDischargeScreenLevels(mScreenOn, mScreenOn);
doPlugLocked(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime));
}
if (doWrite || (mLastWriteTime + (60 * 1000)) < mSecRealtime) {
@@ -4350,6 +4406,50 @@ public final class BatteryStatsImpl extends BatteryStats {
return val;
}
}
+
+ public int getDischargeAmountScreenOn() {
+ synchronized(this) {
+ int val = mDischargeAmountScreenOn;
+ if (mOnBattery && mScreenOn
+ && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
+ val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
+ }
+ return val;
+ }
+ }
+
+ public int getDischargeAmountScreenOnSinceCharge() {
+ synchronized(this) {
+ int val = mDischargeAmountScreenOnSinceCharge;
+ if (mOnBattery && mScreenOn
+ && mDischargeCurrentLevel < mDischargeScreenOnUnplugLevel) {
+ val += mDischargeScreenOnUnplugLevel-mDischargeCurrentLevel;
+ }
+ return val;
+ }
+ }
+
+ public int getDischargeAmountScreenOff() {
+ synchronized(this) {
+ int val = mDischargeAmountScreenOff;
+ if (mOnBattery && !mScreenOn
+ && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
+ val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
+ }
+ return val;
+ }
+ }
+
+ public int getDischargeAmountScreenOffSinceCharge() {
+ synchronized(this) {
+ int val = mDischargeAmountScreenOffSinceCharge;
+ if (mOnBattery && !mScreenOn
+ && mDischargeCurrentLevel < mDischargeScreenOffUnplugLevel) {
+ val += mDischargeScreenOffUnplugLevel-mDischargeCurrentLevel;
+ }
+ return val;
+ }
+ }
@Override
public int getCpuSpeedSteps() {
@@ -4608,7 +4708,7 @@ public final class BatteryStatsImpl extends BatteryStats {
mHistory = mHistoryEnd = mHistoryCache = null;
mHistoryBaseTime = 0;
long time;
- while ((time=in.readLong()) >= 0) {
+ while (in.dataAvail() > 0 && (time=in.readLong()) >= 0) {
HistoryItem rec = new HistoryItem(time, in);
addHistoryRecordLocked(rec);
if (rec.time > mHistoryBaseTime) {
@@ -4656,7 +4756,9 @@ public final class BatteryStatsImpl extends BatteryStats {
mDischargeCurrentLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
-
+ mDischargeAmountScreenOnSinceCharge = in.readInt();
+ mDischargeAmountScreenOffSinceCharge = in.readInt();
+
mStartCount++;
mScreenOn = false;
@@ -4851,6 +4953,8 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(mDischargeCurrentLevel);
out.writeInt(getLowDischargeAmountSinceCharge());
out.writeInt(getHighDischargeAmountSinceCharge());
+ out.writeInt(getDischargeAmountScreenOnSinceCharge());
+ out.writeInt(getDischargeAmountScreenOffSinceCharge());
mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL);
for (int i=0; i<NUM_SCREEN_BRIGHTNESS_BINS; i++) {
@@ -5090,6 +5194,10 @@ public final class BatteryStatsImpl extends BatteryStats {
mDischargeCurrentLevel = in.readInt();
mLowDischargeAmountSinceCharge = in.readInt();
mHighDischargeAmountSinceCharge = in.readInt();
+ mDischargeAmountScreenOn = in.readInt();
+ mDischargeAmountScreenOnSinceCharge = in.readInt();
+ mDischargeAmountScreenOff = in.readInt();
+ mDischargeAmountScreenOffSinceCharge = in.readInt();
mLastWriteTime = in.readLong();
mMobileDataRx[STATS_LAST] = in.readLong();
@@ -5191,6 +5299,10 @@ public final class BatteryStatsImpl extends BatteryStats {
out.writeInt(mDischargeCurrentLevel);
out.writeInt(mLowDischargeAmountSinceCharge);
out.writeInt(mHighDischargeAmountSinceCharge);
+ out.writeInt(mDischargeAmountScreenOn);
+ out.writeInt(mDischargeAmountScreenOnSinceCharge);
+ out.writeInt(mDischargeAmountScreenOff);
+ out.writeInt(mDischargeAmountScreenOffSinceCharge);
out.writeLong(mLastWriteTime);
out.writeLong(getMobileTcpBytesReceived(STATS_SINCE_UNPLUGGED));
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index f0e5517..060f858 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -511,7 +511,7 @@ public class ZygoteInit {
String args[] = {
"--setuid=1000",
"--setgid=1000",
- "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,3001,3002,3003",
+ "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,3001,3002,3003",
"--capabilities=130104352,130104352",
"--runtime-init",
"--nice-name=system_server",
diff --git a/core/java/com/google/android/mms/pdu/PduParser.java b/core/java/com/google/android/mms/pdu/PduParser.java
index 8edfe52..3f185aa 100644..100755
--- a/core/java/com/google/android/mms/pdu/PduParser.java
+++ b/core/java/com/google/android/mms/pdu/PduParser.java
@@ -29,6 +29,8 @@ import java.io.UnsupportedEncodingException;
import java.util.Arrays;
import java.util.HashMap;
+import android.content.res.Resources;
+
public class PduParser {
/**
* The next are WAP values defined in WSP specification.
@@ -1557,43 +1559,55 @@ public class PduParser {
* Attachment = <Octet 129>
* Inline = <Octet 130>
*/
- int len = parseValueLength(pduDataStream);
- pduDataStream.mark(1);
- int thisStartPos = pduDataStream.available();
- int thisEndPos = 0;
- int value = pduDataStream.read();
-
- if (value == PduPart.P_DISPOSITION_FROM_DATA ) {
- part.setContentDisposition(PduPart.DISPOSITION_FROM_DATA);
- } else if (value == PduPart.P_DISPOSITION_ATTACHMENT) {
- part.setContentDisposition(PduPart.DISPOSITION_ATTACHMENT);
- } else if (value == PduPart.P_DISPOSITION_INLINE) {
- part.setContentDisposition(PduPart.DISPOSITION_INLINE);
- } else {
- pduDataStream.reset();
- /* Token-text */
- part.setContentDisposition(parseWapString(pduDataStream, TYPE_TEXT_STRING));
- }
- /* get filename parameter and skip other parameters */
- thisEndPos = pduDataStream.available();
- if (thisStartPos - thisEndPos < len) {
- value = pduDataStream.read();
- if (value == PduPart.P_FILENAME) { //filename is text-string
- part.setFilename(parseWapString(pduDataStream, TYPE_TEXT_STRING));
+ /*
+ * some carrier mmsc servers do not support content_disposition
+ * field correctly
+ */
+ boolean contentDisposition = Resources.getSystem().getBoolean(com
+ .android.internal.R.bool.config_mms_content_disposition_support);
+
+ if (contentDisposition) {
+ int len = parseValueLength(pduDataStream);
+ pduDataStream.mark(1);
+ int thisStartPos = pduDataStream.available();
+ int thisEndPos = 0;
+ int value = pduDataStream.read();
+
+ if (value == PduPart.P_DISPOSITION_FROM_DATA ) {
+ part.setContentDisposition(PduPart.DISPOSITION_FROM_DATA);
+ } else if (value == PduPart.P_DISPOSITION_ATTACHMENT) {
+ part.setContentDisposition(PduPart.DISPOSITION_ATTACHMENT);
+ } else if (value == PduPart.P_DISPOSITION_INLINE) {
+ part.setContentDisposition(PduPart.DISPOSITION_INLINE);
+ } else {
+ pduDataStream.reset();
+ /* Token-text */
+ part.setContentDisposition(parseWapString(pduDataStream
+ , TYPE_TEXT_STRING));
}
- /* skip other parameters */
+ /* get filename parameter and skip other parameters */
thisEndPos = pduDataStream.available();
if (thisStartPos - thisEndPos < len) {
- int last = len - (thisStartPos - thisEndPos);
- byte[] temp = new byte[last];
- pduDataStream.read(temp, 0, last);
+ value = pduDataStream.read();
+ if (value == PduPart.P_FILENAME) { //filename is text-string
+ part.setFilename(parseWapString(pduDataStream
+ , TYPE_TEXT_STRING));
+ }
+
+ /* skip other parameters */
+ thisEndPos = pduDataStream.available();
+ if (thisStartPos - thisEndPos < len) {
+ int last = len - (thisStartPos - thisEndPos);
+ byte[] temp = new byte[last];
+ pduDataStream.read(temp, 0, last);
+ }
}
- }
- tempPos = pduDataStream.available();
- lastLen = length - (startPos - tempPos);
+ tempPos = pduDataStream.available();
+ lastLen = length - (startPos - tempPos);
+ }
break;
default:
if (LOCAL_LOGV) {
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index de18f9f..d1a5546 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -115,6 +115,10 @@ static jobject movie_decodeByteArray(JNIEnv* env, jobject clazz,
return create_jmovie(env, moov);
}
+static void movie_destructor(JNIEnv* env, jobject, SkMovie* movie) {
+ delete movie;
+}
+
//////////////////////////////////////////////////////////////////////////////////////////////
#include <android_runtime/AndroidRuntime.h>
@@ -129,6 +133,7 @@ static JNINativeMethod gMethods[] = {
(void*)movie_draw },
{ "decodeStream", "(Ljava/io/InputStream;)Landroid/graphics/Movie;",
(void*)movie_decodeStream },
+ { "nativeDestructor","(I)V", (void*)movie_destructor },
{ "decodeByteArray", "([BII)Landroid/graphics/Movie;",
(void*)movie_decodeByteArray },
};
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index 6575b9a..4d9bb3b 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -43,6 +43,15 @@ int dhcp_do_request(const char *ifname,
int dhcp_stop(const char *ifname);
int dhcp_release_lease(const char *ifname);
char *dhcp_get_errmsg();
+
+int dhcp_do_request_renew(const char *ifname,
+ in_addr_t *ipaddr,
+ in_addr_t *gateway,
+ in_addr_t *mask,
+ in_addr_t *dns1,
+ in_addr_t *dns2,
+ in_addr_t *server,
+ uint32_t *lease);
}
#define NETUTILS_PKG_NAME "android/net/NetworkUtils"
@@ -211,6 +220,28 @@ static jboolean android_net_utils_configureInterface(JNIEnv* env,
return (jboolean)(result == 0);
}
+static jboolean android_net_utils_runDhcpRenew(JNIEnv* env, jobject clazz, jstring ifname, jobject info)
+{
+ int result = -1;
+ in_addr_t ipaddr, gateway, mask, dns1, dns2, server;
+ uint32_t lease;
+
+ const char *nameStr = env->GetStringUTFChars(ifname, NULL);
+ result = ::dhcp_do_request_renew(nameStr, &ipaddr, &gateway, &mask,
+ &dns1, &dns2, &server, &lease);
+ env->ReleaseStringUTFChars(ifname, nameStr);
+ if (result == 0 && dhcpInfoFieldIds.dhcpInfoClass != NULL) {
+ env->SetIntField(info, dhcpInfoFieldIds.ipaddress, ipaddr);
+ env->SetIntField(info, dhcpInfoFieldIds.gateway, gateway);
+ env->SetIntField(info, dhcpInfoFieldIds.netmask, mask);
+ env->SetIntField(info, dhcpInfoFieldIds.dns1, dns1);
+ env->SetIntField(info, dhcpInfoFieldIds.dns2, dns2);
+ env->SetIntField(info, dhcpInfoFieldIds.serverAddress, server);
+ env->SetIntField(info, dhcpInfoFieldIds.leaseDuration, lease);
+ }
+
+ return (jboolean)(result == 0);
+}
// ----------------------------------------------------------------------------
/*
@@ -232,6 +263,7 @@ static JNINativeMethod gNetworkUtilMethods[] = {
{ "releaseDhcpLease", "(Ljava/lang/String;)Z", (void *)android_net_utils_releaseDhcpLease },
{ "configureNative", "(Ljava/lang/String;IIIII)Z", (void *)android_net_utils_configureInterface },
{ "getDhcpError", "()Ljava/lang/String;", (void*) android_net_utils_getDhcpError },
+ { "runDhcpRenew", "(Ljava/lang/String;Landroid/net/DhcpInfo;)Z", (void *)android_net_utils_runDhcpRenew}
};
int register_android_net_NetworkUtils(JNIEnv* env)
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index 7a53874..8db2553 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -603,6 +603,15 @@ static jlong android_os_Binder_clearCallingIdentity(JNIEnv* env, jobject clazz)
static void android_os_Binder_restoreCallingIdentity(JNIEnv* env, jobject clazz, jlong token)
{
+ // XXX temporary sanity check to debug crashes.
+ int uid = (int)(token>>32);
+ if (uid > 0 && uid < 999) {
+ // In Android currently there are no uids in this range.
+ char buf[128];
+ sprintf(buf, "Restoring bad calling ident: 0x%Lx", token);
+ jniThrowException(env, "java/lang/IllegalStateException", buf);
+ return;
+ }
IPCThreadState::self()->restoreCallingIdentity(token);
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a130bf5..c582eee 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -55,6 +55,7 @@
<protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" />
<protected-broadcast android:name="android.intent.action.REBOOT" />
<protected-broadcast android:name="android.intent.action.DOCK_EVENT" />
+ <protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" />
<protected-broadcast android:name="android.app.action.ENTER_CAR_MODE" />
<protected-broadcast android:name="android.app.action.EXIT_CAR_MODE" />
@@ -82,12 +83,14 @@
<protected-broadcast android:name="android.bluetooth.device.action.PAIRING_REQUEST" />
<protected-broadcast android:name="android.bluetooth.device.action.PAIRING_CANCEL" />
- <protected-broadcast android:name="android.hardware.action.USB_CONNECTED" />
- <protected-broadcast android:name="android.hardware.action.USB_DISCONNECTED" />
- <protected-broadcast android:name="android.hardware.action.USB_STATE" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
<protected-broadcast android:name="android.nfc.action.LLCP_LINK_STATE_CHANGED" />
- <protected-broadcast android:name="android.nfc.action.TRANSACTION_DETECTED" />
+ <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_ON_DETECTED" />
+ <protected-broadcast android:name="com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED" />
+ <protected-broadcast android:name="com.android.nfc_extras.action.AID_SELECTED" />
<!-- ====================================== -->
<!-- Permissions for things that cost money -->
@@ -332,6 +335,14 @@
android:description="@string/permdesc_accessWifiState"
android:label="@string/permlab_accessWifiState" />
+ <!-- Allows applications to access information about WiMAX networks
+ @hide -->
+ <permission android:name="android.permission.ACCESS_WIMAX_STATE"
+ android:permissionGroup="android.permission-group.NETWORK"
+ android:protectionLevel="normal"
+ android:description="@string/permdesc_accessWimaxState"
+ android:label="@string/permlab_accessWimaxState" />
+
<!-- Allows applications to connect to paired bluetooth devices -->
<permission android:name="android.permission.BLUETOOTH"
android:permissionGroup="android.permission-group.NETWORK"
@@ -339,7 +350,7 @@
android:description="@string/permdesc_bluetooth"
android:label="@string/permlab_bluetooth" />
- <!-- Allows applications to directly communicate over NFC -->
+ <!-- Allows applications to perform I/O operations over NFC -->
<permission android:name="android.permission.NFC"
android:permissionGroup="android.permission-group.NETWORK"
android:protectionLevel="dangerous"
@@ -453,13 +464,13 @@
android:label="@string/permlab_flashlight"
android:description="@string/permdesc_flashlight" />
- <!-- Allows an application to access USB devices
+ <!-- Allows an application to manage preferences and permissions for USB devices
@hide -->
- <permission android:name="android.permission.ACCESS_USB"
+ <permission android:name="android.permission.MANAGE_USB"
android:permissionGroup="android.permission-group.HARDWARE_CONTROLS"
android:protectionLevel="signatureOrSystem"
- android:label="@string/permlab_accessUsb"
- android:description="@string/permdesc_accessUsb" />
+ android:label="@string/permlab_manageUsb"
+ android:description="@string/permdesc_manageUsb" />
<!-- Allows access to hardware peripherals. Intended only for hardware testing -->
<permission android:name="android.permission.HARDWARE_TEST"
@@ -842,6 +853,14 @@
android:description="@string/permdesc_changeWifiState"
android:label="@string/permlab_changeWifiState" />
+ <!-- Allows applications to change WiMAX connectivity state
+ @hide -->
+ <permission android:name="android.permission.CHANGE_WIMAX_STATE"
+ android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
+ android:protectionLevel="dangerous"
+ android:description="@string/permdesc_changeWimaxState"
+ android:label="@string/permlab_changeWimaxState" />
+
<!-- Allows applications to enter Wi-Fi Multicast mode -->
<permission android:name="android.permission.CHANGE_WIFI_MULTICAST_STATE"
android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
@@ -1004,7 +1023,7 @@
<permission android:name="android.permission.STOP_APP_SWITCHES"
android:label="@string/permlab_stopAppSwitches"
android:description="@string/permdesc_stopAppSwitches"
- android:protectionLevel="signature" />
+ android:protectionLevel="signatureOrSystem" />
<!-- Allows an application to retrieve the current state of keys and
switches. This is only for use by the system.-->
@@ -1330,6 +1349,12 @@
android:excludeFromRecents="true">
</activity>
+ <activity android:name="com.android.server.usb.UsbResolverActivity"
+ android:theme="@style/Theme.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
+
<service android:name="com.android.server.LoadAverageService"
android:exported="true" />
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png b/core/res/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png
new file mode 100644
index 0000000..4ff7db3
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_inandout_4g.png b/core/res/res/drawable-hdpi/stat_sys_data_inandout_4g.png
new file mode 100644
index 0000000..c5edf2c
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_inandout_4g.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..c2e4b78
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..51b839f
--- /dev/null
+++ b/core/res/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png b/core/res/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png
new file mode 100644
index 0000000..de8c5ee
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png
Binary files differ
diff --git a/core/res/res/drawable-mdpi/stat_sys_data_inandout_4g.png b/core/res/res/drawable-mdpi/stat_sys_data_inandout_4g.png
new file mode 100644
index 0000000..f407bc9
--- /dev/null
+++ b/core/res/res/drawable-mdpi/stat_sys_data_inandout_4g.png
Binary files differ
diff --git a/core/res/res/layout/contact_header.xml b/core/res/res/layout/contact_header.xml
index bf467d3..dfa9af4 100644
--- a/core/res/res/layout/contact_header.xml
+++ b/core/res/res/layout/contact_header.xml
@@ -27,7 +27,6 @@
android:layout_marginRight="8dip"
android:layout_marginLeft="-1dip"
style="@*android:style/Widget.QuickContactBadge.WindowSmall" />
- />
<LinearLayout
android:layout_width="0dip"
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 6446675..748223f 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"للسماح للتطبيق بالتحكم في الهزاز."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"التحكم في الضوء الوامض"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"للسماح للتطبيق بالتحكم في الضوء الوامض."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"الدخول إلى أجهزة USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"للسماح للتطبيق بالدخول إلى أجهزة USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"إدارة التفضيلات والأذونات لأجهزة USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"للسماح للتطبيق بإدارة التفضيلات والأذونات لأجهزة USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"اختبار الأجهزة"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"للسماح للتطبيق بالتحكم في الأجهزة الطرفية المتنوعة بغرض اختبار الأجهزة."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"اتصال مباشر بأرقام الهواتف"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"للسماح لتطبيق ما بالاتصال وفصل الاتصال بنقاط الدخول إلى Wi-Fi، وإجراء تغييرات على شبكات Wi-Fi المهيأة."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"السماح باستقبال بث Wi-Fi متعدد"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"للسماح لتطبيق ما باستلام حزم غير موجهة مباشرة إلى جهازك. يمكن أن يكون ذلك مفيدًا عند اكتشاف خدمات معروضة بالقرب منك. يستخدم ذلك الطاقة أكثر من وضع البث غير المتعدد."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"عرض حالة WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"للسماح لتطبيق ما بعرض معلومات حول حالة WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"تغيير حالة WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"للسماح لتطبيق ما بالاتصال بشبكة WiMAX وقطع الاتصال بها."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"إدارة البلوتوث"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"للسماح لتطبيق ما بتهيئة هاتف البلوتوث المحلي، واكتشاف أجهزة التحكم عن بعد والاقتران معها."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"إنشاء اتصالات بلوتوث"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"الاستخدام بشكل افتراضي لهذا الإجراء."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"محو الإعداد الافتراضي في الإعدادات الرئيسية &gt; التطبيقات &gt; إدارة التطبيقات."</string>
<string name="chooseActivity" msgid="1009246475582238425">"تحديد إجراء"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"تحديد تطبيق لجهاز USB"</string>
<string name="noApplications" msgid="1691104391758345586">"ليس هناك تطبيقات يمكنها تنفيذ هذا الإجراء."</string>
<string name="aerr_title" msgid="653922989522758100">"عذرًا!"</string>
<string name="aerr_application" msgid="4683614104336409186">"توقف التطبيق <xliff:g id="APPLICATION">%1$s</xliff:g> (العملية <xliff:g id="PROCESS">%2$s</xliff:g>) على نحو غير متوقع. الرجاء المحاولة مرة أخرى."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 793b033..5a33fe7 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Разрешава на приложението да контролира устройството за вибрация."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"контролиране на фенерчето"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Разрешава на приложението да контролира фенерчето."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"достъп до USB устройства"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Разрешава на приложението достъп до USB устройства."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"управление на предпочитанията и разрешенията за USB устройства"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Разрешава на приложението да управлява предпочитанията и разрешенията за USB устройства."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"тест на хардуера"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Разрешава на приложението да контролира различни периферни устройства с цел тестване на хардуера."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"директно обаждане до телефонни номера"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Разрешава на приложението да се свързва към Wi-Fi точки за достъп и да прекратява връзката с тях, както и да извършва промени в конфигурирани Wi-Fi мрежи."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"разрешаване на приемане на мултикаст през Wi-Fi мрежата"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Разрешава на приложението да получава пакети, които не са адресирани директно към устройството ви. Това може да е полезно при откриване на предлагани в района услуги. Консумира се повече мощност, отколкото в режим без мултикаст."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"преглед на състоянието на WiMAX мрежата"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Разрешава на приложението да вижда информацията за състоянието на WiMAX мрежата."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"промяна на състоянието на WiMAX мрежата"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Разрешава на приложението да се свързва към WiMAX мрежа и да прекратява връзката с нея."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"администриране на Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Разрешава на приложението да конфигурира локалния Bluetooth телефон, както и да открива и да се сдвоява с отдалечени устройства."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"създаване на връзки през Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Използване по подразбиране за това действие."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Изчистване на стандартната стойност в „Начални настройки“ &gt; „Приложения“ &gt; „Управление на приложенията“."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Избиране на действие"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Избор на приложение за USB устройството"</string>
<string name="noApplications" msgid="1691104391758345586">"Това действие не може да се изпълни от нито едно приложение."</string>
<string name="aerr_title" msgid="653922989522758100">"Съжаляваме!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Приложението „<xliff:g id="APPLICATION">%1$s</xliff:g>“ (процес „<xliff:g id="PROCESS">%2$s</xliff:g>“) спря неочаквано. Моля, опитайте отново."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index d10b4d4..43d3186 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Permet a l\'aplicació controlar el vibrador."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"controlar el flaix"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Permet a l\'aplicació controlar el flaix."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"accedeix a dispositius USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permet que l\'aplicació accedeixi als dispositius USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"gestiona les preferències i els permisos dels dispositius USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permet que l\'aplicació gestioni les preferències i els permisos dels dispositius USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"provar el maquinari"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Permet a l\'aplicació controlar diversos perifèrics per fer proves de maquinari."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"trucar directament a números de telèfon"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permet a una aplicació connectar-se i desconnectar-se de punts d\'accés Wi-fi i fer canvis a les xarxes Wi-fi configurades."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permetre la recepció de multidifusió Wi-fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permet a una aplicació rebre paquets no adreçats directament al vostre dispositiu. Això pot ser útil en detectar serveis oferts a prop. Utilitza més energia que el mode que no utilitza la multidifusió."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"visualitza l\'estat de WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Permet que una aplicació visualitzi la informació sobre l\'estat de WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"canvia l\'estat de WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Permet que una aplicació es connecti i es desconnecti d\'una xarxa WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administració de Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permet a una aplicació configurar el telèfon Bluetooth local i detectar dispositius remots i emparellar-se amb ells."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"crear connexions Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Utilitza-ho de manera predeterminada per a aquesta acció."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Esborra el valor predeterminat a Configuració de la pantalla d\'inici &gt; Aplicacions &gt; Gestiona les aplicacions."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Seleccioneu una acció"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Selecciona una aplicació per al dispositiu USB"</string>
<string name="noApplications" msgid="1691104391758345586">"No hi ha cap aplicació que pugui dur a terme aquesta acció."</string>
<string name="aerr_title" msgid="653922989522758100">"Ho sentim."</string>
<string name="aerr_application" msgid="4683614104336409186">"L\'aplicació <xliff:g id="APPLICATION">%1$s</xliff:g> (procés <xliff:g id="PROCESS">%2$s</xliff:g>) s\'ha aturat inesperadament. Torneu-ho a provar."</string>
@@ -762,17 +767,17 @@
<string name="volume_ringtone" msgid="6885421406845734650">"Volum del timbre"</string>
<string name="volume_music" msgid="5421651157138628171">"Volum de multimèdia"</string>
<string name="volume_music_hint_playing_through_bluetooth" msgid="9165984379394601533">"S\'està reproduint a través de Bluetooth"</string>
- <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"So de trucada silenciós seleccionat"</string>
+ <string name="volume_music_hint_silent_ringtone_selected" msgid="6158339745293431194">"To de silenci seleccionat"</string>
<string name="volume_call" msgid="3941680041282788711">"Volum en trucada"</string>
<string name="volume_bluetooth_call" msgid="2002891926351151534">"Volum en trucada Bluetooth"</string>
<string name="volume_alarm" msgid="1985191616042689100">"Volum de l\'alarma"</string>
<string name="volume_notification" msgid="2422265656744276715">"Volum de notificació"</string>
<string name="volume_unknown" msgid="1400219669770445902">"Volum"</string>
- <string name="ringtone_default" msgid="3789758980357696936">"So de trucada predeterminat"</string>
- <string name="ringtone_default_with_actual" msgid="8129563480895990372">"So de trucada predeterminat (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
+ <string name="ringtone_default" msgid="3789758980357696936">"To predeterminat"</string>
+ <string name="ringtone_default_with_actual" msgid="8129563480895990372">"To predeterminat (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="4440324407807468713">"Silenci"</string>
<string name="ringtone_picker_title" msgid="3515143939175119094">"Sons de trucada"</string>
- <string name="ringtone_unknown" msgid="5477919988701784788">"So de trucada desconegut"</string>
+ <string name="ringtone_unknown" msgid="5477919988701784788">"To desconegut"</string>
<plurals name="wifi_available">
<item quantity="one" msgid="6654123987418168693">"Xarxa Wi-fi disponible"</item>
<item quantity="other" msgid="4192424489168397386">"Xarxes Wi-fi disponibles"</item>
@@ -790,7 +795,7 @@
<string name="date_time_set" msgid="5777075614321087758">"Defineix"</string>
<string name="default_permission_group" msgid="2690160991405646128">"Predeterminat"</string>
<string name="no_permissions" msgid="7283357728219338112">"No cal cap permís"</string>
- <string name="perms_hide" msgid="7283915391320676226"><b>"Oculta"</b></string>
+ <string name="perms_hide" msgid="7283915391320676226"><b>"Oamaga"</b></string>
<string name="perms_show_all" msgid="2671791163933091180"><b>"Mostra\'ls tots"</b></string>
<string name="usb_storage_activity_title" msgid="2399289999608900443">"Emmagatzematge massiu USB"</string>
<string name="usb_storage_title" msgid="5901459041398751495">"USB connectat"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 0e57306..41c60f7 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Umožňuje aplikaci ovládat vibrace."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"ovládání kontrolky"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Umožňuje aplikaci ovládat kontrolku."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"přístup k zařízením USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Umožní aplikaci přístup k zařízením USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"spravovat nastavení a oprávnění pro zařízení USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Umožňuje aplikaci spravovat nastavení a oprávnění pro zařízení USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testování hardwaru"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Umožňuje aplikaci ovládat různé periferie pro účely testování hardwaru."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"přímé volání na telefonní čísla"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Umožňuje aplikaci připojit se k přístupovým bodům WiFi či se od nich odpojit a provádět změny nakonfigurovaných sítí WiFi."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"povolení příjmu Wi-Fi Multicast"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Povoluje aplikaci přijímat pakety, které nebyly adresovány přímo vašemu zařízení. Pomocí této možnosti můžete objevit služby nabízené ve vaší blízkosti. Spotřeba energie je vyšší než u režimu bez vícesměrového vysílání (multicast)."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"zobrazit stav připojení WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Umožňuje aplikaci zobrazit informace o stavu připojení WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"měnit stav připojení WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Umožňuje aplikaci připojovat se k síti WiMAX a odpojovat se od ní."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"správa rozhraní Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Umožňuje aplikaci konfigurovat místní telefon s rozhraním Bluetooth a vyhledávat a párovat vzdálená zařízení."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"vytvoření připojení Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Použít jako výchozí nastavení pro tuto činnost."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Vymažte výchozí hodnoty v Nastavení plochy &gt; Aplikace &gt; Správa aplikací."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Vyberte akci"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Zvolte aplikaci pro zařízení USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Tuto činnost nemohou provádět žádné aplikace."</string>
<string name="aerr_title" msgid="653922989522758100">"Omlouváme se"</string>
<string name="aerr_application" msgid="4683614104336409186">"Aplikace <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) byla neočekávaně ukončena. Zkuste to znovu."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 520e0b0..87c8c55 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Lader programmet kontrollere vibratoren."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"kontroller lommelygte"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Tillader, at programmet kontrollerer lommelygten."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"adgang til USB-enheder."</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Tillader, at programmet har adgang til USB-enheder."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"administrer præferencer og tilladelser for USB-enheder"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Tillader, at programmet administrerer præferencer og tilladelser for USB-enheder."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"test hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Tillader, at et program kontrollerer forskellige perifere enheder for at teste hardwaren."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ring direkte op til telefonnumre"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Tillader, at et program opretter og afbryder forbindelsen fra Wi-Fi-adgangspunkter og foretager ændringer i konfigurerede Wi-Fi-netværk."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"tillad Wi-Fi-multicastmodtagelse"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Tillader, at et program modtager pakker, der ikke er direkte adresseret til din enhed. Dette kan være nyttigt, hvis du finder tjenester, der tilbydes i nærheden. Det bruger mere strøm end multicasttilstanden."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"vise WiMAX-tilstand"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Tillader, at en applikation viser oplysninger om WiMAX-tilstanden."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"skifte WiMAX-tilstand"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Tillader, at en applikation opretter og afbryder forbindelsen til WiMAX-netværk."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth-administration"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Tillader, at et program konfigurerer den lokale Bluetooth-telefon samt opdager og parrer med fjerne enheder."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"opret Bluetooth-forbindelser"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Brug som standard til denne handling."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Ryd standard i Startindstillinger &gt; Programmer &gt; Administrer programmer."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Vælg en handling"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Vælg et program for USB-enheden"</string>
<string name="noApplications" msgid="1691104391758345586">"Der er ingen programmer, der kan foretage denne handling."</string>
<string name="aerr_title" msgid="653922989522758100">"Beklager!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) er standset uventet. Prøv igen."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 7819c6d..4c1b997 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -49,7 +49,7 @@
<string name="needPuk" msgid="919668385956251611">"Ihre SIM-Karte ist mit einem PUK gesperrt. Geben Sie zum Entsperren den PUK-Code ein."</string>
<string name="needPuk2" msgid="4526033371987193070">"Geben Sie zum Entsperren der SIM-Karte den PUK2 ein."</string>
<string name="ClipMmi" msgid="6952821216480289285">"Anrufer-ID für eingehenden Anruf"</string>
- <string name="ClirMmi" msgid="7784673673446833091">"Anrufer-ID für abgehenden Anruf"</string>
+ <string name="ClirMmi" msgid="7784673673446833091">"Anrufer-ID für ausgehenden Anruf"</string>
<string name="CfMmi" msgid="5123218989141573515">"Rufweiterleitung"</string>
<string name="CwMmi" msgid="9129678056795016867">"Anklopfen"</string>
<string name="BaMmi" msgid="455193067926770581">"Anrufsperre"</string>
@@ -147,17 +147,17 @@
<string name="global_actions_airplane_mode_on_status" msgid="2719557982608919750">"Flugmodus ist AN."</string>
<string name="global_actions_airplane_mode_off_status" msgid="5075070442854490296">"Flugmodus ist AUS."</string>
<string name="safeMode" msgid="2788228061547930246">"Abgesicherter Modus"</string>
- <string name="android_system_label" msgid="6577375335728551336">"Android System"</string>
+ <string name="android_system_label" msgid="6577375335728551336">"Android-System"</string>
<string name="permgrouplab_costMoney" msgid="5429808217861460401">"Kostenpflichtige Dienste"</string>
- <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen."</string>
+ <string name="permgroupdesc_costMoney" msgid="8193824940620517189">"Ermöglicht Anwendungen die Ausführung eventuell kostenpflichtiger Aktionen"</string>
<string name="permgrouplab_messages" msgid="7521249148445456662">"Ihre Nachrichten"</string>
<string name="permgroupdesc_messages" msgid="7045736972019211994">"Lesen und schreiben Sie Ihre SMS, E-Mails und anderen Nachrichten."</string>
<string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Ihre persönlichen Informationen"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons."</string>
+ <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Direkter Zugriff auf die Kontakte und den Kalender Ihres Telefons"</string>
<string name="permgrouplab_location" msgid="635149742436692049">"Ihren Standort"</string>
<string name="permgroupdesc_location" msgid="2430258821648348660">"Ihren physischen Standort überwachen"</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Netzwerkkommunikation"</string>
- <string name="permgroupdesc_network" msgid="5035763698958415998">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen."</string>
+ <string name="permgroupdesc_network" msgid="5035763698958415998">"Ermöglicht Anwendungen den Zugriff auf verschiedene Netzwerkfunktionen"</string>
<string name="permgrouplab_accounts" msgid="3359646291125325519">"Ihre Konten"</string>
<string name="permgroupdesc_accounts" msgid="4948732641827091312">"Zugriff auf verfügbare Konten"</string>
<string name="permgrouplab_hardwareControls" msgid="7998214968791599326">"Hardware-Steuerelemente"</string>
@@ -170,14 +170,14 @@
<string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Funktionen nur für Anwendungsentwickler vorgesehen."</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Speicher"</string>
<string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Zugriff auf USB-Speicher"</string>
- <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Greift auf die SD-Karte zu."</string>
+ <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Zugriff auf SD-Karte"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Statusleiste deaktivieren oder ändern"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen."</string>
+ <string name="permdesc_statusBar" msgid="1365473595331989732">"Ermöglicht der Anwendung, die Statusanzeige zu deaktivieren oder Systemsymbole hinzuzufügen oder zu entfernen"</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"Statusleiste"</string>
- <string name="permdesc_statusBarService" msgid="4097605867643520920">"Ermöglicht der Anwendung, zur Statusleiste zu werden."</string>
+ <string name="permdesc_statusBarService" msgid="4097605867643520920">"Ermöglicht der Anwendung, zur Statusleiste zu werden"</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"Statusleiste ein-/ausblenden"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"Abgehende Anrufe abfangen"</string>
+ <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Ermöglicht der Anwendung, die Statusleiste ein- oder auszublenden"</string>
+ <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"Ausgehende Anrufe abfangen"</string>
<string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Ermöglicht einer Anwendung, abgehende Anrufe zu verarbeiten und die zu wählende Nummer zu ändern. Schädliche Anwendungen können so abgehende Anrufe eventuell überwachen, umleiten oder verhindern."</string>
<string name="permlab_receiveSms" msgid="2697628268086208535">"SMS empfangen"</string>
<string name="permdesc_receiveSms" msgid="6298292335965966117">"Ermöglicht der Anwendung, Kurzmitteilungen zu empfangen und zu verarbeiten. Schädliche Anwendungen können Ihre Nachrichten möglicherweise überwachen oder löschen, bevor sie angezeigt werden."</string>
@@ -198,13 +198,13 @@
<string name="permlab_setDebugApp" msgid="4339730312925176742">"Fehlerbeseitigung für Anwendung aktivieren"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Ermöglicht einer Anwendung, die Fehlerbeseitigung für eine andere Anwendung zu aktivieren. Schädliche Anwendungen können so andere Anwendungen löschen."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"UI-Einstellungen ändern"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße."</string>
+ <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Ermöglicht einer Anwendung, die aktuelle Konfiguration zu ändern, etwa das Gebietsschema oder die Schriftgröße"</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"Automodus aktivieren"</string>
- <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Ermöglicht einer Anwendung, den Automodus zu aktivieren."</string>
+ <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Ermöglicht einer Anwendung, den Automodus zu aktivieren"</string>
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"Hintergrundprozesse beenden"</string>
<string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Ermöglicht einer Anwendung, Hintergrundprozesse anderer Anwendungen auch bei ausreichendem Speicher zu beenden."</string>
<string name="permlab_forceStopPackages" msgid="1447830113260156236">"Beenden anderer Anwendungen erzwingen"</string>
- <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Ermöglicht einer Anwendung, das Beenden anderer Anwendungen zu erzwingen."</string>
+ <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Ermöglicht einer Anwendung, das Beenden anderer Anwendungen zu erzwingen"</string>
<string name="permlab_forceBack" msgid="1804196839880393631">"Schließen von Anwendung erzwingen"</string>
<string name="permdesc_forceBack" msgid="6534109744159919013">"Ermöglicht einer Anwendung, alle Aktivitäten, die im Vordergrund ablaufen, zu beenden und in den Hintergrund zu schieben. Sollte nicht für normale Anwendungen benötigt werden."</string>
<string name="permlab_dump" msgid="1681799862438954752">"Systeminternen Status abrufen"</string>
@@ -234,7 +234,7 @@
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"Warnungen auf Systemebene anzeigen"</string>
<string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Ermöglicht einer Anwendung, Fenster mit Systemwarnungen anzuzeigen. Schädliche Anwendungen können so das gesamte Display des Telefons einnehmen."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"Allgemeine Animationsgeschwindigkeit einstellen"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen."</string>
+ <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Ermöglicht einer Anwendung, die allgemeine Animationsgeschwindigkeit (schnellere oder langsamere Animationen) jederzeit anzupassen"</string>
<string name="permlab_manageAppTokens" msgid="17124341698093865">"Anwendungs-Tokens verwalten"</string>
<string name="permdesc_manageAppTokens" msgid="977127907524195988">"Ermöglicht Anwendungen, Ihre eigenen Tokens zu erstellen und zu verwalten. Hierbei wird die normale Z-Reihenfolge umgangen. Dies sollte nicht für normale Anwendungen benötigt werden."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"Tasten und Steuerungstasten drücken"</string>
@@ -250,23 +250,23 @@
<string name="permlab_setOrientation" msgid="3365947717163866844">"Bildschirmausrichtung ändern"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Ermöglicht der Anwendung, die Bildschirmdrehung jederzeit zu ändern. Sollte nicht für normale Anwendungen benötigt werden."</string>
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-Signale an Anwendungen senden"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern."</string>
+ <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Ermöglicht der Anwendung, das Senden des gelieferten Signals an alle anhaltenden Prozesse zu fordern"</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"Anwendungen permanent ausführen"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann."</string>
+ <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Ermöglicht einer Anwendung, eigene Komponenten persistent zu machen, damit das System diese nicht für andere Anwendungen nutzen kann"</string>
<string name="permlab_deletePackages" msgid="3343439331576348805">"Anwendungen löschen"</string>
<string name="permdesc_deletePackages" msgid="3634943677518723314">"Ermöglicht einer Anwendung, Android-Pakete zu löschen. Schädliche Anwendungen können so wichtige Anwendungen löschen."</string>
<string name="permlab_clearAppUserData" msgid="2192134353540277878">"Daten anderer Anwendungen löschen"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten."</string>
+ <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Ermöglicht einer Anwendung das Löschen von Nutzerdaten"</string>
<string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"Caches anderer Anwendungen löschen"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen."</string>
+ <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Ermöglicht einer Anwendung, Cache-Dateien zu löschen"</string>
<string name="permlab_getPackageSize" msgid="4799785352306641460">"Speicherplatz der Anwendung abrufen"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen."</string>
+ <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Ermöglicht einer Anwendung, ihre Code-, Daten- und Cache-Größe abzurufen"</string>
<string name="permlab_installPackages" msgid="335800214119051089">"Anwendungen direkt installieren"</string>
<string name="permdesc_installPackages" msgid="526669220850066132">"Ermöglicht einer Anwendung, neue oder aktualisierte Android-Pakete zu installieren. Schädliche Anwendungen können so neue Anwendungen mit beliebig umfangreichen Berechtigungen hinzufügen."</string>
<string name="permlab_clearAppCache" msgid="4747698311163766540">"Alle Cache-Daten der Anwendung löschen"</string>
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Ermöglicht einer Anwendung, Telefonspeicher durch das Löschen von Dateien im Cache-Verzeichnis der Anwendung freizugeben. Der Zugriff beschränkt sich in der Regel auf Systemprozesse."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Anwendungsressourcen verschieben"</string>
- <string name="permdesc_movePackage" msgid="6323049291923925277">"Ermöglicht einer Anwendung, Anwendungsressourcen von interne auf externe Medien zu verschieben und umgekehrt."</string>
+ <string name="permdesc_movePackage" msgid="6323049291923925277">"Ermöglicht einer Anwendung, Anwendungsressourcen von internen auf externe Medien zu verschieben und umgekehrt"</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"Lesen vertraulicher Protokolldaten"</string>
<string name="permdesc_readLogs" msgid="8896449437464867766">"Ermöglicht einer Anwendung, die verschiedenen Protokolldateien des Systems zu lesen. So können allgemeine Informationen zu den auf Ihrem Telefon durchgeführten Aktionen eingesehen werden. Diese können persönliche oder geheime Daten enthalten."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"Lese-/Schreibberechtigung für zu Diagnosegruppe gehörige Elemente"</string>
@@ -284,7 +284,7 @@
<string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"Automatisch nach dem Booten starten"</string>
<string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Ermöglicht einer Anwendung, sich selbst zu starten, sobald das System gebootet wurde. Dadurch kann es länger dauern, bis das Telefon gestartet wird, und durch die ständige Aktivität der Anwendung wird die gesamte Leistung des Telefons beeinträchtigt."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"dauerhaften Broadcast senden"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Telefon langsam oder unstabil machen, da zuviel Speicherplatz belegt ist."</string>
+ <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Ermöglicht einer Anwendung, dauerhafte Broadcasts zu senden, die auch nach dem Ende des Broadcasts bestehen bleiben. Schädliche Anwendungen können das Telefon langsam oder unstabil machen, da zuviel Speicherplatz belegt wird."</string>
<string name="permlab_readContacts" msgid="6219652189510218240">"Kontaktdaten lesen"</string>
<string name="permdesc_readContacts" msgid="3371591512896545975">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kontaktdaten (Adressen) zu lesen. Schädliche Anwendungen können so Ihre Daten an andere Personen senden."</string>
<string name="permlab_writeContacts" msgid="644616215860933284">"Kontaktdaten schreiben"</string>
@@ -292,8 +292,8 @@
<string name="permlab_readCalendar" msgid="6898987798303840534">"Kalendereinträge lesen"</string>
<string name="permdesc_readCalendar" msgid="5533029139652095734">"Ermöglicht einer Anwendung, alle auf Ihrem Telefon gespeicherten Kalenderereignisse zu lesen. Schädliche Anwendungen können so Ihre Kalenderereignisse an andere Personen senden."</string>
<string name="permlab_writeCalendar" msgid="3894879352594904361">"Kalendereinträge hinzufügen oder ändern und E-Mails an Gäste senden"</string>
- <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Ermöglicht einer Anwendung, Einträge auf Ihrem Kalender hinzuzufügen oder zu ändern, die E-Mails an Gäste senden können. Schädliche Anwendungen können so Ihre Kalenderdaten löschen oder verändern oder E-Mails versenden."</string>
- <string name="permlab_accessMockLocation" msgid="8688334974036823330">"Falsche Standortquellen für Testzwecke"</string>
+ <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Ermöglicht einer Anwendung, Einträge in Ihrem Kalender hinzuzufügen oder zu ändern, wodurch E-Mails an Gäste gesendet werden können. Schädliche Anwendungen können so Ihre Kalenderdaten löschen oder verändern oder E-Mails versenden."</string>
+ <string name="permlab_accessMockLocation" msgid="8688334974036823330">"Simulierte Standortquellen für Testzwecke"</string>
<string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Erstellt falsche Standortquellen für Testzwecke. Schädliche Anwendungen können so den von den echten Standortquellen wie GPS oder Netzwerkanbieter zurückgegebenen Standort und/oder Status überschreiben."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Auf zusätzliche Dienstanbieterbefehle für Standort zugreifen"</string>
<string name="permdesc_accessLocationExtraCommands" msgid="1948144701382451721">"Zugriff auf zusätzliche Dienstanbieterbefehle für Standort. Schädliche Anwendungen könnten so die Funktionsweise von GPS oder anderen Standortquellen beeinträchtigen."</string>
@@ -302,25 +302,25 @@
<string name="permlab_accessFineLocation" msgid="8116127007541369477">"genauer (GPS-) Standort"</string>
<string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Zugriff auf genaue Standortquellen wie GPS auf dem Telefon (falls verfügbar). Schädliche Anwendungen können damit bestimmen, so Sie sich befinden und so Ihren Akku zusätzlich belasten."</string>
<string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"ungefährer (netzwerkbasierter) Standort"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzwerks zu, um falls möglich den ungefähren Standort des Telefons zu bestimmen. Schädliche Anwendungen können damit herauszufinden, wo Sie sich ungefähr befinden."</string>
+ <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Greift auf Quellen mit ungefähren Standortbestimmungen wie die Datenbank des Mobilfunknetzes zu, um falls möglich den ungefähren Standort des Tablets festzustellen. Schädliche Anwendungen können damit herausfinden, wo Sie sich ungefähr befinden"</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Auf SurfaceFlinger zugreifen"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden."</string>
+ <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Ermöglicht einer Anwendung, die systemnahen SurfaceFlinger-Funktionen zu verwenden"</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Frame-Puffer lesen"</string>
- <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Ermöglicht einer Anwendung, den Content des Frame-Puffers zu lesen."</string>
+ <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Ermöglicht einer Anwendung, den Content des Frame-Puffers zu lesen"</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"Audio-Einstellungen ändern"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen."</string>
+ <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Ermöglicht der Anwendung, Änderungen an allgemeinen Audioeinstellungen wie Lautstärke und Weiterleitung vorzunehmen"</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"Audio aufnehmen"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen."</string>
+ <string name="permdesc_recordAudio" msgid="6493228261176552356">"Ermöglicht der Anwendung, auf den Pfad für Audioaufzeichnungen zuzugreifen"</string>
<string name="permlab_camera" msgid="3616391919559751192">"Bilder und Videos aufnehmen"</string>
<string name="permdesc_camera" msgid="6004878235852154239">"Ermöglicht der Anwendung, Fotos und Videos mit der Kamera aufzunehmen. So kann die Anwendung jederzeit Bilder aus dem Sichtfeld der Kamera erfassen."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"Telefon dauerhaft deaktivieren."</string>
+ <string name="permlab_brick" msgid="8337817093326370537">"Telefon dauerhaft deaktivieren"</string>
<string name="permdesc_brick" msgid="5569526552607599221">"Ermöglicht der Anwendung, das gesamte Telefon dauerhaft zu deaktivieren. Dies birgt hohe Risiken."</string>
<string name="permlab_reboot" msgid="2898560872462638242">"Neustart des Telefons erzwingen"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen."</string>
+ <string name="permdesc_reboot" msgid="7914933292815491782">"Ermöglicht der Anwendung, einen Neustart des Telefons zu erzwingen"</string>
<string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Dateisysteme bereitstellen oder Bereitstellung aufheben"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Datenträger bereitzustellen oder die Bereitstellung aufzuheben."</string>
+ <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Ermöglicht der Anwendung, Dateisysteme für austauschbare Datenträger bereitzustellen oder die Bereitstellung aufzuheben"</string>
<string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"Externen Speicher formatieren"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Ermöglicht der Anwendung, austauschbare Datenträger zu formatieren."</string>
+ <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Ermöglicht der Anwendung, austauschbare Datenträger zu formatieren"</string>
<string name="permlab_asec_access" msgid="3411338632002193846">"Informationen zum internen Speicher abrufen"</string>
<string name="permdesc_asec_access" msgid="8820326551687285439">"Ermöglicht der Anwendung, Informationen zum internen Speicher abzurufen."</string>
<string name="permlab_asec_create" msgid="6414757234789336327">"Internen Speicher erstellen"</string>
@@ -332,13 +332,13 @@
<string name="permlab_asec_rename" msgid="7496633954080472417">"Internen Speicher umbenennen"</string>
<string name="permdesc_asec_rename" msgid="2152829985238876790">"Ermöglicht der Anwendung, den internen Speicher umzubenennen."</string>
<string name="permlab_vibrate" msgid="7768356019980849603">"Vibrationsalarm steuern"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern."</string>
+ <string name="permdesc_vibrate" msgid="2886677177257789187">"Ermöglicht der Anwendung, den Vibrationsalarm zu steuern"</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"Lichtanzeige steuern"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"auf USB-Geräte zugreifen"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Ermöglicht der Anwendung den Zugriff auf USB-Geräte."</string>
+ <string name="permdesc_flashlight" msgid="6433045942283802309">"Ermöglicht der Anwendung, die Lichtanzeige zu steuern"</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"Einstellungen und Berechtigungen für USB-Geräte verwalten"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Ermöglicht der Anwendung das Verwalten von Einstellungen und Berechtigungen für USB-Geräte"</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"Hardware testen"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern."</string>
+ <string name="permdesc_hardware_test" msgid="3668894686500081699">"Ermöglicht einer Anwendung, verschiedene Peripherie-Geräte zu Hardware-Testzwecken zu steuern"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"Telefonnummern direkt anrufen"</string>
<string name="permdesc_callPhone" msgid="3369867353692722456">"Ermöglicht dem Anwendungen, Rufnummern ohne Ihr Eingreifen zu wählen. Schädliche Anwendungen können für unerwartete Anrufe auf Ihrer Telefonrechnung verantwortlich sein. Das Wählen von Notrufnummern ist allerdings nicht möglich."</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"Alle Telefonnummern direkt anrufen"</string>
@@ -356,79 +356,83 @@
<string name="permlab_readPhoneState" msgid="2326172951448691631">"Telefonstatus lesen und identifizieren"</string>
<string name="permdesc_readPhoneState" msgid="188877305147626781">"Ermöglicht der Anwendung, auf die Telefonfunktionen des Gerätes zuzugreifen. Eine Anwendung mit dieser Berechtigung kann unter anderem bestimmen, welche Telefonnummer dieses Telefon verwendet, ob ein Anruf aktiv ist oder mit welcher Nummer der Anrufer verbunden ist."</string>
<string name="permlab_wakeLock" msgid="573480187941496130">"Standby-Modus deaktivieren"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren."</string>
+ <string name="permdesc_wakeLock" msgid="7584036471227467099">"Ermöglicht einer Anwendung, den Standby-Modus des Telefons zu deaktivieren"</string>
<string name="permlab_devicePower" msgid="4928622470980943206">"Gerät ein- oder ausschalten"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten."</string>
+ <string name="permdesc_devicePower" msgid="4577331933252444818">"Ermöglicht der Anwendung, das Telefon ein- oder auszuschalten"</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"In Werkstestmodus ausführen"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Telefonhardware zugegriffen werden kann. Nur verfügbar, wenn ein Telefon im Werkstestmodus ausgeführt wird."</string>
+ <string name="permdesc_factoryTest" msgid="8136644990319244802">"Führt einen systemnahen Herstellertest durch, in dessen Rahmen auf die gesamte Telefon-Hardware zugegriffen werden kann. Nur verfügbar, wenn ein Telefon im Herstellertestmodus ausgeführt wird."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"Hintergrund festlegen"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Ermöglicht der Anwendung, den System-Hintergrund festzulegen."</string>
+ <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Ermöglicht der Anwendung, den System-Hintergrund festzulegen"</string>
<string name="permlab_setWallpaperHints" msgid="3600721069353106851">"Größenhinweise für Hintergrund festlegen"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Ermöglicht der Anwendung, die Größenhinweise für den Hintergrund festzulegen."</string>
+ <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Ermöglicht der Anwendung, die Größenhinweise für den Hintergrund festzulegen"</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"System auf Werkseinstellung zurücksetzen"</string>
<string name="permdesc_masterClear" msgid="5033465107545174514">"Ermöglicht einer Anwendung, das System komplett auf Werkseinstellung zurückzusetzen. Hierbei werden alle Daten, Konfigurationen und installierten Anwendungen gelöscht."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"Zeit einstellen"</string>
- <string name="permdesc_setTime" msgid="667294309287080045">"Ermöglicht einer Anwendung, die Uhrzeit des Telefons zu ändern."</string>
+ <string name="permdesc_setTime" msgid="667294309287080045">"Ermöglicht einer Anwendung, die Uhrzeit des Telefons zu ändern"</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"Zeitzone festlegen"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern."</string>
+ <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Ermöglicht einer Anwendung, die Zeitzone des Telefons zu ändern"</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"Als Konto-Manager fungieren"</string>
- <string name="permdesc_accountManagerService" msgid="6056903274106394752">"Ermöglicht einer Anwendung, Anrufe an Konto-Authentifizierer zu tätigen."</string>
+ <string name="permdesc_accountManagerService" msgid="6056903274106394752">"Ermöglicht einer Anwendung, Anrufe an Konto-Authentifizierer zu tätigen"</string>
<string name="permlab_getAccounts" msgid="4549918644233460103">"bekannte Konten suchen"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen."</string>
+ <string name="permdesc_getAccounts" msgid="6839262446413155394">"Ermöglicht einer Anwendung, eine Liste der dem Telefon bekannten Konten abzurufen"</string>
<string name="permlab_authenticateAccounts" msgid="3940505577982882450">"Als Kontoauthentifizierer fungieren"</string>
- <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Ermöglicht einer Anwendung, die Kontoauthentifizierungsfunktionen des Konto-Managers zu verwenden, einschließlich die Funktionen zum Erstellen von Konten und zum Abrufen und Einstellen der entsprechenden Passwörter."</string>
+ <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Ermöglicht einer Anwendung, die Kontoauthentifizierungsfunktionen des Konto-Managers zu verwenden, einschließlich die Funktionen zum Erstellen von Konten und zum Abrufen und Einstellen der entsprechenden Passwörter"</string>
<string name="permlab_manageAccounts" msgid="4440380488312204365">"Kontoliste verwalten"</string>
- <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Ermöglicht einer Anwendung, Konten hinzuzufügen und zu entfernen oder deren Passwörter zu löschen."</string>
+ <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Ermöglicht einer Anwendung, Konten hinzuzufügen und zu entfernen oder deren Passwörter zu löschen"</string>
<string name="permlab_useCredentials" msgid="6401886092818819856">"Authentifizierungsinformationen eines Kontos verwenden"</string>
- <string name="permdesc_useCredentials" msgid="7416570544619546974">"Ermöglicht einer Anwendung, Authentifizierungs-Token anzufordern."</string>
+ <string name="permdesc_useCredentials" msgid="7416570544619546974">"Ermöglicht einer Anwendung, Authentifizierungs-Token anzufordern"</string>
<string name="permlab_accessNetworkState" msgid="6865575199464405769">"Netzwerkstatus anzeigen"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen."</string>
+ <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Ermöglicht einer Anwendung, den Status aller Netzwerke anzuzeigen"</string>
<string name="permlab_createNetworkSockets" msgid="9121633680349549585">"uneingeschränkter Internetzugriff"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten."</string>
+ <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Ermöglicht einer Anwendung, Netzwerk-Sockets einzurichten"</string>
<string name="permlab_writeApnSettings" msgid="7823599210086622545">"Einstellungen für Zugriffspunktname schreiben"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern."</string>
+ <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Ermöglicht einer Anwendung, die APN-Einstellungen wie Proxy und Port eines Zugriffspunkts zu ändern"</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"Netzwerkkonnektivität ändern"</string>
- <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern."</string>
+ <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Ermöglicht einer Anwendung, den Status der Netzwerkkonnektivität zu ändern"</string>
<string name="permlab_changeTetherState" msgid="2702121155761140799">"Tethering-Konnektivität ändern"</string>
- <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Ermöglicht einer Anwendung, den Status der Tethering-Konnektivität zu ändern."</string>
+ <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Ermöglicht einer Anwendung, den Status der Tethering-Konnektivität zu ändern"</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"Einstellung zur Verwendung von Hintergrunddaten ändern"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern."</string>
+ <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Ermöglicht einer Anwendung, die Einstellung der Verwendung von Hintergrunddaten zu ändern"</string>
<string name="permlab_accessWifiState" msgid="8100926650211034400">"WLAN-Status anzeigen"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen."</string>
+ <string name="permdesc_accessWifiState" msgid="485796529139236346">"Ermöglicht einer Anwendung, die Informationen zum WLAN-Status einzusehen"</string>
<string name="permlab_changeWifiState" msgid="7280632711057112137">"WLAN-Status ändern"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen."</string>
+ <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Ermöglicht einer Anwendung, eine Verbindung zu den WLAN-Zugangspunkten herzustellen und diese zu trennen oder Änderungen an den konfigurierten WLAN-Netzwerken vorzunehmen"</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"WLAN-Multicast-Empfang zulassen"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Ermöglicht einer Anwendung, Datenpakete zu empfangen, die nicht direkt an Ihr Gerät gerichtet sind. Dies kann bei der Erkennung von in der Nähe angebotenen Diensten hilfreich sein. Diese Einstellung verbraucht mehr Energie als der Nicht-Multicast-Modus."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"WiMAX-Status anzeigen"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Ermöglicht einer Anwendung, die Informationen zum WiMAX-Status einzusehen"</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"WiMAX-Status ändern"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Ermöglicht einer Anwendung, eine Verbindung mit dem WiMAX-Netzwerk herzustellen bzw. zu trennen"</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth-Verwaltung"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen."</string>
+ <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Ermöglicht einer Anwendung, das lokale Bluetooth-Telefon zu konfigurieren, Remote-Geräte zu erkennen und eine Verbindung zu diesen herzustellen"</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth-Verbindungen herstellen"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren."</string>
+ <string name="permdesc_bluetooth" msgid="762515380679392945">"Ermöglicht einer Anwendung, die Konfiguration des lokalen Bluetooth-Telefons einzusehen und Verbindungen mit Partnergeräten herzustellen und zu akzeptieren"</string>
<string name="permlab_nfc" msgid="4423351274757876953">"Nahfeldkommunikation steuern"</string>
- <string name="permdesc_nfc" msgid="9171401851954407226">"Ermöglicht einer Anwendung die Kommunikation mit Tags für die Nahfeldkommunikation, Karten und Readern."</string>
+ <string name="permdesc_nfc" msgid="9171401851954407226">"Ermöglicht einer Anwendung die Kommunikation mit Tags für Nahfeldkommunikation, Karten und Lesegeräte"</string>
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"Tastensperre deaktivieren"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Ermöglicht einer Anwendung, die Tastensperre sowie den damit verbundenen Passwortschutz zu deaktivieren. So wird die Tastensperre vom Telefon deaktiviert, wenn ein Anruf eingeht, und nach Beendigung des Anrufs wieder aktiviert."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"Synchronisierungseinstellungen lesen"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+ <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu lesen, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht"</string>
<string name="permlab_writeSyncSettings" msgid="6297138566442486462">"Synchronisierungseinstellungen schreiben"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht."</string>
+ <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Ermöglicht einer Anwendung, die Synchronisierungseinstellungen zu ändern, etwa ob die Synchronisierung für Kontakte aktiviert ist oder nicht"</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"Synchronisierungsstatistiken lesen"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen."</string>
+ <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Ermöglicht einer Anwendung, die Synchronisierungsstatistiken zu lesen, etwa den Verlauf der bereits durchgeführten Synchronisierungen"</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"abonnierte Feeds lesen"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Ermöglicht einer Anwendung, Details zu den zurzeit synchronisierten Feeds abzurufen"</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"abonnierte Feeds schreiben"</string>
<string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Ermöglicht einer Anwendung, Änderungen an den kürzlich synchronisierten Feeds vorzunehmen. Schädliche Anwendungen könnten so Ihre synchronisierten Feeds ändern."</string>
<string name="permlab_readDictionary" msgid="432535716804748781">"nutzerdefiniertes Wörterbuch lesen"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Ermöglicht einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat."</string>
+ <string name="permdesc_readDictionary" msgid="1082972603576360690">"Ermöglicht einer Anwendung, alle privaten Wörter, Namen und Ausdrücke zu lesen, die ein Nutzer in seinem Wörterbuch gespeichert hat"</string>
<string name="permlab_writeDictionary" msgid="6703109511836343341">"in nutzerdefiniertes Wörterbuch schreiben"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Ermöglicht einer Anwendung, Ihrem Wörterbuch neue Einträge hinzuzufügen."</string>
- <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"USB-Speicherinh. ändern/lösch."</string>
+ <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Ermöglicht einer Anwendung, Ihrem Wörterbuch neue Einträge hinzuzufügen"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"USB-Speicherinhalt ändern/löschen"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"SD-Karten-Inhalt ändern/löschen"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Ermöglicht der Anwendung Schreiben in USB-Speicher"</string>
<string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Ermöglicht einer Anwendung, auf die SD-Karte zu schreiben"</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"Zugriff auf das Cache-Dateisystem"</string>
<string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Gewährt einer Anwendung Lese- und Schreibzugriff auf das Cache-Dateisystem."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"Internetanrufe tätigen/annehmen"</string>
- <string name="permdesc_use_sip" msgid="6320376185606661843">"Ermöglicht einer Anwendung die Verwendung des SIP-Dienstes zum Tätigen/Annehmen von Internetanrufen."</string>
+ <string name="permdesc_use_sip" msgid="6320376185606661843">"Ermöglicht einer Anwendung die Verwendung des SIP-Dienstes zum Tätigen/Annehmen von Internetanrufen"</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Passwortregeln festlegen"</string>
<string name="policydesc_limitPassword" msgid="9083400080861728056">"Zulässige Länge und Zeichen für Passwörter zum Entsperren des Displays festlegen"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Versuche zum Entsperren des Displays überwachen"</string>
@@ -436,7 +440,7 @@
<string name="policylab_resetPassword" msgid="2620077191242688955">"Passwort zum Entsperren des Displays ändern"</string>
<string name="policydesc_resetPassword" msgid="5391240616981297361">"Passwort zum Entsperren des Displays ändern"</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Display sperren"</string>
- <string name="policydesc_forceLock" msgid="5696964126226028442">"Steuern Sie, wie und wann das Display gesperrt wird."</string>
+ <string name="policydesc_forceLock" msgid="5696964126226028442">"Festlegen, wie und wann das Display gesperrt wird"</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Alle Daten löschen"</string>
<string name="policydesc_wipeData" msgid="7669895333814222586">"Auf Werkseinstellungen zurücksetzen und Daten auf dem Telefon ohne Warnung löschen"</string>
<string-array name="phoneTypes">
@@ -446,19 +450,19 @@
<item msgid="1103601433382158155">"Fax (geschäftl.)"</item>
<item msgid="1735177144948329370">"Fax (privat)"</item>
<item msgid="603878674477207394">"Pager"</item>
- <item msgid="1650824275177931637">"Sonstige"</item>
+ <item msgid="1650824275177931637">"Andere"</item>
<item msgid="9192514806975898961">"Benutzerdefiniert"</item>
</string-array>
<string-array name="emailAddressTypes">
<item msgid="8073994352956129127">"Privat"</item>
<item msgid="7084237356602625604">"Geschäftlich"</item>
- <item msgid="1112044410659011023">"Sonstige"</item>
+ <item msgid="1112044410659011023">"Andere"</item>
<item msgid="2374913952870110618">"Benutzerdefiniert"</item>
</string-array>
<string-array name="postalAddressTypes">
<item msgid="6880257626740047286">"Privat"</item>
<item msgid="5629153956045109251">"Geschäftlich"</item>
- <item msgid="4966604264500343469">"Sonstige"</item>
+ <item msgid="4966604264500343469">"Andere"</item>
<item msgid="4932682847595299369">"Benutzerdefiniert"</item>
</string-array>
<string-array name="imAddressTypes">
@@ -469,7 +473,7 @@
</string-array>
<string-array name="organizationTypes">
<item msgid="7546335612189115615">"Geschäftlich"</item>
- <item msgid="4378074129049520373">"Sonstige"</item>
+ <item msgid="4378074129049520373">"Andere"</item>
<item msgid="3455047468583965104">"Benutzerdefiniert"</item>
</string-array>
<string-array name="imProtocols">
@@ -544,7 +548,7 @@
<string name="keyguard_label_text" msgid="861796461028298424">"Drücken Sie zum Entsperren die Menütaste und dann auf \"0\"."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Notrufnummer"</string>
<string name="lockscreen_carrier_default" msgid="8812714795156374435">"(kein Dienst)"</string>
- <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Display gesperrt."</string>
+ <string name="lockscreen_screen_locked" msgid="7288443074806832904">"Display gesperrt"</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Drücken Sie die Menütaste, um das Telefon zu entsperren oder einen Notruf zu tätigen."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Zum Entsperren die Menütaste drücken"</string>
<string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Muster zum Entsperren zeichnen"</string>
@@ -561,7 +565,7 @@
<string name="lockscreen_missing_sim_instructions" msgid="8874620818937719067">"Bitte legen Sie eine SIM-Karte ein."</string>
<string name="emergency_calls_only" msgid="6733978304386365407">"Nur Notrufe"</string>
<string name="lockscreen_network_locked_message" msgid="143389224986028501">"Netzwerk gesperrt"</string>
- <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"SIM-Karte ist gesperrt. PUK-Eingabe erforderlich."</string>
+ <string name="lockscreen_sim_puk_locked_message" msgid="7441797339976230">"PUK-Sperre auf SIM"</string>
<string name="lockscreen_sim_puk_locked_instructions" msgid="635967534992394321">"Weitere Informationen finden Sie in der Bedienungsanleitung oder wenden Sie sich an den Kundendienst."</string>
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"Bitte PIN-Code eingeben"</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"SIM-Karte wird entsperrt..."</string>
@@ -588,14 +592,14 @@
<string name="factorytest_failed" msgid="5410270329114212041">"Werkstest fehlgeschlagen"</string>
<string name="factorytest_not_system" msgid="4435201656767276723">"Die Aktion FACTORY_TEST wird nur für unter \"/system/app\" gespeicherte Pakete unterstützt."</string>
<string name="factorytest_no_action" msgid="872991874799998561">"Es wurden kein Paket mit der Aktion FACTORY_TEST gefunden."</string>
- <string name="factorytest_reboot" msgid="6320168203050791643">"Neu booten"</string>
+ <string name="factorytest_reboot" msgid="6320168203050791643">"Neustart"</string>
<string name="js_dialog_title" msgid="8143918455087008109">"Die Seite auf \'<xliff:g id="TITLE">%s</xliff:g>\' sagt:"</string>
<string name="js_dialog_title_default" msgid="6961903213729667573">"JavaScript"</string>
<string name="js_dialog_before_unload" msgid="1901675448179653089">"Von dieser Seite navigieren?"\n\n"<xliff:g id="MESSAGE">%s</xliff:g>"\n\n"Wählen Sie \"OK\", um fortzufahren, oder wählen Sie \"Abbrechen\", um auf der aktuellen Seite zu bleiben."</string>
<string name="save_password_label" msgid="6860261758665825069">"Bestätigen"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Tipp: Zum Heranzoomen und Vergrößern zweimal tippen"</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"Browserverlauf und Lesezeichen lesen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ermöglicht der Anwendung, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Ermöglicht der Anwendung, alle URLs, die mit dem Browser besucht wurden, sowie alle Lesezeichen des Browsers zu lesen"</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"Browserverlauf und Lesezeichen schreiben"</string>
<string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Ermöglicht einer Anwendung, den auf Ihrem Telefon gespeicherten Browserverlauf und die Lesezeichen zu ändern. Schädliche Anwendungen können so Ihre Browserdaten löschen oder ändern."</string>
<string name="permlab_setAlarm" msgid="5924401328803615165">"Alarm im Wecker festlegen"</string>
@@ -605,7 +609,7 @@
<string name="save_password_message" msgid="767344687139195790">"Möchten Sie, dass der Browser dieses Passwort speichert?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Nicht jetzt"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Speichern"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Niemals"</string>
+ <string name="save_password_never" msgid="8274330296785855105">"Nie"</string>
<string name="open_permission_deny" msgid="5661861460947222274">"Sie sind zum Öffnen dieser Seite nicht berechtigt."</string>
<string name="text_copied" msgid="4985729524670131385">"Text in Zwischenablage kopiert."</string>
<string name="more_item_label" msgid="4650918923083320495">"Mehr"</string>
@@ -613,7 +617,7 @@
<string name="menu_space_shortcut_label" msgid="2410328639272162537">"Leerzeichen"</string>
<string name="menu_enter_shortcut_label" msgid="2743362785111309668">"Enter"</string>
<string name="menu_delete_shortcut_label" msgid="3658178007202748164">"löschen"</string>
- <string name="search_go" msgid="8298016669822141719">"Suche"</string>
+ <string name="search_go" msgid="8298016669822141719">"Suchen"</string>
<string name="oneMonthDurationPast" msgid="7396384508953779925">"Vor 1 Monat"</string>
<string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Vor mehr als 1 Monat"</string>
<plurals name="num_seconds_ago">
@@ -721,18 +725,19 @@
<string name="addToDictionary" msgid="8793624991686948709">"\"<xliff:g id="WORD">%s</xliff:g>\" zum Wörterbuch hinzufügen"</string>
<string name="editTextMenuTitle" msgid="1672989176958581452">"Text bearbeiten"</string>
<string name="low_internal_storage_view_title" msgid="1399732408701697546">"Geringer Speicher"</string>
- <string name="low_internal_storage_view_text" msgid="635106544616378836">"Kaum noch Telefonspeicher frei."</string>
+ <string name="low_internal_storage_view_text" msgid="635106544616378836">"Kaum noch Telefonspeicher frei"</string>
<string name="ok" msgid="5970060430562524910">"OK"</string>
<string name="cancel" msgid="6442560571259935130">"Abbrechen"</string>
<string name="yes" msgid="5362982303337969312">"OK"</string>
<string name="no" msgid="5141531044935541497">"Abbrechen"</string>
<string name="dialog_alert_title" msgid="2049658708609043103">"Achtung"</string>
<string name="capital_on" msgid="1544682755514494298">"EIN"</string>
- <string name="capital_off" msgid="6815870386972805832">"Aus"</string>
+ <string name="capital_off" msgid="6815870386972805832">"AUS"</string>
<string name="whichApplication" msgid="4533185947064773386">"Aktion durchführen mit"</string>
- <string name="alwaysUse" msgid="4583018368000610438">"Standardmäßig für diese Aktion verwenden."</string>
- <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Standardeinstellung zurücksetzen unter \"Einstellungen &gt; Anwendungen &gt; Anwendungen verwalten\"."</string>
+ <string name="alwaysUse" msgid="4583018368000610438">"Standardmäßig für diese Aktion verwenden"</string>
+ <string name="clearDefaultHintMsg" msgid="4815455344600932173">"Standardeinstellung zurücksetzen unter \"Einstellungen &gt; Anwendungen &gt; Anwendungen verwalten\""</string>
<string name="chooseActivity" msgid="1009246475582238425">"Aktion auswählen"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Anwendung für das USB-Gerät auswählen"</string>
<string name="noApplications" msgid="1691104391758345586">"Diese Aktion kann von keiner Anwendung ausgeführt werden."</string>
<string name="aerr_title" msgid="653922989522758100">"Tut uns leid!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) wurde unerwartet beendet. Versuchen Sie es erneut."</string>
@@ -751,13 +756,13 @@
<string name="smv_application" msgid="295583804361236288">"Die Anwendung <xliff:g id="APPLICATION">%1$s</xliff:g> (Prozess <xliff:g id="PROCESS">%2$s</xliff:g>) hat gegen ihre selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
<string name="smv_process" msgid="5120397012047462446">"Der Prozess <xliff:g id="PROCESS">%1$s</xliff:g> hat gegen seine selbsterzwungene StrictMode-Richtlinie verstoßen."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> läuft"</string>
- <string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Auswählen zum Wechseln in die Anwendung"</string>
+ <string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Zum Wechseln in die Anwendung auswählen"</string>
<string name="heavy_weight_switcher_title" msgid="1135403633766694316">"Anwendung wechseln?"</string>
<string name="heavy_weight_switcher_text" msgid="4592075610079319667">"Es läuft gerade eine andere Anwendung, die vor dem Start einer neuen beendet werden muss."</string>
<string name="old_app_action" msgid="493129172238566282">"Zu <xliff:g id="OLD_APP">%1$s</xliff:g> zurückkehren"</string>
- <string name="old_app_description" msgid="942967900237208466">"Die neue Anwendung nicht starten."</string>
+ <string name="old_app_description" msgid="942967900237208466">"Die neue Anwendung nicht starten"</string>
<string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string>
- <string name="new_app_description" msgid="6830398339826789493">"Anwendung beenden, ohne zu speichern."</string>
+ <string name="new_app_description" msgid="6830398339826789493">"Anwendung beenden, ohne zu speichern"</string>
<string name="sendText" msgid="5132506121645618310">"Aktion für Text auswählen"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"Klingeltonlautstärke"</string>
<string name="volume_music" msgid="5421651157138628171">"Medienlautstärke"</string>
@@ -802,14 +807,14 @@
<string name="usb_storage_notification_title" msgid="8175892554757216525">"USB-Verbindung"</string>
<string name="usb_storage_notification_message" msgid="7380082404288219341">"Zum Kopieren von Dateien zum/vom Computer"</string>
<string name="usb_storage_stop_notification_title" msgid="2336058396663516017">"USB-Speicher deaktivieren"</string>
- <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"Auswählen, um USB-Speicher zu deaktivieren."</string>
+ <string name="usb_storage_stop_notification_message" msgid="2591813490269841539">"USB-Speicher deaktivieren: auswählen"</string>
<string name="usb_storage_stop_title" msgid="660129851708775853">"USB-Speicher in Verwendung"</string>
<string name="usb_storage_stop_message" product="nosdcard" msgid="1368842269463745067">"Stellen Sie vor dem Deaktivieren des USB-Speichers sicher, dass Sie den Android-USB-Speicher von Ihrem Computer getrennt (\"ausgeworfen\") haben."</string>
- <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Stellen Sie vor dem Deaktivieren des USB-Speichers sicher, dass Sie Ihre Android-SD-Karte von Ihrem Computer getrennt (\"ausgeworfen\") haben."</string>
+ <string name="usb_storage_stop_message" product="default" msgid="3613713396426604104">"Achten Sie vor dem Deaktivieren des USB-Speichers darauf, dass Sie die Android-SD-Karte von Ihrem Computer getrennt (\"ausgeworfen\") haben."</string>
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"USB-Speicher deaktivieren"</string>
<string name="usb_storage_stop_error_message" msgid="143881914840412108">"Beim Deaktivieren des USB-Speichers ist ein Problem aufgetreten. Überprüfen Sie, ob Sie den USB-Host getrennt haben, und versuchen Sie es erneut."</string>
<string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"USB-Speicher aktivieren"</string>
- <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Wenn Sie den USB-Speicher aktivieren, werden einige von Ihnen verwendeten Anwendungen angehalten und sind möglicherweise nicht verfügbar, bis Sie den USB-Speicher wieder deaktivieren."</string>
+ <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Wenn Sie den USB-Speicher aktivieren, werden einige von Ihnen verwendete Anwendungen angehalten und sind möglicherweise nicht verfügbar, bis Sie den USB-Speicher wieder deaktivieren."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB-Vorgang fehlgeschlagen"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB-Sp. formatieren"</string>
@@ -818,39 +823,39 @@
<string name="extmedia_format_message" product="default" msgid="3621369962433523619">"Möchten Sie die SD-Karte wirklich formatieren? Alle Daten auf Ihrer Karte gehen dann verloren."</string>
<string name="extmedia_format_button_format" msgid="4131064560127478695">"Format"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"USB-Debugging verbunden"</string>
- <string name="adb_active_notification_message" msgid="8470296818270110396">"Auswählen, um USB-Debugging zu deaktivieren."</string>
+ <string name="adb_active_notification_message" msgid="8470296818270110396">"USB-Debugging deaktivieren: auswählen"</string>
<string name="select_input_method" msgid="6865512749462072765">"Eingabemethode auswählen"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"Kandidaten"</u></string>
<string name="ext_media_checking_notification_title" product="nosdcard" msgid="3449816005351468560">"USB-Speicher wird vorbereitet."</string>
- <string name="ext_media_checking_notification_title" product="default" msgid="5457603418970994050">"SD-Karte wird vorbereitet"</string>
+ <string name="ext_media_checking_notification_title" product="default" msgid="5457603418970994050">"SD-Karte wird vorbereitet..."</string>
<string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Suche nach Fehlern"</string>
<string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"USB-Speicher leer"</string>
<string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"SD-Karte leer"</string>
<string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"USB-Speicher ist leer oder verfügt über ein nicht unterstütztes Dateisystem."</string>
<string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"SD-Karte ist leer oder verfügt über ein nicht unterstütztes Dateisystem."</string>
<string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"USB-Speicher beschädigt"</string>
- <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Beschädigte SD-Karte"</string>
- <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB-Speicher ist beschädigt. Sie müssen ihn neu formatieren."</string>
- <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"Die SD-Karte ist beschädigt. Sie müssen Ihre Karte eventuell neu formatieren."</string>
- <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-Speicher unerw. entfernt"</string>
+ <string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"SD-Karte beschädigt"</string>
+ <string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"Der USB-Speicher ist beschädigt. Sie müssen ihn eventuell neu formatieren."</string>
+ <string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"Die SD-Karte ist beschädigt. Sie müssen sie eventuell neu formatieren."</string>
+ <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-Speicher unerwartet entfernt"</string>
<string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"SD-Karte unerwartet entfernt"</string>
<string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Trennen Sie den USB-Speicher vor dem Entfernen, um Datenverlust zu vermeiden."</string>
<string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"SD-Karte vor dem Entnehmen trennen, um Datenverlust zu vermeiden."</string>
- <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB-Speicher kann entf. werden"</string>
+ <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB-Speicher kann entfernt werden."</string>
<string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"SD-Karte kann entfernt werden."</string>
<string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"Der USB-Speicher kann entfernt werden."</string>
<string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"Die SD-Karte kann entfernt werden."</string>
<string name="ext_media_nomedia_notification_title" product="nosdcard" msgid="4486377230140227651">"USB-Speicher entfernt"</string>
<string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"SD-Karte entfernt"</string>
<string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"USB-Speicher entfernt. Neuen Datenträger einlegen"</string>
- <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"SD-Karte entfernt. Legen Sie eine neue ein."</string>
+ <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"SD-Karte entfernt. Neue Karte einlegen"</string>
<string name="activity_list_empty" msgid="4168820609403385789">"Keine passenden Aktivitäten gefunden"</string>
<string name="permlab_pkgUsageStats" msgid="8787352074326748892">"Nutzungsstatistik der Komponente aktualisieren"</string>
<string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Ermöglicht die Änderung von gesammelten Nutzungsstatistiken der Komponente. Nicht für normale Anwendungen vorgesehen."</string>
- <string name="permlab_copyProtectedData" msgid="1660908117394854464">"Ermöglicht das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalt. Keine Verwendung bei normalen Anwendungen."</string>
- <string name="permdesc_copyProtectedData" msgid="537780957633976401">"Ermöglicht das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalt. Keine Verwendung bei normalen Anwendungen."</string>
+ <string name="permlab_copyProtectedData" msgid="1660908117394854464">"Ermöglicht das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalt. Nicht zum Gebrauch mit normalen Anwendungen."</string>
+ <string name="permdesc_copyProtectedData" msgid="537780957633976401">"Ermöglicht das Aufrufen des Standard-Containerdienstes zum Kopieren von Inhalt. Nicht zum Gebrauch mit normalen Anwendungen."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Für Zoomeinstellung zweimal berühren"</string>
<string name="gadget_host_error_inflating" msgid="2613287218853846830">"Fehler beim Vergrößern des Widgets"</string>
<string name="ime_action_go" msgid="8320845651737369027">"Los"</string>
@@ -878,7 +883,7 @@
<string name="pptp_vpn_description" msgid="2688045385181439401">"Point-to-Point-Tunneling-Protokoll"</string>
<string name="l2tp_vpn_description" msgid="3750692169378923304">"Layer-2-Tunneling-Protokoll"</string>
<string name="l2tp_ipsec_psk_vpn_description" msgid="3945043564008303239">"L2TP/IPSec-VPN mit vorinstalliertem Schlüssel"</string>
- <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"Zertifikat mit vorinstalliertem Schlüssel"</string>
+ <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"L2TP/IPSec-VPN mit Zertifikat"</string>
<string name="upload_file" msgid="2897957172366730416">"Datei auswählen"</string>
<string name="reset" msgid="2448168080964209908">"Zurücksetzen"</string>
<string name="submit" msgid="1602335572089911941">"Senden"</string>
@@ -888,9 +893,9 @@
<string name="tethered_notification_title" msgid="3146694234398202601">"Tethering oder Hotspot aktiv"</string>
<string name="tethered_notification_message" msgid="3067108323903048927">"Zum Konfigurieren berühren"</string>
<string name="throttle_warning_notification_title" msgid="4890894267454867276">"Hohe Mobildatennutzung"</string>
- <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Weitere Informationen über die Mobildatennutzung durch Berühren aufrufen"</string>
+ <string name="throttle_warning_notification_message" msgid="2609734763845705708">"Durch Berühren weitere Informationen zur Mobildatennutzung aufrufen"</string>
<string name="throttled_notification_title" msgid="6269541897729781332">"Mobildatenlimit überschritten"</string>
- <string name="throttled_notification_message" msgid="4712369856601275146">"Weitere Informationen über die Mobildatennutzung durch Berühren aufrufen"</string>
+ <string name="throttled_notification_message" msgid="4712369856601275146">"Durch Berühren weitere Informationen zur Mobildatennutzung aufrufen"</string>
<string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"USB-Speicher wird getrennt..."</string>
<string name="progress_unmounting" product="default" msgid="5556813978958789471">"SD-Karte wird getrennt..."</string>
<string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"USB-Speicher wird gelöscht..."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 4244aa5..b4f6a76 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Επιτρέπει στην εφαρμογή τον έλεγχο του δονητή."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"έλεγχος φακού"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Επιτρέπει στην εφαρμογή τον έλεγχο του φακού."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"πρόσβαση σε συσκευές USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Επιτρέπει στην εφαρμογή την πρόσβαση σε συσκευές USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"διαχείριση προτιμήσεων και αδειών για συσκευές USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Επιτρέπει στην εφαρμογή να διαχειρίζεται προτιμήσεις και άδειες για συσκευές USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"δοκιμή υλικού"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Επιτρέπει σε μια εφαρμογή τον έλεγχο διαφόρων περιφερειακών για την εκτέλεση δοκιμών υλικού."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Επιτρέπει σε μια εφαρμογή τη σύνδεση σε σημεία πρόσβασης Wi-Fi και την αποσύνδεση από αυτά, καθώς και την πραγματοποίηση αλλαγών σε διαμορφωμένα δίκτυα Wi-Fi."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"να επιτρέπεται η λήψη πολλαπλής διανομής Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Επιτρέπει στην εφαρμογή να λαμβάνει πακέτα τα οποία δεν αποστέλλονται απευθείας στη συσκευή σας. Αυτό μπορεί να φανεί χρήσιμο κατά την ανακάλυψη υπηρεσιών που προσφέρονται σε κοντινές τοποθεσίες. Χρησιμοποιεί περισσότερη ενέργεια σε σχέση με την κατάσταση μη πολλαπλής διανομής."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"προβολή κατάστασης WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Επιτρέπει σε μια εφαρμογή την προβολή των πληροφοριών σχετικά με την κατάσταση του WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"αλλαγή κατάστασης WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Επιτρέπει σε μια εφαρμογή τη σύνδεση και αποσύνδεση από το δίκτυο WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"διαχείριση Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Επιτρέπει σε μια εφαρμογή τη διαμόρφωση του τοπικού τηλεφώνου Bluetooth και την ανακάλυψη και σύζευξη με απομακρυσμένες συσκευές."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"δημιουργία συνδέσεων Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Χρήση από προεπιλογή για αυτήν την ενέργεια."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Εκκαθάριση προεπιλεγμένων σε Ρυθμίσεις αρχικής σελίδας &gt; Εφαρμογές &gt; Διαχείριση εφαρμογών."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Επιλέξτε μια ενέργεια"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Επιλέξτε μια εφαρμογή για τη συσκευή USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Δεν υπάρχουν εφαρμογές, οι οποίες μπορούν να εκτελέσουν αυτήν την ενέργεια."</string>
<string name="aerr_title" msgid="653922989522758100">"Λυπούμαστε!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Υπήρξε μη αναμενόμενη διακοπή της εφαρμογής <xliff:g id="APPLICATION">%1$s</xliff:g> (διαδικασία <xliff:g id="PROCESS">%2$s</xliff:g>). Προσπαθήστε ξανά."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 5cc7a63..4175bb0 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Allows the application to control the vibrator."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Allows the application to control the flashlight."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"access USB devices"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Allows the application to access USB devices."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"manage preferences and permissions for USB devices"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Allows the application to manage preferences and permissions for USB devices."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"test hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Allows the application to control various peripherals for the purpose of hardware testing."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Allows an application to connect to and disconnect from Wi-Fi access points and to make changes to configured Wi-Fi networks."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"allow Wi-Fi Multicast reception"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Allows an application to receive packets not directly addressed to your device. This can be useful when discovering services offered nearby. It uses more power than the non-multicast mode."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"view WiMAX state"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Allows an application to view the information about the state of WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"change WiMAX state"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Allows an application to connect to and disconnect from WiMAX network."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth administration"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Allows an application to configure the local Bluetooth phone and to discover and pair with remote devices."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"create Bluetooth connections"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Use by default for this action."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Clear default in Home Settings &gt; Applications &gt; Manage applications."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Select an action"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Select an application for the USB device"</string>
<string name="noApplications" msgid="1691104391758345586">"No applications can perform this action."</string>
<string name="aerr_title" msgid="653922989522758100">"Sorry!"</string>
<string name="aerr_application" msgid="4683614104336409186">"The application <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) has stopped unexpectedly. Please try again."</string>
@@ -796,7 +801,7 @@
<string name="usb_storage_title" msgid="5901459041398751495">"USB connected"</string>
<string name="usb_storage_message" product="nosdcard" msgid="115779324551502062">"You have connected your phone to your computer via USB. Select the button below if you want to copy files between your computer and your Android‘s USB storage."</string>
<string name="usb_storage_message" product="default" msgid="4796759646167247178">"You have connected your phone to your computer via USB. Select the button below if you want to copy files between your computer and your Android\'s SD card."</string>
- <string name="usb_storage_button_mount" msgid="1052259930369508235">"Turn off USB storage"</string>
+ <string name="usb_storage_button_mount" msgid="1052259930369508235">"Turn on USB storage"</string>
<string name="usb_storage_error_message" product="nosdcard" msgid="3276413764430468454">"There is a problem with using your USB storage for USB mass storage."</string>
<string name="usb_storage_error_message" product="default" msgid="120810397713773275">"There is a problem with using your SD card for USB mass storage."</string>
<string name="usb_storage_notification_title" msgid="8175892554757216525">"USB connected"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 504b828..f0299af 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -202,7 +202,7 @@
<string name="permlab_enableCarMode" msgid="5684504058192921098">"habilitar el modo de auto"</string>
<string name="permdesc_enableCarMode" msgid="5673461159384850628">"Permite que una aplicación habilite el modo auto."</string>
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"eliminar los procesos de fondo"</string>
- <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Permite que una aplicación elimine los procesos de fondo de otras aplicaciones, aun si la memoria no es baja."</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Permite que una aplicación elimine los procesos de fondo de otras aplicaciones, aun si la no queda poco espacio en la memoria."</string>
<string name="permlab_forceStopPackages" msgid="1447830113260156236">"forzar la detención de otras aplicaciones"</string>
<string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Permite que una aplicación provoque la detención de otras aplicaciones."</string>
<string name="permlab_forceBack" msgid="1804196839880393631">"provocar que la aplicación se acerque"</string>
@@ -245,7 +245,7 @@
<string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Permite al propietario vincularse a la interfaz de nivel superior de un método de entrada. Se debe evitar utilizarlo en aplicaciones normales."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"vincular a un fondo de pantalla"</string>
<string name="permdesc_bindWallpaper" msgid="5287754520361915347">"Permite al propietario vincularse a la interfaz de nivel superior de un fondo de pantalla. Se debe evitar utilizarlo en aplicaciones normales."</string>
- <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivo"</string>
+ <string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactuar con un administrador de dispositivos"</string>
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permite que el propietario envíe sus intentos a un administrador de dispositivos. No se necesita para las aplicaciones normales."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"cambiar la orientación de la pantalla"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Admite una aplicación que cambia la rotación de la pantalla en cualquier momento. Se debe evitar utilizarlo en aplicaciones normales."</string>
@@ -264,11 +264,11 @@
<string name="permlab_installPackages" msgid="335800214119051089">"instalar aplicaciones directamente"</string>
<string name="permdesc_installPackages" msgid="526669220850066132">"Admite una aplicación que instala paquetes de Android nuevos o actualizados. Las aplicaciones maliciosas pueden utilizarlo para agregar aplicaciones nuevas con permisos arbitrariamente potentes."</string>
<string name="permlab_clearAppCache" msgid="4747698311163766540">"eliminar todos los datos de memoria caché de la aplicación"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Admite una aplicación que libera espacio de almacenamiento en el teléfono al eliminar archivos del directorio de memoria caché de la aplicación. En general, el acceso es muy restringido para el proceso del sistema."</string>
+ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Permite que una aplicación libere espacio de almacenamiento en el teléfono borrando archivos del directorio de memoria caché de la aplicación. En general el acceso está muy restringido al proceso del sistema."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Mover recursos de la aplicación"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Permite a una aplicación mover recursos de aplicación de medios internos a externos y viceversa."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"lee los datos confidenciales del registro"</string>
- <string name="permdesc_readLogs" msgid="8896449437464867766">"Admite una aplicación que lee diversos archivos de registro del sistema. Esto te permite descubrir información general acerca de lo que haces con el teléfono, y puede potencialmente incluir información personal o privada."</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Permite que una aplicación lea los diversos archivos de registro del sistema. Esto le permite descubrir información general acerca de lo que haces con el teléfono, y puede potencialmente incluir información personal o privada."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"leer y escribir a recursos dentro del grupo de diagnóstico"</string>
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Admite una aplicación que lee y escribe a cualquier recurso dentro del grupo de diagnóstico; por ejemplo, archivos con /dev. Esto puede afectar potencialmente la estabilidad y la seguridad del sistema. Debe utilizarlo SÓLO el fabricante o el operador en los diagnósticos específicos del hardware."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"activar o desactivar componentes de la aplicación"</string>
@@ -281,12 +281,12 @@
<string name="permdesc_writeSecureSettings" msgid="5497873143539034724">"Permite a una aplicación modificar los datos de la configuración segura de los sistemas. Las aplicaciones normales no deben utilizarlo."</string>
<string name="permlab_writeGservices" msgid="2149426664226152185">"modificar el mapa de servicios de Google"</string>
<string name="permdesc_writeGservices" msgid="6602362746516676175">"Admite una aplicación que modifica el mapa de servicios de Google. Las aplicaciones normales no deben utilizarlo."</string>
- <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"iniciar automáticamente durante la inicialización"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Admite una aplicación que se inicia cuando el sistema haya finalizado la inicialización. Esto puede ocasionar que se demore más tiempo en inicializar el teléfono y que la aplicación retarde el funcionamiento total del teléfono al estar en ejecución constante."</string>
+ <string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"ejecutar automáticamente al iniciar"</string>
+ <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Permite que una aplicación se inicie en cuanto el sistema haya finalizado la inicialización. Esto puede ocasionar que el teléfono tarde más en inicializarse y que la aplicación demore el funcionamiento total del teléfono al estar en ejecución constante."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"enviar emisiones pegajosas"</string>
<string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Admite una aplicación que envía emisiones pegajosas, las cuales permanecen luego de que finaliza la emisión. Las aplicaciones maliciosas pueden hacer lento e inestable al teléfono, ya que ocasiona que utilice demasiada memoria."</string>
<string name="permlab_readContacts" msgid="6219652189510218240">"leer datos de contacto"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Admite una aplicación que lee todos los datos de (direcciones) de contactos almacenados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para enviar tus eventos de calendario a otras personas."</string>
+ <string name="permdesc_readContacts" msgid="3371591512896545975">"Permite que una aplicación lea todos los datos (direcciones) de contactos almacenados en tu tablet. Las aplicaciones maliciosas pueden utilizarlo para enviar tus datos a otras personas."</string>
<string name="permlab_writeContacts" msgid="644616215860933284">"escribir datos de contacto"</string>
<string name="permdesc_writeContacts" msgid="3924383579108183601">"Admite una aplicación que modifica los datos de (dirección de) contacto guardados en tu teléfono. Las aplicaciones maliciosas pueden utilizarlo para borrar o modificar los datos de contacto."</string>
<string name="permlab_readCalendar" msgid="6898987798303840534">"Leer eventos del calendario"</string>
@@ -315,8 +315,8 @@
<string name="permdesc_camera" msgid="6004878235852154239">"Admite una aplicación que toma fotografías y graba video con la cámara. Esto permite que la aplicación en cualquier momento recopile imágenes que esté viendo la cámara."</string>
<string name="permlab_brick" msgid="8337817093326370537">"desactivar teléfono de manera permanente"</string>
<string name="permdesc_brick" msgid="5569526552607599221">"Admite que la aplicación desactive todo el teléfono de manera permanente. Esto es muy peligroso."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"provocar el reinicio del teléfono"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Admite que la aplicación provoque que el teléfono se reinicie."</string>
+ <string name="permlab_reboot" msgid="2898560872462638242">"forzar reinicio del teléfono"</string>
+ <string name="permdesc_reboot" msgid="7914933292815491782">"Permite que la aplicación fuerce el reinicio del tablet."</string>
<string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"montar y desmontar filesystems"</string>
<string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Admite que la aplicación monte y desmonte filesystems para obtener almacenamiento extraíble."</string>
<string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"espacio de almacenamiento externo del formato"</string>
@@ -335,15 +335,15 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Admite que la aplicación controle el vibrador."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Admite que la aplicación controle la linterna."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"acceder a dispositivos USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permite que la aplicación acceda a dispositivos USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"administrar preferencias y permisos para los dispositivos USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permite a la aplicación administrar preferencias y permisos para los dispositivos USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"probar el hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Admite que la aplicación controle diversos periféricos con el fin de probar el hardware."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
<string name="permdesc_callPhone" msgid="3369867353692722456">"Admite que la aplicación llame a ciertos números de teléfono sin tu permiso. Las aplicaciones maliciosas pueden ocasionar llamadas imprevistas en tu factura telefónica. Ten en cuenta que esto no admite que la aplicación llame a los números de emergencia."</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"llamar directamente a cualquier número de teléfono"</string>
<string name="permdesc_callPrivileged" msgid="244405067160028452">"Admite que la aplicación llame a cualquier número de teléfono, incluidos los números de emergencia, sin tu intervención. Las aplicaciones maliciosas pueden realizar llamadas innecesarias e ilegales a los servicios de emergencia."</string>
- <string name="permlab_performCdmaProvisioning" msgid="5604848095315421425">"comienza directamente la configuración CDMA del teléfono"</string>
+ <string name="permlab_performCdmaProvisioning" msgid="5604848095315421425">"iniciar directamente la configuración CDMA del teléfono"</string>
<string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"Admite la aplicación para comenzar con el aprovisionamiento CDMA. Las aplicaciones maliciosas pueden comenzar con el aprovisionamiento CDMA sin necesidad."</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"controlar las notificaciones de actualización de ubicación"</string>
<string name="permdesc_locationUpdates" msgid="2300018303720930256">"Permite activar y desactivar las notificaciones de actualización de ubicación de la radio. Las aplicaciones normales no deben utilizarlo."</string>
@@ -390,7 +390,7 @@
<string name="permlab_changeNetworkState" msgid="958884291454327309">"cambiar la conectividad de la red"</string>
<string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Permite que una aplicación cambie el estado de la conectividad de red."</string>
<string name="permlab_changeTetherState" msgid="2702121155761140799">"Cambiar la conectividad de anclaje a red"</string>
- <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Permite que una aplicación cambie el estado de la conectividad de red del anclaje."</string>
+ <string name="permdesc_changeTetherState" msgid="8905815579146349568">"ermite que una aplicación cambie el estado de la conectividad de anclaje a red."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"cambiar la configuración del uso de datos del fondo"</string>
<string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Admite una aplicación que cambia la configuración del uso de datos del fondo."</string>
<string name="permlab_accessWifiState" msgid="8100926650211034400">"ver el estado de Wi-Fi"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Admite una aplicación que se conecta y desconecta de los puntos de acceso de Wi-Fi y que hace cambios en las redes de Wi-Fi configuradas."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recepción de multidifusión Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite a una aplicación recibir paquetes que no están dirigidos directamente a tu dispositivo. Esta opción puede ser útil al descubrir servicios ofrecidos. Además, ejerce más potencia que el modo que no es de multidifusión."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"ver el estado de WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Permite que una aplicación vea la información acerca del estado de WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"cambiar estado de WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Permite que una aplicación se conecte a una red WiMAX y se desconecte de esta."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administración de bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Admite una aplicación que configura el teléfono Bluetooth local y descubre y se vincula con dispositivos remotos."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"crear conexiones de Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Utilizar de manera predeterminada en esta acción."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Borrar la predeterminación en Configuración de la página principal &gt; Aplicaciones &gt; Administrar aplicaciones."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Seleccionar una acción"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Selecciona una aplicación para el dispositivo USB."</string>
<string name="noApplications" msgid="1691104391758345586">"Ninguna aplicación puede realizar esta acción."</string>
<string name="aerr_title" msgid="653922989522758100">"¡Lo sentimos!"</string>
<string name="aerr_application" msgid="4683614104336409186">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha detenido de forma imprevista. Vuelve a intentarlo."</string>
@@ -750,7 +755,7 @@
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> se inició originalmente."</string>
<string name="smv_application" msgid="295583804361236288">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) ha violado su política StrictMode autoimpuesta."</string>
<string name="smv_process" msgid="5120397012047462446">"El proceso <xliff:g id="PROCESS">%1$s</xliff:g> ha violado su política StrictMode autoimpuesta."</string>
- <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> Correr"</string>
+ <string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> en ejecución"</string>
<string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Selecciona cambiar la aplicación"</string>
<string name="heavy_weight_switcher_title" msgid="1135403633766694316">"¿Deseas cambiar aplicaciones?"</string>
<string name="heavy_weight_switcher_text" msgid="4592075610079319667">"Ya se está ejecutando una aplicación que debe detenerse antes de iniciar una nueva."</string>
@@ -835,17 +840,17 @@
<string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"Almacenamiento USB dañado. Es posible que debas reformatearlo."</string>
<string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"Tarjeta SD dañada. Es posible que debas reformatearla."</string>
<string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"Almacenamiento USB extraído inesperadamente"</string>
- <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Tarjeta SD extraída de forma imprevista"</string>
+ <string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Almacenamiento USB extraído de forma imprevista"</string>
<string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Desmontar el almacenamiento USB antes de extraerlo para evitar la pérdida de datos."</string>
<string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Desmontar la tarjeta SD antes de extraerla para evitar la pérdida de datos."</string>
<string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"Es seguro extraer el almacenamiento USB"</string>
- <string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"Tarjeta SD fácil de extraer"</string>
+ <string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"Es seguro extraer la tarjeta SD"</string>
<string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"Puedes extraer de forma segura el almacenamiento USB."</string>
- <string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"Puedes eliminar la tarjeta SD sin riesgos."</string>
+ <string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"Puedes extraer de forma segura la tarjeta SD."</string>
<string name="ext_media_nomedia_notification_title" product="nosdcard" msgid="4486377230140227651">"Almacenamiento USB extraído"</string>
<string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"Tarjeta SD extraída"</string>
<string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"Almacenamiento USB eliminado. Insertar nuevos medios."</string>
- <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"Tarjeta SD eliminada. Inserta una nueva."</string>
+ <string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"Tarjeta SD extraída. Insertar una nueva."</string>
<string name="activity_list_empty" msgid="4168820609403385789">"No se encontraron actividades coincidentes"</string>
<string name="permlab_pkgUsageStats" msgid="8787352074326748892">"actualizar la estadística de uso de los componentes"</string>
<string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Permite la modificación de estadísticas recopiladas sobre el uso de componentes. Las aplicaciones normales no deben utilizarlo."</string>
@@ -877,8 +882,8 @@
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambiar fondo de pantalla"</string>
<string name="pptp_vpn_description" msgid="2688045385181439401">"Protocolo de túnel punto a punto"</string>
<string name="l2tp_vpn_description" msgid="3750692169378923304">"Protocolo de túnel de nivel 2"</string>
- <string name="l2tp_ipsec_psk_vpn_description" msgid="3945043564008303239">"Clave previamente compartida según L2TP/IPSec VPN"</string>
- <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"Certificado según L2TP/IPSec VPN"</string>
+ <string name="l2tp_ipsec_psk_vpn_description" msgid="3945043564008303239">"VPN L2TP/IPSec basada en clave compartida previamente"</string>
+ <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"VPN L2TP/IPSec basada en certificado"</string>
<string name="upload_file" msgid="2897957172366730416">"Elegir archivo"</string>
<string name="reset" msgid="2448168080964209908">"Restablecer"</string>
<string name="submit" msgid="1602335572089911941">"Enviar"</string>
@@ -896,7 +901,7 @@
<string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"Borrando almacenamiento USB..."</string>
<string name="progress_erasing" product="default" msgid="2115214724367534095">"Borrando tarjeta SD..."</string>
<string name="format_error" product="nosdcard" msgid="4320339096529911637">"No pudo borrar el almacenamiento USB."</string>
- <string name="format_error" product="default" msgid="1343380371925238343">"No pudo borrar la tarjeta SD."</string>
+ <string name="format_error" product="default" msgid="1343380371925238343">"No se pudo borrar la tarjeta SD."</string>
<string name="media_bad_removal" msgid="7960864061016603281">"Se ha extraído la tarjeta SD antes de ser desmontada."</string>
<string name="media_checking" product="nosdcard" msgid="418188720009569693">"Se está verificando el almacenamiento USB en este momento."</string>
<string name="media_checking" product="default" msgid="7334762503904827481">"Se está verificando la tarjeta SD en este momento."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 543b53e..efff15b 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Permite que la aplicación controle la función de vibración."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Permite que la aplicación controle la función de linterna."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"acceso a dispositivos USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"La aplicación puede acceder a dispositivos USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"administrar preferencias y permisos de dispositivos USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permite que la aplicación administre las preferencias y los permisos de los dispositivos USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"probar hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite que la aplicación controle distintos periféricos con fines de prueba del hardware."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite que una aplicación se conecte a puntos de acceso Wi-Fi y se desconecte de ellos, y realice modificaciones en las redes Wi-Fi configuradas."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recepción multidifusión Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite que una aplicación reciba paquetes no dirigidos directamente a tu dispositivo. Esta función puede resultar útil para descubrir servicios cercanos. Utiliza más energía que el modo de no multidifusión."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"ver estado de WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Permite que una aplicación acceda a la información sobre el estado de la conectividad WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"cambiar estado de WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Permite a una aplicación conectarse a una red WiMAX y desconectarse de ella."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administración de Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permite que una aplicación configure el teléfono Bluetooth local, y vea dispositivos remotos y sincronice el teléfono con ellos."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"crear conexiones de Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Utilizar de forma predeterminada para esta acción"</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Borrar valores predeterminados en la página de configuración de la pantalla de inicio del teléfono &gt; Aplicaciones &gt; Administrar aplicaciones\"."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Seleccionar una acción"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Seleccionar una aplicación para el dispositivo USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Ninguna aplicación puede realizar esta acción."</string>
<string name="aerr_title" msgid="653922989522758100">"Lo sentimos."</string>
<string name="aerr_application" msgid="4683614104336409186">"La aplicación <xliff:g id="APPLICATION">%1$s</xliff:g> (proceso <xliff:g id="PROCESS">%2$s</xliff:g>) se ha interrumpido inesperadamente. Inténtalo de nuevo."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6c77768..114a6dd 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"به برنامه کاربردی اجازه می دهد لرزاننده را کنترل کند."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"کنترل چراغ قوه"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"به برنامه کاربردی اجازه می دهد چراغ قوه را کنترل کند."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"دسترسی به دستگاه های USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"به برنامه کاربردی اجازه می دهد به دستگاه های USB دسترسی پیدا کند."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"مدیریت تنظیمات برگزیده و مجوزها برای دستگاه های USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"به برنامه کاربردی جهت مدیریت تنظیمات برگزیده و مجوزها برای دستگاه های USB اجازه می دهد."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"تست سخت افزار"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"به برنامه کاربردی اجازه می دهد سایر برنامه های جانبی را برای تست سخت افزاری کنترل کند."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"تماس مستقیم با شماره تلفن ها"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"به یک برنامه کاربردی اجازه می دهد به نقاط دسترسی Wi-Fi متصل شده و از آنها جدا شود، همچنین تغییراتی را در مورد شبکه های Wi-Fi پیکربندی شده ایجاد کند."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"دریافت چندگانه Wi-Fi را مجاز می کند"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"به یک برنامه کاربردی اجازه می دهد بسته هایی را دریافت کند که مستقیماً برای دستگاه شما ارسال نشده باشد. این امر زمانی که در حال شناسایی سرویس های نزدیک به خود هستید، می تواند مؤثر باشد. در این حالت در مقایسه با حالت غیر چندگانه، از انرژِی بیشتری استفاده می شود."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"مشاهده وضعیت WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"به یک برنامه کاربردی امکان می دهد اطلاعات مربوط به وضعیت WiMAX را مشاهده کند."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"تغییر وضعیت WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"به یک برنامه کاربردی امکان می دهد به شبکه WiMAX متصل یا از آن قطع شود."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"سرپرست بلوتوث"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"به یک برنامه کاربردی اجازه می دهد تا تلفن محلی بلوتوث را پیکربندی کرده، دستگاه های راه دور را شناسایی کرده و با آنها جفت شود."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"ایجاد اتصال های بلوتوث"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"استفاده به صورت پیش فرض برای این عملکرد."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"پاک کردن موارد پیش فرض در تنظیمات صفحه اصلی &gt; برنامه های کاربردی &gt; مدیریت برنامه ها."</string>
<string name="chooseActivity" msgid="1009246475582238425">"انتخاب یک عملکرد"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"انتخاب یک برنامه کاربردی برای دستگاه USB"</string>
<string name="noApplications" msgid="1691104391758345586">"هیچ برنامه ای نمی تواند این عملکرد را اجرا کند."</string>
<string name="aerr_title" msgid="653922989522758100">"متأسفیم!"</string>
<string name="aerr_application" msgid="4683614104336409186">"برنامه کاربردی <xliff:g id="APPLICATION">%1$s</xliff:g> ( فرآیند <xliff:g id="PROCESS">%2$s</xliff:g>) به طور غیر منتظره ای متوقف شد. لطفاً دوباره امتحان کنید."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 192bf13..6603d15 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Antaa sovelluksen hallita värinää."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"hallitse taskulamppua"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Antaa sovelluksen hallita lamppua."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"käytä USB-tiloja"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Antaa sovelluksen käyttää USB-tiloja."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"hallinnoi USB-laitteiden asetuksia ja käyttöoikeuksia"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Antaa sovelluksen hallinnoida USB-laitteiden asetuksia ja käyttöoikeuksia"</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testaa laitteistoa"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Antaa sovelluksen hallita useita liitännäislaitteita laitteistotestaustarkoituksessa."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"soittaa puhelinnumeroihin suoraan"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Antaa sovelluksen muodostaa ja katkaista yhteyden wifi-tukiasemista ja tehdä muutoksia määritettyihin wifi-verkkoihin."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"anna ottaa vastaan wifi-ryhmälähetyksiä"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Antaa sovelluksen vastaanottaa paketteja, joita ei ole osoitettu suoraan laitteellesi. Tämän toiminnon avulla voit löytää lähistöllä tarjolla olevia palveluita. Toiminto käyttää enemmän akkua kuin ei-ryhmälähetystila."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"tarkastele WiMAX-verkon tilaa"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Antaa sovelluksen tarkastella WiMAX-verkon tilaa."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"vaihda WiMAX-verkon tilaa"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Antaa sovelluksen muodostaa yhteyden WiMAX-verkkoon ja katkaista yhteyden."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"hallitse bluetooth-yhteyttä"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Antaa sovelluksen määrittää paikallisen Bluetooth-puhelimen ja etsiä muita laitteita ja muodostaa niihin laitepariyhteyden."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"luo Bluetooth-yhteyksiä"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Käytä oletuksena tälle toiminnolle."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Tyhjennä oletusasetus kohdassa Etusivun asetukset &gt; Sovellukset &gt; Hallinnoi sovelluksia."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Valitse toiminto"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Valitse sovellus USB-laitteelle"</string>
<string name="noApplications" msgid="1691104391758345586">"Yksikään sovellus ei voi suorittaa tätä toimintoa."</string>
<string name="aerr_title" msgid="653922989522758100">"Pahoittelemme!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Sovellus <xliff:g id="APPLICATION">%1$s</xliff:g> (prosessi <xliff:g id="PROCESS">%2$s</xliff:g>) pysähtyi yllättäen. Yritä uudelleen."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index ee9b97f..a1939e4 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -125,7 +125,7 @@
<string name="contentServiceSync" msgid="8353523060269335667">"Synchroniser"</string>
<string name="contentServiceSyncNotificationTitle" msgid="397743349191901458">"Synchronisation"</string>
<string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Trop de contenus supprimés (<xliff:g id="CONTENT_TYPE">%s</xliff:g>)."</string>
- <string name="low_memory" msgid="6632412458436461203">"La mémoire du téléphone est pleine ! Supprimez des fichiers pour libérer de l\'espace."</string>
+ <string name="low_memory" msgid="6632412458436461203">"La mémoire du téléphone est pleine. Supprimez des fichiers pour libérer de l\'espace."</string>
<string name="me" msgid="6545696007631404292">"Moi"</string>
<string name="power_dialog" msgid="1319919075463988638">"Options du téléphone"</string>
<string name="silent_mode" msgid="7167703389802618663">"Mode silencieux"</string>
@@ -153,7 +153,7 @@
<string name="permgrouplab_messages" msgid="7521249148445456662">"Vos messages"</string>
<string name="permgroupdesc_messages" msgid="7045736972019211994">"Permet de lire et rédiger vos SMS, e-mails et autres messages."</string>
<string name="permgrouplab_personalInfo" msgid="3519163141070533474">"Vos informations personnelles"</string>
- <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Accédez directement aux contacts et à l\'agenda enregistrés sur votre téléphone."</string>
+ <string name="permgroupdesc_personalInfo" msgid="5488050357388806068">"Accéder directement aux contacts et à l\'agenda enregistrés sur votre téléphone"</string>
<string name="permgrouplab_location" msgid="635149742436692049">"Votre position"</string>
<string name="permgroupdesc_location" msgid="2430258821648348660">"Suivre votre position géographique"</string>
<string name="permgrouplab_network" msgid="5808983377727109831">"Communications réseau"</string>
@@ -170,7 +170,7 @@
<string name="permgroupdesc_developmentTools" msgid="9056431193893809814">"Ces fonctionnalités sont réservées aux développeurs d\'applications."</string>
<string name="permgrouplab_storage" msgid="1971118770546336966">"Stockage"</string>
<string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Accéder à la mémoire de stockage USB"</string>
- <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Accès à la carte SD"</string>
+ <string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Accéder à la carte SD"</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"Désactivation ou modification de la barre d\'état"</string>
<string name="permdesc_statusBar" msgid="1365473595331989732">"Permet à une application de désactiver la barre d\'état ou d\'ajouter/supprimer des icônes système."</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"barre d\'état"</string>
@@ -246,7 +246,7 @@
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"Se fixer sur un fond d\'écran"</string>
<string name="permdesc_bindWallpaper" msgid="5287754520361915347">"Permet au support de se fixer sur l\'interface de plus haut niveau d\'un fond d\'écran. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interagir avec l\'administrateur du périphérique"</string>
- <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permet à l\'application d\'envoyer des intentions à l\'administrateur du périphérique. Les applications standard ne devraient jamais avoir recours à cette fonctionnalité."</string>
+ <string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Permet à l\'application d\'envoyer des intentions à l\'administrateur de l\'appareil. Les applications standard ne devraient jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"Changement d\'orientation de l\'écran"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Permet à une application de modifier la rotation de l\'écran à tout moment. Les applications normales ne devraient jamais avoir recours à cette fonctionnalité."</string>
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Envoi de signaux Linux aux applications"</string>
@@ -290,9 +290,9 @@
<string name="permlab_writeContacts" msgid="644616215860933284">"Édition des données d\'un contact"</string>
<string name="permdesc_writeContacts" msgid="3924383579108183601">"Permet à une application de modifier toutes les données de contact (adresses) enregistrées sur le téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour effacer ou modifier vos données de contact."</string>
<string name="permlab_readCalendar" msgid="6898987798303840534">"lire des événements de l\'agenda"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Permet à une application de lire tous les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
+ <string name="permdesc_readCalendar" msgid="5533029139652095734">"Permet à une application de lire tous les événements de l\'agenda enregistrés sur votre téléphone. Des applications malveillantes peuvent exploiter cette fonctionnalité pour envoyer les événements de votre agenda à d\'autres personnes."</string>
<string name="permlab_writeCalendar" msgid="3894879352594904361">"ajouter ou modifier des événements d\'agenda et envoyer des e-mails aux invités"</string>
- <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Autorise les applications à ajouter ou à modifier des événements dans votre agenda, qui pourra envoyer des e-mails aux invités. Des logiciels malveillants peuvent utiliser cette fonctionnalité pour supprimer ou modifier des événements de l\'agenda ou envoyer des e-mails aux invités."</string>
+ <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Permet aux applications d\'ajouter ou de modifier des événements dans votre agenda, qui est susceptible d\'envoyer des e-mails aux invités. Des applications malveillantes peuvent exploiter cette fonctionnalité pour supprimer ou modifier des événements de l\'agenda ou envoyer des e-mails aux invités."</string>
<string name="permlab_accessMockLocation" msgid="8688334974036823330">"Création de sources de localisation fictives à des fins de test"</string>
<string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Permet de créer des sources de localisation fictives à des fins de test. Des applications malveillantes peuvent utiliser cette fonctionnalité pour remplacer la position géographique et/ou l\'état fournis par des sources réelles comme le GPS ou les fournisseurs d\'accès."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"Accès aux commandes de fournisseur de position géographique supplémentaires"</string>
@@ -300,9 +300,9 @@
<string name="permlab_installLocationProvider" msgid="6578101199825193873">"autoriser l\'installation d\'un fournisseur de services de localisation"</string>
<string name="permdesc_installLocationProvider" msgid="5449175116732002106">"Créer des sources de données de localisation factices à des fins de test. Les applications malveillantes peuvent exploiter cette fonction pour remplacer la position géographique et/ou l\'état renvoyé par les sources de données de localisation réelles, telles que le GPS ou les fournisseurs réseau, ou pour surveiller et transmettre votre position géographique à une source externe."</string>
<string name="permlab_accessFineLocation" msgid="8116127007541369477">"Localisation OK (GPS)"</string>
- <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Permet d\'accéder à des sources de localisation précises comme le Global Positioning System (GPS) sur le téléphone, lorsque ces services sont disponibles. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer l\'endroit où vous vous trouvez et augmenter la consommation de la batterie de votre téléphone."</string>
+ <string name="permdesc_accessFineLocation" msgid="7411213317434337331">"Permet d\'accéder à des sources de localisation précises telles que le système GPS du téléphone, lorsque ces services sont disponibles. Des applications malveillantes peuvent exploiter cette fonctionnalité pour déterminer votre position, ce qui peut entraîner une utilisation accrue de la batterie."</string>
<string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"Position géo. approximative (selon le réseau)"</string>
- <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Accès à des sources de localisation approximative (par ex. des bases de données de réseaux mobiles) pour déterminer la position géographique du téléphone, lorsque cette option est disponible. Des applications malveillantes peuvent utiliser cette fonctionnalité pour déterminer approximativement l\'endroit où vous vous trouvez."</string>
+ <string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Permet d\'accéder à des sources de localisation approximatives telles que des bases de données de réseaux mobiles pour déterminer la position géographique du téléphone, lorsque cette option est disponible. Des applications malveillantes peuvent exploiter cette fonctionnalité pour déterminer votre position approximative."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"Accès à SurfaceFlinger"</string>
<string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Permet à certaines applications d\'utiliser les fonctionnalités SurfaceFlinger de bas niveau."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"Lecture de la mémoire tampon graphique"</string>
@@ -313,30 +313,30 @@
<string name="permdesc_recordAudio" msgid="6493228261176552356">"Permet à l\'application d\'accéder au chemin de l\'enregistrement audio."</string>
<string name="permlab_camera" msgid="3616391919559751192">"prendre des photos et enregistrer des vidéos"</string>
<string name="permdesc_camera" msgid="6004878235852154239">"Permet de prendre des photos et d\'enregistrer des vidéos avec l\'appareil photo. Cette fonctionnalité permet à l\'application de récupérer à tout moment les images perçues par l\'appareil."</string>
- <string name="permlab_brick" msgid="8337817093326370537">"Désactivation définitive du téléphone"</string>
+ <string name="permlab_brick" msgid="8337817093326370537">"désactiver définitivement le téléphone"</string>
<string name="permdesc_brick" msgid="5569526552607599221">"Permet à l\'application de désactiver définitivement le téléphone. Cette fonctionnalité est très dangereuse."</string>
- <string name="permlab_reboot" msgid="2898560872462638242">"Redémarrage forcé du téléphone"</string>
+ <string name="permlab_reboot" msgid="2898560872462638242">"forcer le redémarrage du téléphone"</string>
<string name="permdesc_reboot" msgid="7914933292815491782">"Permet à l\'application de forcer le redémarrage du téléphone."</string>
- <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Monter et démonter des systèmes de fichiers"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permet à l\'application de monter et démonter des systèmes de fichiers pour des périphériques de stockage amovibles."</string>
+ <string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"Installer et désinstaller des systèmes de fichiers"</string>
+ <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Permet à l\'application d\'installer et de désinstaller des systèmes de fichiers pour des périphériques de stockage amovibles."</string>
<string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"Formatage du périphérique de stockage externe"</string>
<string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Permet à l\'application de formater le périphérique de stockage amovible."</string>
<string name="permlab_asec_access" msgid="3411338632002193846">"obtenir des informations sur la mémoire de stockage interne"</string>
- <string name="permdesc_asec_access" msgid="8820326551687285439">"Permet à l\'application d\'obtenir des informations sur le stockage interne."</string>
- <string name="permlab_asec_create" msgid="6414757234789336327">"créer un stockage interne"</string>
+ <string name="permdesc_asec_access" msgid="8820326551687285439">"Permet à l\'application d\'obtenir des informations sur la mémoire de stockage interne."</string>
+ <string name="permlab_asec_create" msgid="6414757234789336327">"créer une mémoire de stockage interne"</string>
<string name="permdesc_asec_create" msgid="2621346764995731250">"Permet à l\'application de créer une mémoire de stockage interne."</string>
<string name="permlab_asec_destroy" msgid="526928328301618022">"détruire la mémoire de stockage interne"</string>
- <string name="permdesc_asec_destroy" msgid="2746706889208066256">"Permet à l\'application de détruire le stockage interne."</string>
+ <string name="permdesc_asec_destroy" msgid="2746706889208066256">"Permet à l\'application de détruire la mémoire de stockage interne."</string>
<string name="permlab_asec_mount_unmount" msgid="2456287623689029744">"installer/désinstaller la mémoire de stockage interne"</string>
<string name="permdesc_asec_mount_unmount" msgid="5934375590189368200">"Permet l\'installation ou la désinstallation de la mémoire de stockage interne par l\'application."</string>
<string name="permlab_asec_rename" msgid="7496633954080472417">"renommer la mémoire de stockage interne"</string>
- <string name="permdesc_asec_rename" msgid="2152829985238876790">"Permet à l\'application de renommer le stockage interne."</string>
+ <string name="permdesc_asec_rename" msgid="2152829985238876790">"Permet à l\'application de renommer la mémoire de stockage interne."</string>
<string name="permlab_vibrate" msgid="7768356019980849603">"Contrôle du vibreur"</string>
<string name="permdesc_vibrate" msgid="2886677177257789187">"Permet à l\'application de contrôler le vibreur."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"Contrôle de la lampe de poche"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Permet à l\'application de contrôler la lampe de poche."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"accéder aux périphériques USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Autorise l\'application à accéder aux périphériques USB"</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"gérer les préférences et les autorisations des périphériques USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permet à l\'application de gérer les préférences et les autorisations des périphériques USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"Tests du matériel"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Permet à l\'application de contrôler différents périphériques à des fins de test matériel."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"Appel direct des numéros de téléphone"</string>
@@ -355,12 +355,12 @@
<string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Permet à une application de contrôler les fonctionnalités téléphoniques de l\'appareil. Une application bénéficiant de cette autorisation peut changer de réseau, éteindre et allumer le signal radio du téléphone, etc., sans vous en avertir."</string>
<string name="permlab_readPhoneState" msgid="2326172951448691631">"Lire l\'état et l\'identité du téléphone"</string>
<string name="permdesc_readPhoneState" msgid="188877305147626781">"Permet à l\'application d\'accéder aux fonctionnalités d\'appel du téléphone. L\'application peut alors déterminer le numéro de téléphone et le numéro de série de l\'appareil, savoir si un appel est en cours, identifier le numéro appelé, etc."</string>
- <string name="permlab_wakeLock" msgid="573480187941496130">"Arrêt du mode veille sur le téléphone"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Permet à une application d\'empêcher votre téléphone de passer en mode veille."</string>
+ <string name="permlab_wakeLock" msgid="573480187941496130">"empêcher le téléphone de passer en mode veille"</string>
+ <string name="permdesc_wakeLock" msgid="7584036471227467099">"Permet à une application d\'empêcher le téléphone de passer en mode veille."</string>
<string name="permlab_devicePower" msgid="4928622470980943206">"Éteindre ou allumer le téléphone"</string>
<string name="permdesc_devicePower" msgid="4577331933252444818">"Permet à l\'application d\'éteindre et d\'allumer le téléphone."</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"Exécution en mode Test d\'usine"</string>
- <string name="permdesc_factoryTest" msgid="8136644990319244802">"Permet d\'exécuter en tant que test fabricant de faible niveau en autorisant l\'accès au matériel du téléphone. Cette fonctionnalité est uniquement disponible lorsque le téléphone est en mode de test fabricant."</string>
+ <string name="permdesc_factoryTest" msgid="8136644990319244802">"Permet d\'exécuter une application en mode test fabricant de faible niveau en autorisant ainsi l\'accès au téléphone. Cette fonctionnalité est uniquement disponible lorsque le téléphone est en mode test fabricant."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"Configuration du fond d\'écran"</string>
<string name="permdesc_setWallpaper" msgid="6417041752170585837">"Permet à une application de définir le fond d\'écran du système."</string>
<string name="permlab_setWallpaperHints" msgid="3600721069353106851">"Sélection de la la taille du fond d\'écran"</string>
@@ -399,12 +399,16 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permet à une application de se connecter à des points d\'accès Wi-Fi, de s\'en déconnecter et de modifier des réseaux Wi-Fi configurés."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"autoriser la réception de données en Wi-Fi multidiffusion"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Autorise une application à recevoir des paquets qui ne sont pas directement adressés à votre mobile. Cela peut être utile pour la recherche de services disponibles à proximité. Consomme plus que le mode non multidiffusion."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"afficher l\'état du WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Permet à une application d\'afficher les informations concernant l\'état du WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"modifier l\'état du WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Permet à une application de se connecter au réseau WiMAX et de s\'en déconnecter."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Gestion Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permet à une application de configurer le téléphone Bluetooth local, d\'identifier des périphériques distants et de les associer au téléphone."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"Création de connexions Bluetooth"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Permet à une application d\'obtenir la configuration du téléphone Bluetooth local et de créer et accepter des connexions à des appareils associés."</string>
+ <string name="permdesc_bluetooth" msgid="762515380679392945">"Permet à une application d\'obtenir la configuration du téléphone Bluetooth local, de se connecter à des appareils associés et d\'accepter leur connexion."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"contrôler la communication en champ proche"</string>
- <string name="permdesc_nfc" msgid="9171401851954407226">"Autorise une application à communiquer avec des tags, cartes et lecteurs prenant en charge la communication en champ proche (NFC)."</string>
+ <string name="permdesc_nfc" msgid="9171401851954407226">"Permet à une application de communiquer avec des tags, cartes et lecteurs prenant en charge la communication en champ proche (NFC)."</string>
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"Désactivation du verrouillage des touches"</string>
<string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Permet à une application de désactiver le verrouillage des touches et toute sécurité par mot de passe. Exemple : Votre téléphone désactive le verrouillage du clavier lorsque vous recevez un appel, puis le réactive lorsque vous raccrochez."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"Lecture des paramètres de synchronisation"</string>
@@ -421,8 +425,8 @@
<string name="permdesc_readDictionary" msgid="1082972603576360690">"Permet à une application de lire tous les mots, noms et expressions que l\'utilisateur a pu enregistrer dans son dictionnaire personnel."</string>
<string name="permlab_writeDictionary" msgid="6703109511836343341">"Enregistrement dans le dictionnaire défini par l\'utilisateur"</string>
<string name="permdesc_writeDictionary" msgid="2241256206524082880">"Permet à une application d\'enregistrer de nouveaux mots dans le dictionnaire personnel de l\'utilisateur."</string>
- <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"modifier/supprimer le contenu de la mémoire de stockage USB"</string>
- <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"Modifier/supprimer le contenu de la carte SD"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"modif./suppr. contenu mémoire USB"</string>
+ <string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"modifier/supprimer le contenu de la carte SD"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Autorise une application à écrire sur la mémoire USB."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Autorise une application à écrire sur la carte SD."</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"accéder au système de fichiers en cache"</string>
@@ -432,13 +436,13 @@
<string name="policylab_limitPassword" msgid="4497420728857585791">"Définir les règles du mot de passe"</string>
<string name="policydesc_limitPassword" msgid="9083400080861728056">"Gérer le nombre et le type de caractères autorisés dans les mots de passe de déverrouillage de l\'écran"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Gérer les tentatives de déverrouillage de l\'écran"</string>
- <string name="policydesc_watchLogin" msgid="7227578260165172673">"Gérer le nombre de mots de passe incorrects saisis lors du déverrouillage de l\'écran et verrouiller le téléphone ou effacer toutes ses données après un certain nombre de tentatives"</string>
+ <string name="policydesc_watchLogin" msgid="7227578260165172673">"Surveiller le nombre de mots de passe incorrects saisis lors du déverrouillage de l\'écran et verrouiller le téléphone ou effacer toutes ses données après un certain nombre de tentatives"</string>
<string name="policylab_resetPassword" msgid="2620077191242688955">"Modifier le mot de passe de déverrouillage de l\'écran"</string>
<string name="policydesc_resetPassword" msgid="5391240616981297361">"Modifier le mot de passe de déverrouillage de l\'écran"</string>
<string name="policylab_forceLock" msgid="2274085384704248431">"Verrouiller l\'écran"</string>
<string name="policydesc_forceLock" msgid="5696964126226028442">"Gérer le mode et les conditions de verrouillage de l\'écran"</string>
<string name="policylab_wipeData" msgid="3910545446758639713">"Effacer toutes les données"</string>
- <string name="policydesc_wipeData" msgid="7669895333814222586">"Effacer les données du téléphone sans avertissement, en restaurant les valeurs d\'usine"</string>
+ <string name="policydesc_wipeData" msgid="7669895333814222586">"Effacer les données du téléphone sans avertissement, en restaurant la configuration usine"</string>
<string-array name="phoneTypes">
<item msgid="8901098336658710359">"Domicile"</item>
<item msgid="869923650527136615">"Mobile"</item>
@@ -541,11 +545,11 @@
<string name="keyguard_password_enter_pin_code" msgid="3731488827218876115">"Saisissez le code PIN"</string>
<string name="keyguard_password_enter_password_code" msgid="9138158344813213754">"Saisissez le mot de passe pour procéder au déverrouillage."</string>
<string name="keyguard_password_wrong_pin_code" msgid="1295984114338107718">"Le code PIN est incorrect !"</string>
- <string name="keyguard_label_text" msgid="861796461028298424">"Pour débloquer le clavier, appuyez sur \"Menu\" puis sur 0."</string>
+ <string name="keyguard_label_text" msgid="861796461028298424">"Pour déverrouiller le clavier, appuyez sur \"Menu\" puis sur 0."</string>
<string name="emergency_call_dialog_number_for_display" msgid="696192103195090970">"Numéro d\'urgence"</string>
<string name="lockscreen_carrier_default" msgid="8812714795156374435">"(Aucun service)"</string>
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Écran verrouillé"</string>
- <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Appuyez sur \"Menu\" pour débloquer le téléphone ou appeler un numéro d\'urgence"</string>
+ <string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Appuyez sur \"Menu\" pour déverrouiller le téléphone ou appeler un numéro d\'urgence"</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Appuyez sur \"Menu\" pour déverrouiller le téléphone."</string>
<string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Dessinez un schéma pour déverrouiller le téléphone"</string>
<string name="lockscreen_emergency_call" msgid="5347633784401285225">"Appel d\'urgence"</string>
@@ -566,7 +570,7 @@
<string name="lockscreen_sim_locked_message" msgid="8066660129206001039">"La carte SIM est verrouillée."</string>
<string name="lockscreen_sim_unlock_progress_dialog_message" msgid="595323214052881264">"Déblocage de la carte SIM..."</string>
<string name="lockscreen_too_many_failed_attempts_dialog_message" msgid="3514742106066877476">"Vous avez mal reproduit le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. "\n\n"Veuillez réessayer dans <xliff:g id="NUMBER_1">%d</xliff:g> secondes."</string>
- <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Vous avez mal saisi le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> tentatives supplémentaires, vous devrez débloquer votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
+ <string name="lockscreen_failed_attempts_almost_glogin" msgid="3351013842320127827">"Vous avez mal saisi le schéma de déverrouillage <xliff:g id="NUMBER_0">%d</xliff:g> fois. Au bout de <xliff:g id="NUMBER_1">%d</xliff:g> tentatives supplémentaires, vous devrez déverrouiller votre téléphone à l\'aide de votre identifiant Google."\n\n"Merci de réessayer dans <xliff:g id="NUMBER_2">%d</xliff:g> secondes."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6251480343394389665">"Réessayez dans <xliff:g id="NUMBER">%d</xliff:g> secondes."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="2626999449610695930">"Schéma oublié ?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="2588521501166032747">"Déverrouillage du compte"</string>
@@ -577,7 +581,7 @@
<string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Se connecter"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Nom d\'utilisateur ou mot de passe incorrect."</string>
<string name="lockscreen_glogin_checking_password" msgid="6758890536332363322">"Vérification..."</string>
- <string name="lockscreen_unlock_label" msgid="737440483220667054">"Débloquer"</string>
+ <string name="lockscreen_unlock_label" msgid="737440483220667054">"Déverrouiller"</string>
<string name="lockscreen_sound_on_label" msgid="9068877576513425970">"Son activé"</string>
<string name="lockscreen_sound_off_label" msgid="996822825154319026">"Son désactivé"</string>
<string name="password_keyboard_label_symbol_key" msgid="992280756256536042">"?123"</string>
@@ -597,7 +601,7 @@
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"lire l\'historique et les favoris du navigateur"</string>
<string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Autorise l\'application à lire toutes les URL auxquelles le navigateur a accédé et tous ses favoris."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"écrire dans l\'historique et les favoris du navigateur"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Autorise une application à modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Des applications malveillantes peuvent utiliser cette fonction pour effacer ou modifier les données de votre navigateur."</string>
+ <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Permet à une application de modifier l\'historique du navigateur ou les favoris enregistrés sur votre téléphone. Des applications malveillantes peuvent exploiter cette fonction pour effacer ou modifier les données de votre navigateur."</string>
<string name="permlab_setAlarm" msgid="5924401328803615165">"régler le réveil"</string>
<string name="permdesc_setAlarm" msgid="5966966598149875082">"Permet à l\'application de définir une alarme dans un utilitaire faisant office de réveil. Certains réveils risquent ne pas prendre en charge cette fonctionnalité."</string>
<string name="permlab_writeGeolocationPermissions" msgid="4715212655598275532">"Modifier les autorisations de géolocalisation du navigateur"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Utiliser cette application par défaut pour cette action"</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Effacer les paramètres par défaut dans les Paramètres de page d\'accueil &gt; Applications &gt; Gérer les applications."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Sélectionner une action"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Sélectionnez une application pour le périphérique USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Aucune application ne peut effectuer cette action."</string>
<string name="aerr_title" msgid="653922989522758100">"Désolé !"</string>
<string name="aerr_application" msgid="4683614104336409186">"Fermeture soudaine de l\'application <xliff:g id="APPLICATION">%1$s</xliff:g> (du processus <xliff:g id="PROCESS">%2$s</xliff:g>). Merci de réessayer."</string>
@@ -828,22 +833,22 @@
<string name="ext_media_checking_notification_message" msgid="8287319882926737053">"Recherche d\'erreurs"</string>
<string name="ext_media_nofs_notification_title" product="nosdcard" msgid="7788040745686229307">"Mémoire de stockage USB vide"</string>
<string name="ext_media_nofs_notification_title" product="default" msgid="780477838241212997">"Carte SD vide"</string>
- <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"Le stockage USB est vide ou son système de fichiers n\'est pas pris en charge."</string>
+ <string name="ext_media_nofs_notification_message" product="nosdcard" msgid="8623130522556087311">"La mémoire de stockage USB est vide ou son système de fichiers n\'est pas pris en charge."</string>
<string name="ext_media_nofs_notification_message" product="default" msgid="3817704088027829380">"La carte SD est vide ou son système de fichiers n\'est pas pris en charge."</string>
- <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Stockage USB endommagé"</string>
+ <string name="ext_media_unmountable_notification_title" product="nosdcard" msgid="2090046769532713563">"Mémoire de stockage USB endommagée"</string>
<string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Carte SD endommagée"</string>
<string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"La mémoire de stockage USB est endommagée. Un reformatage est peut-être nécessaire."</string>
<string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"La carte SD est endommagée. Vous devrez peut-être la reformater."</string>
<string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"Mémoire USB retirée inopinément"</string>
<string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Carte SD retirée inopinément"</string>
<string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Désinstaller la mémoire de stockage USB avant de la retirer pour éviter toute perte de données."</string>
- <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Désactiver la carte SD avant de la retirer pour éviter toute perte de données."</string>
- <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"Retirez la mémoire USB en toute sécurité."</string>
+ <string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Désinstaller la carte SD avant de la retirer pour éviter toute perte de données."</string>
+ <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"Vous pouvez retirer la mémoire USB."</string>
<string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"La carte SD peut être retirée en toute sécurité"</string>
- <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"La mémoire de stockage USB peut être retirée en toute sécurité."</string>
+ <string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"Vous pouvez retirer la mémoire de stockage USB en toute sécurité."</string>
<string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"Vous pouvez retirer la carte SD en toute sécurité."</string>
<string name="ext_media_nomedia_notification_title" product="nosdcard" msgid="4486377230140227651">"Mémoire de stockage USB retirée"</string>
- <string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"Carte SD manquante"</string>
+ <string name="ext_media_nomedia_notification_title" product="default" msgid="8902518030404381318">"Carte SD retirée"</string>
<string name="ext_media_nomedia_notification_message" product="nosdcard" msgid="6921126162580574143">"Mémoire de stockage USB retirée. Insérez un nouveau support."</string>
<string name="ext_media_nomedia_notification_message" product="default" msgid="3870120652983659641">"La carte SD a été retirée. Insérez-en une autre."</string>
<string name="activity_list_empty" msgid="4168820609403385789">"Aucune activité correspondante trouvée"</string>
@@ -893,7 +898,7 @@
<string name="throttled_notification_message" msgid="4712369856601275146">"Touchez pour en savoir plus sur l\'utilisation des données mobiles"</string>
<string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"Désinstallation de la mémoire de stockage USB..."</string>
<string name="progress_unmounting" product="default" msgid="5556813978958789471">"Désinstallation de la carte SD..."</string>
- <string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"Effacement de la mémoire de stockage USB..."</string>
+ <string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"Effacement de la mémoire de stockage USB..."</string>
<string name="progress_erasing" product="default" msgid="2115214724367534095">"Effacement de la carte SD..."</string>
<string name="format_error" product="nosdcard" msgid="4320339096529911637">"Impossible d\'effacer la mémoire de stockage USB"</string>
<string name="format_error" product="default" msgid="1343380371925238343">"Impossible d\'effacer la carte SD"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index fbf149b..fdc3679 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Aplikaciji omogućuje nadzor nad vibracijom."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"nadzor bljeskalice"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Aplikaciji omogućuje nadzor nad bljeskalicom."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"pristupi USB uređajima"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Omogućuje aplikaciji pristup USB uređajima."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"upravljanje postavkama i dozvolama za USB uređaje"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Aplikaciji omogućuje upravljanje postavkama i dozvolama za USB uređaje."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testiranje hardvera"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Aplikacijama omogućuje nadzor nad raznim vanjskim jedinicama u svrhu hardverskog testiranja."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"izravno pozivanje telefonskog broja"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Aplikacije omogućuju povezivanje i prekidanje veze s Wi-Fi pristupnim točkama te promjene u konfiguriranim Wi-Fi mrežama."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"omogući višenamjenski Wi-Fi prijem"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Aplikaciji omogućuje primanje paketa koji nisu izravno upućeni na vaš uređaj. To može biti korisno za otkrivanje obližnjih usluge. Koristi više energije od višenamjenskog načina rada."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"prikaz stanja WiMAX mreže"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Aplikaciji omogućuje prikaz informacija o stanju WiMAX mreže."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"promjena stanja WiMAX mreže"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Omogućuje aplikaciji povezivanje i prekid veze s WiMAX mrežom."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth administracija"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Aplikaciji omogućuje konfiguraciju lokalnog Bluetooth telefona i otkrivanje i sparivanje s udaljenim uređajima."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"stvaranje Bluetooth veza"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Koristi se kao zadana postavka za ovu lokaciju."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Izbrišite zadane postavke u izborniku Početne postavke &gt; Aplikacije &gt; Upravljanje aplikacijama."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Odaberite radnju"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Odaberite aplikaciju za USB uređaj"</string>
<string name="noApplications" msgid="1691104391758345586">"Tu radnju ne može izvesti nijedna aplikacija."</string>
<string name="aerr_title" msgid="653922989522758100">"Žao nam je."</string>
<string name="aerr_application" msgid="4683614104336409186">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (postupak <xliff:g id="PROCESS">%2$s</xliff:g>) neočekivano je zaustavljen. Pokušajte ponovo."</string>
@@ -891,7 +896,7 @@
<string name="throttle_warning_notification_message" msgid="2609734763845705708">"Dotaknite da biste saznali više o upotrebi mobilnih podataka"</string>
<string name="throttled_notification_title" msgid="6269541897729781332">"Prekoračeno je ograničenje za podatke na mobilnom uređaju"</string>
<string name="throttled_notification_message" msgid="4712369856601275146">"Dotaknite da biste saznali više o upotrebi mobilnih podataka"</string>
- <string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"Isključivanje memorije USB..."</string>
+ <string name="progress_unmounting" product="nosdcard" msgid="535863554318797377">"Isključivanje USB memorije..."</string>
<string name="progress_unmounting" product="default" msgid="5556813978958789471">"Isključivanje SD kartice..."</string>
<string name="progress_erasing" product="nosdcard" msgid="4183664626203056915">"Brisanje memorije USB..."</string>
<string name="progress_erasing" product="default" msgid="2115214724367534095">"Brisanje SD kartice..."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 33fe6d3..da96ada 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Lehetővé teszi az alkalmazás számára a rezgés vezérlését."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"vaku vezérlése"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Lehetővé teszi az alkalmazás számára a vaku vezérlését."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"USB-eszközök elérése"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Lehetővé teszi az alkalmazások számára az USB-eszközök elérését."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"USB-eszközök preferenciáinak és engedélyeinek kezelése"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Lehetővé teszi, hogy az alkalmazás kezelje az USB-eszközök preferenciáit és engedélyeit."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"hardver tesztelése"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Lehetővé teszi az alkalmazás számára különböző perifériák vezérlését hardvertesztelés céljából."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefonszámok közvetlen hívása"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Lehetővé teszi egy alkalmazás számára Wi-Fi hozzáférési pontok használatát, valamint módosítások végrehajtását a konfigurált Wi-Fi hálózatokban."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fi multicast vétel engedélyezése"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Lehetővé teszi egy alkalmazás számára, hogy nem közvetlenül az eszköznek küldött csomagokat is fogadjon. Ez a közeli szolgáltatások felderítésében nyújthat segítséget. Több energiát fogyaszt, mint a nem multicast mód."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"WiMAX-állapot megtekintése"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Lehetővé teszi az alkalmazás számára a WiMAX állapotinformációk megtekintését."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"WiMAX-állapot módosítása"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Lehetővé teszi, hogy egy alkalmazás csatlakozzon a WiMAX hálózathoz, illetve megszüntesse a kapcsolatot a hálózattal."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth felügyelet"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Lehetővé teszi egy alkalmazás számára a helyi Bluetooth telefon konfigurálását, valamint a távoli eszközök felderítését és párosítását."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth kapcsolatok létrehozása"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Ez legyen az alapértelmezett program ehhez a művelethez."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Az alapértelmezés törlése a Főoldal beállításai &gt; Alkalmazások &gt; Alkalmazások kezelése menüben lehetséges."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Válasszon műveletet"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Válasszon egy alkalmazást az USB-eszköz számára"</string>
<string name="noApplications" msgid="1691104391758345586">"Egyik alkalmazás sem tudja végrehajtani ezt a műveletet."</string>
<string name="aerr_title" msgid="653922989522758100">"Sajnáljuk!"</string>
<string name="aerr_application" msgid="4683614104336409186">"A(z) <xliff:g id="APPLICATION">%1$s</xliff:g> alkalmazás <xliff:g id="PROCESS">%2$s</xliff:g> folyamata váratlanul leállt. Kérjük, próbálja újra."</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index cefc140..052ccb5 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -128,7 +128,7 @@
<string name="low_memory" msgid="6632412458436461203">"Penyimpanan di ponsel penuh! Hapus sebagian berkas untuk mendapatkan ruang."</string>
<string name="me" msgid="6545696007631404292">"Saya"</string>
<string name="power_dialog" msgid="1319919075463988638">"Opsi telepon"</string>
- <string name="silent_mode" msgid="7167703389802618663">"Mode senyap"</string>
+ <string name="silent_mode" msgid="7167703389802618663">"Modus senyap"</string>
<string name="turn_on_radio" msgid="3912793092339962371">"Hidupkan nirkabel"</string>
<string name="turn_off_radio" msgid="8198784949987062346">"Matikan nirkabel"</string>
<string name="screen_lock" msgid="799094655496098153">"Kunci layar"</string>
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Mengizinkan aplikasi mengontrol penggetar."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"mengontrol lampu senter"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Mengizinkan aplikasi mengontrol lampu senter."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"akses perangkat USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Mengizinkan aplikasi untuk perangkat USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"kelola preferensi dan izin untuk perangkat USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Membiarkan aplikasi mengelola preferensi dan izin untuk perangkat USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"uji perangkat keras"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Mengizinkan aplikasi mengontrol berbagai perangkat periferal untuk tujuan menguji perangkat keras."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"panggil nomor telepon secara langsung"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Mengizinkan aplikasi tersambung dan diputus dari titik akses Wi-Fi, dan melakukan perubahan pada jaringan Wi-Fi yang dikonfigurasi."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Izinkan penerimaan Wi-Fi Multicast"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Mengizinkan aplikasi menerima paket yang tidak langsung dialamatkan ke perangkat Anda. Ini dapat bermanfaat ketika mencari perangkat yang ditawarkan di dekat Anda. Aplikasi ini menggunakan lebih banyak daya ketimbang mode selain multicast."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"lihat status WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Mengizinkan aplikasi melihat informasi tentang status WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"Ganti status WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Mengizinkan aplikasi menyambung ke dan memutus dari jaringan WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Administrasi bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Mengizinkan aplikasi mengonfigurasi ponsel Bluetooth lokal, dan menemukan dan menyandingkan perangkat jarak jauh."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"buat sambungan Bluetooth"</string>
@@ -605,7 +609,7 @@
<string name="save_password_message" msgid="767344687139195790">"Apakah Anda ingin peramban menyimpan sandi ini?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Tidak sekarang"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Ingat"</string>
- <string name="save_password_never" msgid="8274330296785855105">"Tidak pernah"</string>
+ <string name="save_password_never" msgid="8274330296785855105">"Jangan"</string>
<string name="open_permission_deny" msgid="5661861460947222274">"Anda tidak memiliki izin untuk membuka laman ini."</string>
<string name="text_copied" msgid="4985729524670131385">"Teks disalin ke clipboard."</string>
<string name="more_item_label" msgid="4650918923083320495">"Lainnya"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Gunakan secara bawaan untuk tindakan ini."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Bersihkan bawaan pada Setelan Beranda &gt; Aplikasi &gt; Kelola aplikasi."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Pilih tindakan"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Pilih sebuah aplikasi untuk perangkat USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Tidak ada aplikasi dapat melakukan tindakan ini."</string>
<string name="aerr_title" msgid="653922989522758100">"Maaf!"</string>
<string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> aplikasi (<xliff:g id="PROCESS">%2$s</xliff:g> proses) berhenti tiba-tiba. Harap coba lagi."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 8608b5b..90c2ab7 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Consente all\'applicazione di controllare la vibrazione."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"controllo flash"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Consente all\'applicazione di controllare il flash."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"accesso a dispositivi USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Consente all\'applicazione di accedere ai dispositivi USB"</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"gestione preferenze e autorizzazioni per dispositivi USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Consente all\'applicazione di gestire le preferenze e le autorizzazioni relative ai dispositivi USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"esecuzione test hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Consente all\'applicazione di controllare varie periferiche per il test dell\'hardware."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"chiamata diretta n. telefono"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Consente a un\'applicazione di connettersi/disconnettersi da punti di accesso Wi-Fi e di apportare modifiche alle reti Wi-Fi configurate."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"consenti ricezione multicast Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Consente a un\'applicazione di ricevere pacchetti non direttamente indirizzati al tuo dispositivo. Può essere utile durante la ricerca di servizi offerti nelle vicinanze. Consuma di più rispetto alla modalità non multicast."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"visualizzazione stato WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Consente a un\'applicazione di visualizzare le informazioni relative allo stato della rete WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"modifica stato WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Consente a un\'applicazione di connettersi/disconnettersi dalla rete WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"gestione Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Consente a un\'applicazione di configurare il telefono Bluetooth locale e di rilevare e abbinare dispositivi remoti."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"creazione connessioni Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Usa come predefinita per questa azione."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Cancella predefinita in Home &gt; Impostazioni &gt; Applicazioni &gt; Gestisci applicazioni."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Seleziona un\'azione"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Seleziona un\'applicazione per il dispositivo USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Nessuna applicazione è in grado di svolgere questa azione."</string>
<string name="aerr_title" msgid="653922989522758100">"Spiacenti."</string>
<string name="aerr_application" msgid="4683614104336409186">"Interruzione imprevista dell\'applicazione <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>). Riprova."</string>
@@ -872,7 +877,7 @@
<string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Autorizzazione richiesta"\n"per l\'account <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
<string name="input_method_binding_label" msgid="1283557179944992649">"Metodo inserimento"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"Sinc"</string>
- <string name="accessibility_binding_label" msgid="4148120742096474641">"Accesso facilitato"</string>
+ <string name="accessibility_binding_label" msgid="4148120742096474641">"Accessibilità"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Sfondo"</string>
<string name="chooser_wallpaper" msgid="7873476199295190279">"Cambia sfondo"</string>
<string name="pptp_vpn_description" msgid="2688045385181439401">"Protocollo di tunneling Point-to-Point"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 454a624..1d48f6e 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"מאפשר ליישום לשלוט ברטט."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"שליטה בפנס"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"מאפשר ליישום לשלוט בפנס."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"גישה להתקני USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"מאפשר ליישום גישה להתקני USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"נהל העדפות ואישורים עבור התקני USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"מאפשר ליישום לנהל העדפות ואישורים עבור התקני USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"בדוק חומרה"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"מאפשר ליישום לשלוט בציוד היקפי מסוגים שונים לצורך בדיקת חומרה."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"התקשר ישירות למספרי טלפון"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"מאפשר ליישום להתחבר ולהתנתק מנקודות גישה של Wi-Fi, ולבצע שינויים ברשתות Wi-Fi מוגדרות."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"אפשר קבלת שידורים מרובים ב-Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"מאפשר ליישום לקבל חפיסות שלא ממוענות ישירות למכשיר שלך. יכולת זו שימושית בעת גילוי שירותים המוצעים בקרבת מקום. היא משתמשת במתח סוללה רב יותר לעומת מצב שאינו ריבוי שידורים."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"הצג את מצב WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"מאפשר ליישום להציג את המידע על המצב של WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"שנה את מצב WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"מאפשר ליישום להתחבר ולהתנתק מרשת WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"ניהול Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"מאפשר ליישום להגדיר את טלפון Bluetooth המקומי, ולגלות מכשירים מרוחקים ולבצע התאמה איתם."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"צור חיבורי Bluetooth"</string>
@@ -440,7 +444,7 @@
<string name="policylab_wipeData" msgid="3910545446758639713">"מחק את כל הנתונים"</string>
<string name="policydesc_wipeData" msgid="7669895333814222586">"מחק את נתוני הטלפון ללא אזהרה, על ידי ביצוע איפוס נתוני יצרן"</string>
<string-array name="phoneTypes">
- <item msgid="8901098336658710359">"דף הבית"</item>
+ <item msgid="8901098336658710359">"בית"</item>
<item msgid="869923650527136615">"נייד"</item>
<item msgid="7897544654242874543">"עבודה"</item>
<item msgid="1103601433382158155">"פקס בעבודה"</item>
@@ -450,19 +454,19 @@
<item msgid="9192514806975898961">"מותאם אישית"</item>
</string-array>
<string-array name="emailAddressTypes">
- <item msgid="8073994352956129127">"דף הבית"</item>
+ <item msgid="8073994352956129127">"בית"</item>
<item msgid="7084237356602625604">"עבודה"</item>
<item msgid="1112044410659011023">"אחר"</item>
<item msgid="2374913952870110618">"מותאם אישית"</item>
</string-array>
<string-array name="postalAddressTypes">
- <item msgid="6880257626740047286">"דף הבית"</item>
+ <item msgid="6880257626740047286">"בית"</item>
<item msgid="5629153956045109251">"עבודה"</item>
<item msgid="4966604264500343469">"אחר"</item>
<item msgid="4932682847595299369">"מותאם אישית"</item>
</string-array>
<string-array name="imAddressTypes">
- <item msgid="1738585194601476694">"דף הבית"</item>
+ <item msgid="1738585194601476694">"בית"</item>
<item msgid="1359644565647383708">"עבודה"</item>
<item msgid="7868549401053615677">"אחר"</item>
<item msgid="3145118944639869809">"מותאם אישית"</item>
@@ -483,7 +487,7 @@
<item msgid="1648797903785279353">"Jabber"</item>
</string-array>
<string name="phoneTypeCustom" msgid="1644738059053355820">"מותאם אישית"</string>
- <string name="phoneTypeHome" msgid="2570923463033985887">"דף הבית"</string>
+ <string name="phoneTypeHome" msgid="2570923463033985887">"בית"</string>
<string name="phoneTypeMobile" msgid="6501463557754751037">"נייד"</string>
<string name="phoneTypeWork" msgid="8863939667059911633">"עבודה"</string>
<string name="phoneTypeFaxWork" msgid="3517792160008890912">"פקס בעבודה"</string>
@@ -507,16 +511,16 @@
<string name="eventTypeAnniversary" msgid="3876779744518284000">"יום השנה"</string>
<string name="eventTypeOther" msgid="5834288791948564594">"אירוע"</string>
<string name="emailTypeCustom" msgid="8525960257804213846">"מותאם אישית"</string>
- <string name="emailTypeHome" msgid="449227236140433919">"דף הבית"</string>
+ <string name="emailTypeHome" msgid="449227236140433919">"בית"</string>
<string name="emailTypeWork" msgid="3548058059601149973">"עבודה"</string>
<string name="emailTypeOther" msgid="2923008695272639549">"אחר"</string>
<string name="emailTypeMobile" msgid="119919005321166205">"סלולרי"</string>
<string name="postalTypeCustom" msgid="8903206903060479902">"מותאם אישית"</string>
- <string name="postalTypeHome" msgid="8165756977184483097">"דף הבית"</string>
+ <string name="postalTypeHome" msgid="8165756977184483097">"בית"</string>
<string name="postalTypeWork" msgid="5268172772387694495">"עבודה"</string>
<string name="postalTypeOther" msgid="2726111966623584341">"אחר"</string>
<string name="imTypeCustom" msgid="2074028755527826046">"מותאם אישית"</string>
- <string name="imTypeHome" msgid="6241181032954263892">"דף הבית"</string>
+ <string name="imTypeHome" msgid="6241181032954263892">"בית"</string>
<string name="imTypeWork" msgid="1371489290242433090">"עבודה"</string>
<string name="imTypeOther" msgid="5377007495735915478">"אחר"</string>
<string name="imProtocolCustom" msgid="6919453836618749992">"מותאם אישית"</string>
@@ -533,7 +537,7 @@
<string name="orgTypeOther" msgid="3951781131570124082">"אחר"</string>
<string name="orgTypeCustom" msgid="225523415372088322">"מותאם אישית"</string>
<string name="sipAddressTypeCustom" msgid="2473580593111590945">"מותאם אישית"</string>
- <string name="sipAddressTypeHome" msgid="6093598181069359295">"דף הבית"</string>
+ <string name="sipAddressTypeHome" msgid="6093598181069359295">"בית"</string>
<string name="sipAddressTypeWork" msgid="6920725730797099047">"עבודה"</string>
<string name="sipAddressTypeOther" msgid="4408436162950119849">"אחר"</string>
<string name="contact_status_update_attribution" msgid="5112589886094402795">"דרך <xliff:g id="SOURCE">%1$s</xliff:g>"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"השתמש כברירת מחדל עבור פעולה זו."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"נקה את ברירת המחדל ב\'הגדרות דף הבית\' &gt; \'יישומים\' &gt; \'נהל יישומים\'."</string>
<string name="chooseActivity" msgid="1009246475582238425">"בחר פעולה"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"בחר יישום עבור התקן ה-USB"</string>
<string name="noApplications" msgid="1691104391758345586">"אין יישומים שיכולים לבצע פעולה זו."</string>
<string name="aerr_title" msgid="653922989522758100">"מצטערים!"</string>
<string name="aerr_application" msgid="4683614104336409186">"היישום <xliff:g id="APPLICATION">%1$s</xliff:g> (תהליך <xliff:g id="PROCESS">%2$s</xliff:g>) הופסק באופן לא צפוי. נסה שוב."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 48c73cc..0e26ce2 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -270,7 +270,7 @@
<string name="permlab_readLogs" msgid="6615778543198967614">"機密ログデータの読み取り"</string>
<string name="permdesc_readLogs" msgid="8896449437464867766">"システムの各種ログファイルの読み取りをアプリケーションに許可します。許可すると端末の使用状況に関する全般的な情報が読み取られます。この情報には個人情報や機密情報が含まれる場合があります。"</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"diagが所有するリソースの読み書き"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"diagグループが所有するリソース(例:/dev内のファイル)への読み書きをアプリケーションに許可します。システムの安定性とセキュリティに影響する恐れがあります。メーカー/オペレーターによるハードウェア固有の診断以外には使用しないでください。"</string>
+ <string name="permdesc_diagnostic" msgid="3121238373951637049">"diagグループが所有するリソース(例:/dev内のファイル)への読み書きをアプリケーションに許可します。システムの安定性とセキュリティに影響する恐れがあります。メーカー/通信事業者によるハードウェア固有の診断以外には使用しないでください。"</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"アプリケーションのコンポーネントを有効/無効にする"</string>
<string name="permdesc_changeComponentState" msgid="4569107043246700630">"別アプリケーションのコンポーネントの有効/無効を変更することをアプリケーションに許可します。これにより悪意のあるアプリケーションが、携帯電話の重要な機能を無効にする恐れがあります。アプリケーションコンポーネントが利用できない、整合性が取れない、または不安定な状態になる恐れがあるので、許可には注意が必要です。"</string>
<string name="permlab_setPreferredApplications" msgid="3393305202145172005">"優先アプリケーションの設定"</string>
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"バイブレーションの制御をアプリケーションに許可します。"</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"ライトのコントロール"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"ライトの制御をアプリケーションに許可します。"</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"USBデバイスへのアクセス"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"USBデバイスへのアクセスをアプリケーションに許可します。"</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"USBデバイスの設定と許可の管理"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"USBデバイスの設定と許可の管理をアプリケーションに許可します。"</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"ハードウェアのテスト"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"ハードウェアのテストのためにさまざまな周辺機器を制御することをアプリケーションに許可します。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"電話番号発信"</string>
@@ -352,13 +352,13 @@
<string name="permlab_bindGadget" msgid="776905339015863471">"ウィジェットの選択"</string>
<string name="permdesc_bindGadget" msgid="2098697834497452046">"どのアプリケーションがどのウィジェットを使用できるかシステムに指定することをこのアプリケーションに許可します。これにより、アプリケーション間で個人データにアクセスできるようになります。通常のアプリケーションでは使用しません。"</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"端末ステータスの変更"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"端末の電話機能のコントロールをアプリケーションに許可します。アプリケーションは、ネットワークの切り替え、携帯電話の無線通信のオン/オフなどを通知せずに行うことができます。"</string>
+ <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"端末の電話機能のコントロールをアプリケーションに許可します。アプリケーションは、ネットワークの切り替え、携帯電話の無線通信のON/OFFなどを通知せずに行うことができます。"</string>
<string name="permlab_readPhoneState" msgid="2326172951448691631">"携帯のステータスとIDの読み取り"</string>
<string name="permdesc_readPhoneState" msgid="188877305147626781">"端末の電話機能へのアクセスをアプリケーションに許可します。この権限が許可されたアプリケーションでは、この携帯の電話番号やシリアル番号、通話中かどうか、通話相手の電話番号などを特定できます。"</string>
<string name="permlab_wakeLock" msgid="573480187941496130">"端末のスリープを無効にする"</string>
<string name="permdesc_wakeLock" msgid="7584036471227467099">"端末のスリープを無効にすることをアプリケーションに許可します。"</string>
<string name="permlab_devicePower" msgid="4928622470980943206">"電源のON/OFF"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"携帯電話の電源のオン/オフをアプリケーションに許可します。"</string>
+ <string name="permdesc_devicePower" msgid="4577331933252444818">"携帯電話の電源のON/OFFをアプリケーションに許可します。"</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"出荷時試験モードでの実行"</string>
<string name="permdesc_factoryTest" msgid="8136644990319244802">"携帯電話のハードウェアへのアクセスを完全に許可して、低レベルのメーカーテストとして実行します。メーカーのテストモードで携帯電話を使用するときのみ利用できます。"</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"壁紙の設定"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Wi-Fiアクセスポイントへの接続や接続の切断、設定されたWi-Fiネットワークの変更をアプリケーションに許可します。"</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fiマルチキャストの受信を許可する"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"端末を直接の宛先とはしていないパケットの受信をアプリケーションに許可します。近隣で提供中のサービスを検出したい場合に便利です。マルチキャスト以外のモードよりも電力を消費します。"</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"WiMAX状態の表示"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"WiMAX状態に関する情報の表示をアプリケーションに許可します。"</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"WiMAX状態の変更"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"WiMAXネットワークへの接続と接続解除をアプリケーションに許可します。"</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetoothの管理"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"このBluetooth端末の設定、およびリモート端末を検出してペアに設定することをアプリケーションに許可します。"</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth接続の作成"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"常にこの操作で使用する"</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"ホームの[設定]&gt;[アプリケーション]&gt;[アプリケーションの管理]でデフォルト設定をクリアします。"</string>
<string name="chooseActivity" msgid="1009246475582238425">"操作の選択"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"USBデバイス用アプリケーションを選択"</string>
<string name="noApplications" msgid="1691104391758345586">"この操作を実行できるアプリケーションはありません。"</string>
<string name="aerr_title" msgid="653922989522758100">"エラー"</string>
<string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g>(<xliff:g id="PROCESS">%2$s</xliff:g>)が予期せず停止しました。やり直してください。"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 179dabe..90892e5 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -177,7 +177,7 @@
<string name="permdesc_statusBarService" msgid="4097605867643520920">"애플리케이션이 상태 표시줄이 되도록 허용합니다."</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"상태 표시줄 확장/축소"</string>
<string name="permdesc_expandStatusBar" msgid="7088604400110768665">"애플리케이션이 상태 표시줄을 확장하거나 축소할 수 있도록 합니다."</string>
- <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"발신전화 가로채기"</string>
+ <string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"발신전화 차단"</string>
<string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"애플리케이션이 발신전화를 처리하고 전화를 걸 번호를 변경할 수 있도록 합니다. 이 경우 악성 애플리케이션이 발신전화를 모니터링하거나, 다른 방향으로 돌리거나, 중단시킬 수 있습니다."</string>
<string name="permlab_receiveSms" msgid="2697628268086208535">"SMS 수신"</string>
<string name="permdesc_receiveSms" msgid="6298292335965966117">"애플리케이션이 SMS 메시지를 받고 처리할 수 있도록 합니다. 이 경우 악성 애플리케이션이 메시지를 모니터링하거나 사용자가 보기 전에 삭제할 수 있습니다."</string>
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"애플리케이션이 진동을 제어할 수 있도록 합니다."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"카메라 플래시 제어"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"애플리케이션이 카메라 플래시를 제어할 수 있도록 합니다."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"USB 장치 액세스"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"애플리케이션이 USB 장치에 액세스하도록 허용합니다."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"USB 기기에 대한 환경설정 및 권한 관리"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"애플리케이션이 USB 기기에 대한 환경설정 및 권한을 관리하도록 허용합니다."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"하드웨어 테스트"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"애플리케이션이 하드웨어를 테스트할 목적으로 다양한 주변장치를 제어할 수 있도록 합니다."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"전화번호 자동 연결"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"애플리케이션이 Wi-Fi 액세스포인트에 연결하거나 연결을 끊고, 구성된 Wi-Fi 네트워크를 변경할 수 있도록 합니다."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fi 멀티캐스트 수신 허용"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"애플리케이션이 휴대기기로 직접 주소가 지정되지 않은 패킷을 받을 수 있도록 합니다. 이 기능은 가까운 곳에서 제공되는 서비스를 검색할 때 유용하며 비멀티캐스트 모드보다 전원을 더 많이 소비합니다."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"WiMAX 상태 보기"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"애플리케이션이 WiMAX의 상태에 대한 정보를 볼 수 있도록 합니다."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"WiMAX 상태 변경"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"애플리케이션이 WiMAX 네트워크에 연결하거나 연결을 끊을 수 있도록 합니다."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth 관리"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"애플리케이션이 로컬 Bluetooth 휴대전화를 구성한 다음 원격 장치를 검색하여 페어링할 수 있도록 합니다."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth 연결 만들기"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"이 작업에 대해 기본값으로 사용"</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"홈 설정 &gt; 애플리케이션 &gt; 애플리케이션 관리에서 기본값을 지웁니다."</string>
<string name="chooseActivity" msgid="1009246475582238425">"작업 선택"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"USB 기기에 대한 애플리케이션 선택"</string>
<string name="noApplications" msgid="1691104391758345586">"작업을 수행할 수 있는 애플리케이션이 없습니다."</string>
<string name="aerr_title" msgid="653922989522758100">"죄송합니다."</string>
<string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> 애플리케이션(<xliff:g id="PROCESS">%2$s</xliff:g> 프로세스)이 예상치 않게 중지되었습니다. 다시 시도해 주세요."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 07a1e72..656338a 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Leidžia programai valdyti vibratorių."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"valdyti šviesos signalą"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Leidžia programai valdyti šviesos signalą."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"pasiekti USB įrenginius"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Leidžiama programai pasiekti USB įrenginius."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"valdyti USB įrenginių nuostatas ir leidimus"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Leidžiama programai valdyti USB įrenginių nuostatas ir leidimus."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"bandyti aparatinę įrangą"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Leidžia programai valdyti įvairius išorinius įrenginius aparatinės įrangos bandymo tikslais."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"skambinti tiesiogiai telefono numeriais"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Leidžia programai prisijungti ir atsijungti nuo „Wi-Fi“ prieigos taškų ir keisti konfigūruotus „Wi-Fi“ tinklus."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"leisti „Wi-Fi“ daugiaadresio perdavimo priėmimą"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Leidžia programai gauti paketus, tiesiogiai neadresuotus jūsų įrenginiui. Tai naudinga atradus šalia siūlomas paslaugas. Tai naudoja daugiau energijos nei ne daugiaadresio perdavimo režimas."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"žiūrėti „WiMAX“ būseną"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Leidžiama programai matyti informaciją apie „WiMAX“ būseną."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"keisti „WiMAX“ būseną"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Leidžiama programai prisijungti prie „WiMAX“ tinklo ir nuo jo atsijungti."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"„bluetooth“ administravimas"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Leidžia programai konfigūruoti vietinį „Bluetooth“ telefoną ir atrasti bei susieti su nuotoliniais įrenginiais."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"kurti „Bluetooth“ ryšius"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Šiam veiksmui tai naudoti pagal numatytuosius nustatymus."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Išvalykite numatytuosius nustatymus apsilankę „Pagrindiniai nustatymai“ &gt; „Programos“ &gt; „Valdyti programas“."</string>
<string name="chooseActivity" msgid="1009246475582238425">"pasirinkti veiksmą"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Pasirinkti programą USB įrenginiui"</string>
<string name="noApplications" msgid="1691104391758345586">"Šio veiksmo negali atlikti jokios programos."</string>
<string name="aerr_title" msgid="653922989522758100">"Apgailestaujame!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Programa <xliff:g id="APPLICATION">%1$s</xliff:g> (<xliff:g id="PROCESS">%2$s</xliff:g> procesas) netikėtai sustojo. Bandykite dar kartą."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 59c93393..6462b05 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Ļauj lietojumprogrammai kontrolēt vibrozvanu."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"kontrolēt uzliesmojumu"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Ļauj lietojumprogrammai kontrolēt uzliesmojumu."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"piekļuve USB ierīcēm"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Ļauj lietojumprogrammai piekļūt USB ierīcēm."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"USB ierīču preferenču un atļauju pārvaldība"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Ļauj lietojumprogrammai pārvaldīt preferences un atļaujas saistībā ar USB ierīcēm."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"pārbaudīt aparatūru"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Ļauj lietojumprogrammai kontrolēt dažādas perifērijas ierīces aparatūras pārbaudīšanas nolūkos."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"tieši zvanīt uz tālruņa numuriem"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Ļauj lietojumprogrammai izveidot savienojumu ar Wi-Fi piekļuves punktiem un atvienot to, kā arī veikt izmaiņas konfigurētajos Wi-Fi tīklos."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"atļaut Wi-Fi multiraides uztveršanu"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Ļauj lietojumprogrammai saņemt paketes, kas nav tieši adresētas ierīcei. Tas var būt noderīgi, atklājot pakalpojumus, kas tiek piedāvāti tuvākajā apkārtnē. Tas izmanto vairāk jaudas nekā režīmā, kas nav multiraides režīms."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"WiMAX statusa skatīšana"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Ļauj lietojumprogrammai skatīt informāciju par WiMAX statusu."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"WiMAX statusa mainīšana"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Ļauj lietojumprogrammai izveidot un pārtraukt savienojumu ar WiMAX tīklu."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth administrēšana"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Ļauj lietojumprogrammai konfigurēt vietējo Bluetooth tālruni un atklāt attālās ierīces, un izveidot pāri ar tām."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"izveidot Bluetooth savienojumus"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Pēc noklusējuma izmantot šai darbībai."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Notīriet noklusējumu šeit: Sākuma iestatījumi &gt; Lietojumprogrammas &gt; Lietojumprogrammu pārvaldība."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Atlasiet darbību"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Atlasīt lietojumprogrammu USB ierīcei"</string>
<string name="noApplications" msgid="1691104391758345586">"Šo darbību nevar veikt neviena lietojumprogramma."</string>
<string name="aerr_title" msgid="653922989522758100">"Atvainojiet!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Lietojumprogrammas <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) darbība neparedzēti tika apturēta. Lūdzu, mēģiniet vēlreiz."</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 6424c68..35a7606 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Lar applikasjonen kontrollere vibratoren."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"kontrollere lommelykten"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Lar applikasjonen kontrollere lommelykten."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"tilgang til USB-enheter"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Tillater programmet å få tilgang til USB-enheter."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"administrere innstillinger og tillatelser for USB-enheter"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Tillater at programmet administrerer innstillinger og tillatelser for USB-enheter."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"teste maskinvare"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Lar applikasjonen styre diverse enheter med det formål å teste maskinvaren."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ringe telefonnummer direkte"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Lar applikasjonen koble til og fra trådløse aksesspunkt, og å gjøre endringer i konfigurerte trådløse nettverk."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"tillat multicast for trådløse nettverk"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Lar applikasjonen motta pakker som ikke er adressert til enheten selv. Dette kan være nyttig ved leting etter nærliggende tjenester, men bruker mer strøm enn ikke-multicast-modus."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"vis WiMAX-status"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Dette gjør det mulig for en app å vise informasjon om WiMAX-statusen."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"endre WiMAX-status"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Gjør at en app kan koble til og fra WiMAX-nettverk."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"Bluetooth-administrasjon"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Lar applikasjonen konfigurere den lokale Bluetooth-telefonen, og å oppdage og pare med andre enheter."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"opprette Bluetooth-tilkoblinger"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Bruk som standardvalg."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Fjern standardvalg i Innstillinger &gt; Applikasjoner &gt; Installerte applikasjoner."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Velg en aktivitet"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Velg et program for USB-enheten"</string>
<string name="noApplications" msgid="1691104391758345586">"Ingen applikasjoner kan gjøre dette."</string>
<string name="aerr_title" msgid="653922989522758100">"Beklager!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Applikasjonen <xliff:g id="APPLICATION">%1$s</xliff:g> (prosess <xliff:g id="PROCESS">%2$s</xliff:g>) stoppet uventet. Prøv igjen."</string>
@@ -834,11 +839,11 @@
<string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Skadet minnekort"</string>
<string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB-lagring er skadet. Det kan være nødvendig å formatere enheten på nytt."</string>
<string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"Minnekortet er skadet. Du må kanskje formatere det."</string>
- <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-lagring fjernet uventet"</string>
+ <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-enhet fjernet uventet"</string>
<string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Minnekortet ble tatt ut uventet"</string>
- <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Koble fra USB-lagring før enheten tas ut av maskinen for å unngå tap av data."</string>
+ <string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Koble fra USB-enheten før du tar den ut for å unngå tap av data."</string>
<string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Avmonter minnekortet før det tas ut, for å unngå datatap."</string>
- <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB-lagring kan trygt fjernes"</string>
+ <string name="ext_media_safe_unmount_notification_title" product="nosdcard" msgid="3967973893270360230">"USB-enheten kan trygt fjernes"</string>
<string name="ext_media_safe_unmount_notification_title" product="default" msgid="6729801130790616200">"Trygt å ta ut minnekort"</string>
<string name="ext_media_safe_unmount_notification_message" product="nosdcard" msgid="6142195361606493530">"Det er trygt å ta ut enheten for USB-lagring."</string>
<string name="ext_media_safe_unmount_notification_message" product="default" msgid="568841278138377604">"Det er trygt å ta ut minnekortet."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 9c3478d..0a51eae 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -172,75 +172,75 @@
<string name="permgroupdesc_storage" product="nosdcard" msgid="7442318502446874999">"Toegang krijgen tot USB-opslag."</string>
<string name="permgroupdesc_storage" product="default" msgid="9203302214915355774">"Toegang tot de SD-kaart."</string>
<string name="permlab_statusBar" msgid="7417192629601890791">"statusbalk uitschakelen of wijzigen"</string>
- <string name="permdesc_statusBar" msgid="1365473595331989732">"Hiermee kan een toepassing de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
+ <string name="permdesc_statusBar" msgid="1365473595331989732">"Hiermee kan een app de statusbalk uitschakelen of systeempictogrammen toevoegen en verwijderen."</string>
<string name="permlab_statusBarService" msgid="7247281911387931485">"statusbalk"</string>
- <string name="permdesc_statusBarService" msgid="4097605867643520920">"Hiermee kan de toepassing de statusbalk zijn."</string>
+ <string name="permdesc_statusBarService" msgid="4097605867643520920">"Hiermee kan de app de statusbalk zijn."</string>
<string name="permlab_expandStatusBar" msgid="1148198785937489264">"statusbalk uitvouwen/samenvouwen"</string>
- <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Hiermee kan de toepassing de statusbalk uitvouwen of samenvouwen."</string>
+ <string name="permdesc_expandStatusBar" msgid="7088604400110768665">"Hiermee kan de app de statusbalk uitvouwen of samenvouwen."</string>
<string name="permlab_processOutgoingCalls" msgid="1136262550878335980">"uitgaande oproepen onderscheppen"</string>
- <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Hiermee kan een toepassing uitgaande oproepen verwerken en het nummer wijzigen dat wordt gebeld. Schadelijke toepassingen kunnen uitgaande oproepen bijhouden, omleiden of tegenhouden."</string>
+ <string name="permdesc_processOutgoingCalls" msgid="2228988201852654461">"Hiermee kan een app uitgaande oproepen verwerken en het nummer wijzigen dat wordt gebeld. Schadelijke apps kunnen uitgaande oproepen bijhouden, omleiden of tegenhouden."</string>
<string name="permlab_receiveSms" msgid="2697628268086208535">"SMS ontvangen"</string>
- <string name="permdesc_receiveSms" msgid="6298292335965966117">"Hiermee kan een toepassing SMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permdesc_receiveSms" msgid="6298292335965966117">"Hiermee kan een app SMS-berichten ontvangen en verwerken. Schadelijke apps kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
<string name="permlab_receiveMms" msgid="8894700916188083287">"MMS ontvangen"</string>
- <string name="permdesc_receiveMms" msgid="4563346832000174373">"Hiermee kan een toepassing MMS-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permdesc_receiveMms" msgid="4563346832000174373">"Hiermee kan een app MMS-berichten ontvangen en verwerken. Schadelijke apps kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
<string name="permlab_sendSms" msgid="5600830612147671529">"SMS-berichten verzenden"</string>
- <string name="permdesc_sendSms" msgid="1946540351763502120">"Hiermee kan de toepassing SMS-berichten verzenden. Schadelijke toepassingen kunnen u geld kosten door berichten te verzenden zonder uw toestemming."</string>
+ <string name="permdesc_sendSms" msgid="1946540351763502120">"Hiermee kan de app SMS-berichten verzenden. Schadelijke apps kunnen u geld kosten door berichten te verzenden zonder uw toestemming."</string>
<string name="permlab_readSms" msgid="4085333708122372256">"SMS of MMS lezen"</string>
- <string name="permdesc_readSms" msgid="3002170087197294591">"Hiermee kan een toepassing de op uw telefoon of SIM-kaart opgeslagen SMS-berichten lezen. Schadelijke toepassingen kunnen uw vertrouwelijke berichten mogelijk lezen."</string>
+ <string name="permdesc_readSms" msgid="3002170087197294591">"Hiermee kan een app de op uw telefoon of SIM-kaart opgeslagen SMS-berichten lezen. Schadelijke apps kunnen uw vertrouwelijke berichten mogelijk lezen."</string>
<string name="permlab_writeSms" msgid="6881122575154940744">"SMS of MMS bewerken"</string>
- <string name="permdesc_writeSms" msgid="6299398896177548095">"Hiermee kan een toepassing naar de op uw telefoon of SIM-kaart opgeslagen SMS-berichten schrijven. Schadelijke toepassingen kunnen uw berichten mogelijk verwijderen."</string>
+ <string name="permdesc_writeSms" msgid="6299398896177548095">"Hiermee kan een app naar de op uw telefoon of SIM-kaart opgeslagen SMS-berichten schrijven. Schadelijke apps kunnen uw berichten mogelijk verwijderen."</string>
<string name="permlab_receiveWapPush" msgid="8258226427716551388">"WAP ontvangen"</string>
- <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Hiermee kan een toepassing WAP-berichten ontvangen en verwerken. Schadelijke toepassingen kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
+ <string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Hiermee kan een app WAP-berichten ontvangen en verwerken. Schadelijke apps kunnen uw berichten bijhouden of deze verwijderen zonder dat u ze te zien krijgt."</string>
<string name="permlab_getTasks" msgid="5005277531132573353">"actieve toepassingen ophalen"</string>
- <string name="permdesc_getTasks" msgid="7048711358713443341">"Hiermee kan een toepassing informatie over huidige en recent uitgevoerde taken ophalen. Schadelijke toepassingen kunnen op deze manier mogelijk privé-informatie over andere toepassingen achterhalen."</string>
+ <string name="permdesc_getTasks" msgid="7048711358713443341">"Hiermee kan een app informatie over huidige en recent uitgevoerde taken ophalen. Schadelijke apps kunnen op deze manier mogelijk privé-informatie over andere apps achterhalen."</string>
<string name="permlab_reorderTasks" msgid="5669588525059921549">"actieve toepassingen opnieuw indelen"</string>
- <string name="permdesc_reorderTasks" msgid="126252774270522835">"Hiermee kan een toepassing taken naar de voor- en achtergrond verplaatsen. Schadelijke toepassingen kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
+ <string name="permdesc_reorderTasks" msgid="126252774270522835">"Hiermee kan een app taken naar de voor- en achtergrond verplaatsen. Schadelijke apps kunnen zichzelf op de voorgrond plaatsen zonder dat u hier iets aan kunt doen."</string>
<string name="permlab_setDebugApp" msgid="4339730312925176742">"foutopsporing in toepassingen inschakelen"</string>
- <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Hiermee kan een toepassing de foutopsporing voor een andere toepassing inschakelen. Schadelijke toepassingen kunnen dit gebruiken om andere toepassingen af te sluiten."</string>
+ <string name="permdesc_setDebugApp" msgid="5584310661711990702">"Hiermee kan een app de foutopsporing voor een andere app inschakelen. Schadelijke apps kunnen dit gebruiken om andere apps af te sluiten."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"uw UI-instellingen wijzigen"</string>
- <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Hiermee kan een toepassing de huidige configuratie, zoals de landinstelling of de algemene lettergrootte, wijzigen."</string>
+ <string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Hiermee kan een app de huidige configuratie, zoals de landinstelling of de algemene lettergrootte, wijzigen."</string>
<string name="permlab_enableCarMode" msgid="5684504058192921098">"automodus inschakelen"</string>
- <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Staat een toepassing toe de automodus in te schakelen."</string>
+ <string name="permdesc_enableCarMode" msgid="5673461159384850628">"Staat een app toe de automodus in te schakelen."</string>
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"processen op de achtergrond beëindigen"</string>
- <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Staat een toepassing toe processen op de achtergrond te beëindigen, zelfs als er voldoende geheugen beschikbaar is."</string>
+ <string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Staat een app toe processen op de achtergrond te beëindigen, zelfs als er voldoende geheugen beschikbaar is."</string>
<string name="permlab_forceStopPackages" msgid="1447830113260156236">"andere toepassingen gedwongen stoppen"</string>
- <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Staat een toepassing toe andere toepassingen te stoppen."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"toepassing nu sluiten"</string>
- <string name="permdesc_forceBack" msgid="6534109744159919013">"Hiermee kan een toepassing elke willekeurige activiteit die op de voorgrond wordt uitgevoerd, sluiten en naar de achtergrond verplaatsen. Nooit vereist voor normale toepassingen."</string>
+ <string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Staat een app toe andere apps te stoppen."</string>
+ <string name="permlab_forceBack" msgid="1804196839880393631">"app nu sluiten"</string>
+ <string name="permdesc_forceBack" msgid="6534109744159919013">"Hiermee kan een app elke willekeurige activiteit die op de voorgrond wordt uitgevoerd, sluiten en naar de achtergrond verplaatsen. Nooit vereist voor normale apps."</string>
<string name="permlab_dump" msgid="1681799862438954752">"interne systeemstatus ophalen"</string>
- <string name="permdesc_dump" msgid="2198776174276275220">"Hiermee kan een toepassing de interne status van het systeem ophalen. Schadelijke toepassingen kunnen privé- of veiligheidsgegevens ophalen die ze normaal niet nodig hebben."</string>
+ <string name="permdesc_dump" msgid="2198776174276275220">"Hiermee kan een app de interne status van het systeem ophalen. Schadelijke apps kunnen privé- of veiligheidsgegevens ophalen die ze normaal niet nodig hebben."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"gedeeltelijke uitschakeling"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Hiermee wordt activiteitenbeheer uitgeschakeld. Er wordt geen volledige uitschakeling uitgevoerd."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"schakelen tussen toepassingen voorkomen"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hiermee wordt voorkomen dat de gebruiker overschakelt naar een andere toepassing."</string>
+ <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hiermee wordt voorkomen dat de gebruiker overschakelt naar een andere app."</string>
<string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"alle startende toepassingen bijhouden en beheren"</string>
- <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Hiermee kan een toepassing de manier waarop het systeem activiteiten start, bijhouden en beheren. Schadelijke toepassingen kunnen het systeem volledig in gevaar brengen. Deze machtiging is alleen voor ontwikkeling vereist, nooit voor normaal telefoongebruik."</string>
+ <string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Hiermee kan een app de manier waarop het systeem activiteiten start, bijhouden en beheren. Schadelijke apps kunnen het systeem volledig in gevaar brengen. Deze machtiging is alleen voor ontwikkeling vereist, nooit voor normaal telefoongebruik."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"melding verzenden dat pakket is verwijderd"</string>
- <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Hiermee kan een toepassing een melding verzenden dat een toepassingspakket is verwijderd. Schadelijke toepassingen kunnen hiervan gebruik maken om alle andere actieve toepassingen af te sluiten."</string>
+ <string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Hiermee kan een app een melding verzenden dat een applicatiepakket (APK) is verwijderd. Schadelijke apps kunnen hiervan gebruik maken om alle andere actieve apps af te sluiten."</string>
<string name="permlab_broadcastSmsReceived" msgid="5689095009030336593">"melding over ontvangen SMS-bericht verzenden"</string>
- <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Hiermee kan een toepassing een melding verzenden dat een SMS-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om inkomende SMS-berichten te vervalsen."</string>
+ <string name="permdesc_broadcastSmsReceived" msgid="9122419277306740155">"Hiermee kan een app een melding verzenden dat een SMS-bericht is ontvangen. Schadelijke apps kunnen hiervan gebruik maken om inkomende SMS-berichten te vervalsen."</string>
<string name="permlab_broadcastWapPush" msgid="3145347413028582371">"melding over ontvangen WAP-PUSH-bericht verzenden"</string>
- <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Hiermee kan een toepassing een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke toepassingen kunnen hiervan gebruik maken om een valse MMS-ontvangst te melden of de inhoud van willekeurige webpagina\'s door schadelijke varianten te vervangen."</string>
+ <string name="permdesc_broadcastWapPush" msgid="3955303669461378091">"Hiermee kan een app een melding verzenden dat een WAP PUSH-bericht is ontvangen. Schadelijke apps kunnen hiervan gebruik maken om een valse MMS-ontvangst te melden of de inhoud van willekeurige webpagina\'s door schadelijke varianten te vervangen."</string>
<string name="permlab_setProcessLimit" msgid="2451873664363662666">"aantal actieve processen beperken"</string>
- <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Hiermee kan een toepassing het maximum aantal processen bepalen dat wordt uitgevoerd. Nooit vereist voor normale toepassingen."</string>
+ <string name="permdesc_setProcessLimit" msgid="7824786028557379539">"Hiermee kan een app het maximum aantal processen bepalen dat wordt uitgevoerd. Nooit vereist voor normale apps."</string>
<string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"alle achtergrondtoepassingen sluiten"</string>
- <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Hiermee kan een toepassing bepalen of activiteiten altijd worden afgesloten zodra deze naar de achtergrond gaan. Nooit nodig voor normale toepassingen."</string>
+ <string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"Hiermee kan een app bepalen of activiteiten altijd worden afgesloten zodra deze naar de achtergrond gaan. Nooit nodig voor normale apps."</string>
<string name="permlab_batteryStats" msgid="7863923071360031652">"accustatistieken aanpassen"</string>
<string name="permdesc_batteryStats" msgid="5847319823772230560">"Hiermee kunnen verzamelde accustatistieken worden gewijzigd. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_backup" msgid="470013022865453920">"systeemback-up en -herstel beheren"</string>
- <string name="permdesc_backup" msgid="4837493065154256525">"Hiermee kan de toepassing het mechanisme voor systeemback-up en -herstel beheren. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permdesc_backup" msgid="4837493065154256525">"Hiermee kan de app het mechanisme voor systeemback-up en -herstel beheren. Niet voor gebruik door normale apps."</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"niet-geautoriseerde vensters weergeven"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"Hiermee kunnen vensters worden gemaakt die door de interne systeemgebruikersinterface worden gebruikt. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"waarschuwingen op systeemniveau weergeven"</string>
- <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Hiermee kan een toepassing systeemwaarschuwingen weergeven. Schadelijke toepassingen kunnen op deze manier het hele scherm van de telefoon overnemen."</string>
+ <string name="permdesc_systemAlertWindow" msgid="5109622689323490558">"Hiermee kan een app systeemwaarschuwingen weergeven. Schadelijke apps kunnen op deze manier het hele scherm van de telefoon overnemen."</string>
<string name="permlab_setAnimationScale" msgid="2805103241153907174">"algemene animatiesnelheid wijzigen"</string>
- <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Hiermee kan een toepassing op elk gewenst moment de algemene animatiesnelheid wijzigen (snellere of tragere animaties)."</string>
+ <string name="permdesc_setAnimationScale" msgid="7181522138912391988">"Hiermee kan een app op elk gewenst moment de algemene animatiesnelheid wijzigen (snellere of tragere animaties)."</string>
<string name="permlab_manageAppTokens" msgid="17124341698093865">"toepassingstokens beheren"</string>
<string name="permdesc_manageAppTokens" msgid="977127907524195988">"Hiermee kunnen toepassingen hun eigen tokens maken en beheren, waarbij de normale Z-volgorde wordt overgeslagen. Nooit nodig voor normale toepassingen."</string>
<string name="permlab_injectEvents" msgid="1378746584023586600">"drukken op toetsen en bedieningselementen"</string>
- <string name="permdesc_injectEvents" msgid="3946098050410874715">"Hiermee kan een toepassing zijn eigen invoergebeurtenissen (toetsaanslagen, enzovoort) aan andere toepassingen doorgeven. Schadelijke toepassingen kunnen dit gebruiken om de telefoon over te nemen."</string>
+ <string name="permdesc_injectEvents" msgid="3946098050410874715">"Hiermee kan een app zijn de invoergebeurtenissen (toetsaanslagen, enzovoort) aan andere apps doorgeven. Schadelijke apps kunnen dit gebruiken om de telefoon over te nemen."</string>
<string name="permlab_readInputState" msgid="469428900041249234">"uw invoer en acties vastleggen"</string>
- <string name="permdesc_readInputState" msgid="5132879321450325445">"Hiermee kan een toepassing uw toetsaanslagen registreren, zelfs tijdens de interactie met een andere toepassing (zoals de invoer van een wachtwoord). Nooit vereist voor normale toepassingen."</string>
+ <string name="permdesc_readInputState" msgid="5132879321450325445">"Hiermee kan een app uw toetsaanslagen registreren, zelfs tijdens de interactie met een andere app (zoals de invoer van een wachtwoord). Nooit vereist voor normale apps."</string>
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"verbinden aan een invoermethode"</string>
<string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Hiermee staat u de houder toe zich te verbinden met de hoofdinterface van een invoermethode. Nooit vereist voor normale toepassingen."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"verbinden met een achtergrond"</string>
@@ -248,51 +248,51 @@
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interactie met apparaatbeheer"</string>
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Staat de houder toe intenties te verzenden naar een apparaatbeheerder. Nooit vereist voor normale toepassingen."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"schermstand wijzigen"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"Hiermee kan een toepassing op elk gewenst moment de oriëntatie van het scherm wijzigen. Nooit vereist voor normale toepassingen."</string>
+ <string name="permdesc_setOrientation" msgid="6335814461615851863">"Hiermee kan een app op elk gewenst moment de oriëntatie van het scherm wijzigen. Nooit vereist voor normale apps."</string>
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"Linux-signalen verzenden naar toepassingen"</string>
- <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Hiermee kan de toepassing ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
- <string name="permlab_persistentActivity" msgid="8659652042401085862">"toepassing altijd laten uitvoeren"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Hiermee kan een toepassing delen van zichzelf persistent maken, zodat het systeem dat deel niet voor andere toepassingen kan gebruiken."</string>
+ <string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Hiermee kan de app ervoor zorgen dat het geleverde signaal wordt verzonden naar alle persistente processen."</string>
+ <string name="permlab_persistentActivity" msgid="8659652042401085862">"app altijd laten uitvoeren"</string>
+ <string name="permdesc_persistentActivity" msgid="5037199778265006008">"Hiermee kan een app delen van zichzelf persistent maken, zodat het systeem dat deel niet voor andere apps kan gebruiken."</string>
<string name="permlab_deletePackages" msgid="3343439331576348805">"toepassingen verwijderen"</string>
- <string name="permdesc_deletePackages" msgid="3634943677518723314">"Hiermee kan een toepassing Android-pakketten verwijderen. Schadelijke toepassingen kunnen dit gebruiken om belangrijke toepassingen te verwijderen."</string>
+ <string name="permdesc_deletePackages" msgid="3634943677518723314">"Hiermee kan een app Android-pakketten verwijderen. Schadelijke apps kunnen dit gebruiken om belangrijke apps te verwijderen."</string>
<string name="permlab_clearAppUserData" msgid="2192134353540277878">"gegevens van andere toepassingen verwijderen"</string>
- <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Hiermee kan een toepassing gebruikersgegevens wissen."</string>
+ <string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Hiermee kan een app gebruikersgegevens wissen."</string>
<string name="permlab_deleteCacheFiles" msgid="1518556602634276725">"caches van andere toepassingen verwijderen"</string>
- <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Hiermee kan een toepassing cachebestanden verwijderen."</string>
- <string name="permlab_getPackageSize" msgid="4799785352306641460">"opslagruimte van toepassing bepalen"</string>
- <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Hiermee kan een toepassing de bijbehorende code, gegevens en cachegrootten ophalen."</string>
+ <string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Hiermee kan een app cachebestanden verwijderen."</string>
+ <string name="permlab_getPackageSize" msgid="4799785352306641460">"opslagruimte van app bepalen"</string>
+ <string name="permdesc_getPackageSize" msgid="5557253039670753437">"Hiermee kan een app de bijbehorende code, gegevens en cachegrootten ophalen."</string>
<string name="permlab_installPackages" msgid="335800214119051089">"toepassingen rechtstreeks installeren"</string>
- <string name="permdesc_installPackages" msgid="526669220850066132">"Hiermee kan een toepassing nieuwe of bijgewerkte Android-pakketten installeren. Schadelijke toepassingen kunnen hiervan gebruik maken om nieuwe toepassingen met willekeurig krachtige machtigingen toe te voegen."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"alle cachegegevens van toepassing verwijderen"</string>
- <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Hiermee kan een toepassing opslagruimte op de telefoon vrij maken door bestanden te verwijderen uit de cachemap van de toepassing. De toegang is doorgaans beperkt tot het systeemproces."</string>
+ <string name="permdesc_installPackages" msgid="526669220850066132">"Hiermee kan een app nieuwe of bijgewerkte Android-pakketten installeren. Schadelijke apps kunnen hiervan gebruik maken om nieuwe apps met willekeurig krachtige machtigingen toe te voegen."</string>
+ <string name="permlab_clearAppCache" msgid="4747698311163766540">"alle cachegegevens van app verwijderen"</string>
+ <string name="permdesc_clearAppCache" msgid="7740465694193671402">"Hiermee kan een app opslagruimte op de telefoon vrij maken door bestanden te verwijderen uit de cachemap van de app. De toegang is doorgaans beperkt tot het systeemproces."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Toepassingsbronnen verplaatsen"</string>
- <string name="permdesc_movePackage" msgid="6323049291923925277">"Een toepassing toestaan toepassingsbronnen te verplaatsen van interne naar externe media en omgekeerd."</string>
+ <string name="permdesc_movePackage" msgid="6323049291923925277">"Een app toestaan app-bronnen te verplaatsen van interne naar externe media en omgekeerd."</string>
<string name="permlab_readLogs" msgid="6615778543198967614">"gevoelige logbestandsgegevens lezen"</string>
- <string name="permdesc_readLogs" msgid="8896449437464867766">"Hiermee kan een toepassing de verschillende logbestanden van het systeem lezen. De toepassing kan op deze manier algemene informatie achterhalen over uw telefoongebruik, mogelijk inclusief persoonlijke of privé-informatie."</string>
+ <string name="permdesc_readLogs" msgid="8896449437464867766">"Hiermee kan een app de verschillende logbestanden van het systeem lezen. De app kan op deze manier algemene informatie achterhalen over uw telefoongebruik, mogelijk inclusief persoonlijke of privé-informatie."</string>
<string name="permlab_diagnostic" msgid="8076743953908000342">"lezen/schrijven naar bronnen van diag"</string>
- <string name="permdesc_diagnostic" msgid="3121238373951637049">"Hiermee kan een toepassing lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of operator."</string>
+ <string name="permdesc_diagnostic" msgid="3121238373951637049">"Hiermee kan een app lezen en schrijven naar elke bron die hoort bij de diagnostische groep, zoals bestanden in /dev. Hierdoor kan de systeemstabiliteit en -veiligheid worden beïnvloed. Dit mag ALLEEN worden gebruikt voor hardwarespecifieke diagnostiek door de fabrikant of operator."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"toepassingscomponenten in- of uitschakelen"</string>
- <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Hiermee kan een toepassing bepalen of een component van een andere toepassing is ingeschakeld. Schadelijke toepassingen kunnen hiervan gebruik maken om belangrijke telefoonfuncties uit te schakelen. Een machtiging moet zorgvuldig worden overwogen, aangezien toepassingscomponenten onbruikbaar, inconsistent of instabiel kunnen worden."</string>
+ <string name="permdesc_changeComponentState" msgid="4569107043246700630">"Hiermee kan een app bepalen of een component van een andere app is ingeschakeld. Schadelijke apps kunnen hiervan gebruik maken om belangrijke telefoonfuncties uit te schakelen. Een machtiging moet zorgvuldig worden overwogen, aangezien app-componenten onbruikbaar, inconsistent of instabiel kunnen worden."</string>
<string name="permlab_setPreferredApplications" msgid="3393305202145172005">"voorkeurstoepassingen instellen"</string>
- <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Hiermee kan een toepassing uw voorkeurstoepassingen wijzigen. Schadelijke toepassingen kunnen op deze manier de actieve toepassingen zonder uw medeweten wijzigen en uw bestaande toepassingen doorzoeken om privégegevens van u te verzamelen."</string>
+ <string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Hiermee kan een app uw voorkeurs-apps wijzigen. Schadelijke apps kunnen op deze manier de actieve apps zonder uw medeweten wijzigen en uw bestaande apps doorzoeken om privégegevens van u te verzamelen."</string>
<string name="permlab_writeSettings" msgid="1365523497395143704">"algemene systeeminstellingen wijzigen"</string>
- <string name="permdesc_writeSettings" msgid="838789419871034696">"Hiermee kan een toepassing de systeeminstellingen wijzigen. Schadelijke toepassingen kunnen hiermee uw systeemconfiguratie beschadigen."</string>
+ <string name="permdesc_writeSettings" msgid="838789419871034696">"Hiermee kan een app de systeeminstellingen wijzigen. Schadelijke apps kunnen hiermee uw systeemconfiguratie beschadigen."</string>
<string name="permlab_writeSecureSettings" msgid="204676251876718288">"beveiligde systeeminstellingen wijzigen"</string>
- <string name="permdesc_writeSecureSettings" msgid="5497873143539034724">"Hiermee kan een toepassing beveiligde systeeminstellingen wijzigen. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permdesc_writeSecureSettings" msgid="5497873143539034724">"Hiermee kan een app beveiligde systeeminstellingen wijzigen. Niet voor gebruik door normale apps."</string>
<string name="permlab_writeGservices" msgid="2149426664226152185">"de Google-serviceskaart wijzigen"</string>
- <string name="permdesc_writeGservices" msgid="6602362746516676175">"Hiermee kan een toepassing de Google-serviceskaart wijzigen. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permdesc_writeGservices" msgid="6602362746516676175">"Hiermee kan een app de Google-serviceskaart wijzigen. Niet voor gebruik door normale apps."</string>
<string name="permlab_receiveBootCompleted" msgid="7776779842866993377">"automatisch starten bij opstarten"</string>
- <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Hiermee kan een toepassing zichzelf starten zodra het systeem klaar is met opstarten. Hierdoor kan het langer duren voordat de telefoon is opgestart en kan de toepassing de telefoonprocessen vertragen door altijd actief te zijn."</string>
+ <string name="permdesc_receiveBootCompleted" msgid="698336728415008796">"Hiermee kan een app zichzelf starten zodra het systeem klaar is met opstarten. Hierdoor kan het langer duren voordat de telefoon is opgestart en kan de app de telefoonprocessen vertragen door altijd actief te zijn."</string>
<string name="permlab_broadcastSticky" msgid="7919126372606881614">"sticky broadcast verzenden"</string>
- <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Hiermee kan een toepassing sticky broadcasts verzenden die achterblijven als de broadcast eindigt. Schadelijke toepassingen kunnen hiermee de telefoon traag of instabiel maken door ervoor te zorgen dat er te veel geheugenruimte wordt gebruikt."</string>
+ <string name="permdesc_broadcastSticky" msgid="1920045289234052219">"Hiermee kan een app sticky broadcasts verzenden die achterblijven als de broadcast eindigt. Schadelijke apps kunnen hiermee de telefoon traag of instabiel maken door ervoor te zorgen dat er te veel geheugenruimte wordt gebruikt."</string>
<string name="permlab_readContacts" msgid="6219652189510218240">"contactgegevens lezen"</string>
- <string name="permdesc_readContacts" msgid="3371591512896545975">"Hiermee kan een toepassing alle contactgegevens (adresgegevens) zien die op uw telefoon zijn opgeslagen. Schadelijke toepassingen kunnen hiervan gebruik maken om uw gegevens te verzenden naar andere personen."</string>
+ <string name="permdesc_readContacts" msgid="3371591512896545975">"Hiermee kan een app alle contactgegevens (adresgegevens) zien die op uw telefoon zijn opgeslagen. Schadelijke apps kunnen hiervan gebruik maken om uw gegevens te verzenden naar andere personen."</string>
<string name="permlab_writeContacts" msgid="644616215860933284">"contactgegevens schrijven"</string>
- <string name="permdesc_writeContacts" msgid="3924383579108183601">"Hiermee kan een toepassing de op uw telefoon opgeslagen contactgegevens (adresgegevens) wijzigen. Schadelijke toepassingen kunnen hiermee uw contactgegevens verwijderen of wijzigen."</string>
+ <string name="permdesc_writeContacts" msgid="3924383579108183601">"Hiermee kan een app de op uw telefoon opgeslagen contactgegevens (adresgegevens) wijzigen. Schadelijke apps kunnen hiermee uw contactgegevens verwijderen of wijzigen."</string>
<string name="permlab_readCalendar" msgid="6898987798303840534">"agendagebeurtenissen lezen"</string>
- <string name="permdesc_readCalendar" msgid="5533029139652095734">"Hiermee kan een toepassing alle agendagebeurtenissen lezen die zijn opgeslagen op uw telefoon. Schadelijke toepassingen kunnen hiervan gebruik maken om uw agendagebeurtenissen te verzenden naar andere personen."</string>
+ <string name="permdesc_readCalendar" msgid="5533029139652095734">"Hiermee kan een app alle agendagebeurtenissen lezen die zijn opgeslagen op uw telefoon. Schadelijke apps kunnen hiervan gebruik maken om uw agendagebeurtenissen te verzenden naar andere personen."</string>
<string name="permlab_writeCalendar" msgid="3894879352594904361">"agendagebeurtenissen toevoegen of aanpassen en e-mail verzenden naar gasten"</string>
- <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Een toepassing toestaan gebeurtenissen aan uw agenda toe te voegen of te wijzigen, wat inhoudt dat er e-mails kunnen worden verzonden naar gasten. Schadelijke toepassingen kunnen dit gebruiken om uw agendagebeurtenissen te wissen of aan te passen of om e-mail naar gasten te verzenden."</string>
+ <string name="permdesc_writeCalendar" msgid="2988871373544154221">"Een app toestaan gebeurtenissen aan uw agenda toe te voegen of te wijzigen, wat inhoudt dat er e-mails kunnen worden verzonden naar gasten. Schadelijke apps kunnen dit gebruiken om uw agendagebeurtenissen te wissen of aan te passen of om e-mail naar gasten te verzenden."</string>
<string name="permlab_accessMockLocation" msgid="8688334974036823330">"neplocatiebronnen voor test"</string>
<string name="permdesc_accessMockLocation" msgid="7648286063459727252">"Neplocatiebronnen voor testdoeleinden maken. Schadelijke toepassingen kunnen dit gebruiken om de locatie en/of status te overschrijven die door de echte locatiebronnen wordt aangegeven, zoals GPS of netwerkaanbieders."</string>
<string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"toegang tot extra opdrachten van locatieaanbieder"</string>
@@ -304,131 +304,135 @@
<string name="permlab_accessCoarseLocation" msgid="4642255009181975828">"globale (netwerkgebaseerde) locatie"</string>
<string name="permdesc_accessCoarseLocation" msgid="8235655958070862293">"Toegang tot globale locatiebronnen, zoals de mobiele netwerkdatabase om een globale telefoonlocatie te bepalen, indien beschikbaar. Schadelijke toepassingen kunnen hiervan gebruik maken om bij benadering te bepalen waar u zich bevindt."</string>
<string name="permlab_accessSurfaceFlinger" msgid="2363969641792388947">"toegang tot SurfaceFlinger"</string>
- <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Hiermee kan een toepassing SurfaceFlinger-functies op laag niveau gebruiken."</string>
+ <string name="permdesc_accessSurfaceFlinger" msgid="6805241830020733025">"Hiermee kan een app SurfaceFlinger-functies op laag niveau gebruiken."</string>
<string name="permlab_readFrameBuffer" msgid="6690504248178498136">"framebuffer lezen"</string>
- <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Hiermee kan een toepassing de inhoud van de framebuffer lezen."</string>
+ <string name="permdesc_readFrameBuffer" msgid="7530020370469942528">"Hiermee kan een app de inhoud van de framebuffer lezen."</string>
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"uw audio-instellingen wijzigen"</string>
- <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Hiermee kan een toepassing de algemene audio-instellingen, zoals volume en omleiding, wijzigen."</string>
+ <string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"Hiermee kan een app de algemene audio-instellingen, zoals volume en omleiding, wijzigen."</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"audio opnemen"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"Hiermee krijgt de toepassing toegang tot het audio-opnamepad."</string>
+ <string name="permdesc_recordAudio" msgid="6493228261176552356">"Hiermee krijgt de app toegang tot het audio-opnamepad."</string>
<string name="permlab_camera" msgid="3616391919559751192">"foto\'s en video\'s maken"</string>
- <string name="permdesc_camera" msgid="6004878235852154239">"Hiermee kan een toepassing foto\'s en video\'s maken met de camera. De toepassing kan op deze manier op elk gewenste moment beelden verzamelen van wat de camera ziet."</string>
+ <string name="permdesc_camera" msgid="6004878235852154239">"Hiermee kan een app foto\'s en video\'s maken met de camera. De app kan op deze manier op elk gewenste moment beelden verzamelen van wat de camera ziet."</string>
<string name="permlab_brick" msgid="8337817093326370537">"telefoon permanent uitschakelen"</string>
- <string name="permdesc_brick" msgid="5569526552607599221">"Hiermee kan de toepassing de telefoon permanent uitschakelen. Dit is erg gevaarlijk."</string>
+ <string name="permdesc_brick" msgid="5569526552607599221">"Hiermee kan de app de telefoon permanent uitschakelen. Dit is erg gevaarlijk."</string>
<string name="permlab_reboot" msgid="2898560872462638242">"telefoon nu opnieuw opstarten"</string>
- <string name="permdesc_reboot" msgid="7914933292815491782">"Hiermee kan de toepassing de telefoon nu opnieuw opstarten."</string>
+ <string name="permdesc_reboot" msgid="7914933292815491782">"Hiermee kan de app de telefoon nu opnieuw opstarten."</string>
<string name="permlab_mount_unmount_filesystems" msgid="1761023272170956541">"bestandssystemen koppelen en ontkoppelen"</string>
- <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Hiermee kan de toepassing bestandssystemen koppelen en ontkoppelen voor verwisselbare opslagruimte."</string>
+ <string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"Hiermee kan de app bestandssystemen koppelen en ontkoppelen voor verwisselbare opslagruimte."</string>
<string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"externe opslag formatteren"</string>
- <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Hiermee kan de toepassing de externe opslag formatteren."</string>
+ <string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"Hiermee kan de app de externe opslag formatteren."</string>
<string name="permlab_asec_access" msgid="3411338632002193846">"informatie over de interne opslag verkrijgen"</string>
- <string name="permdesc_asec_access" msgid="8820326551687285439">"Hiermee kan de toepassing informatie over de interne opslag verkrijgen."</string>
+ <string name="permdesc_asec_access" msgid="8820326551687285439">"Hiermee kan de app informatie over de interne opslag verkrijgen."</string>
<string name="permlab_asec_create" msgid="6414757234789336327">"interne opslag maken"</string>
- <string name="permdesc_asec_create" msgid="2621346764995731250">"Hiermee kan de toepassing interne opslag maken."</string>
+ <string name="permdesc_asec_create" msgid="2621346764995731250">"Hiermee kan de app interne opslag maken."</string>
<string name="permlab_asec_destroy" msgid="526928328301618022">"interne opslag vernietigen"</string>
- <string name="permdesc_asec_destroy" msgid="2746706889208066256">"Hiermee kan de toepassing de interne opslag vernietigen."</string>
+ <string name="permdesc_asec_destroy" msgid="2746706889208066256">"Hiermee kan de app de interne opslag vernietigen."</string>
<string name="permlab_asec_mount_unmount" msgid="2456287623689029744">"interne opslag koppelen/ontkoppelen"</string>
- <string name="permdesc_asec_mount_unmount" msgid="5934375590189368200">"Hiermee kan de toepassing de interne opslag koppelen/ontkoppelen."</string>
+ <string name="permdesc_asec_mount_unmount" msgid="5934375590189368200">"Hiermee kan de app de interne opslag koppelen/ontkoppelen."</string>
<string name="permlab_asec_rename" msgid="7496633954080472417">"naam van interne opslag wijzigen"</string>
- <string name="permdesc_asec_rename" msgid="2152829985238876790">"Hiermee kan de toepassing de naam van de interne opslag wijzigen."</string>
+ <string name="permdesc_asec_rename" msgid="2152829985238876790">"Hiermee kan de app de naam van de interne opslag wijzigen."</string>
<string name="permlab_vibrate" msgid="7768356019980849603">"trilstand beheren"</string>
- <string name="permdesc_vibrate" msgid="2886677177257789187">"Hiermee kan de toepassing de trilstand beheren."</string>
+ <string name="permdesc_vibrate" msgid="2886677177257789187">"Hiermee kan de app de trilstand beheren."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"zaklamp bedienen"</string>
- <string name="permdesc_flashlight" msgid="6433045942283802309">"Hiermee kan de toepassing de zaklamp bedienen."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"toegang krijgen tot USB-apparaten"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Hiermee kan de toepassing toegang krijgen tot USB-apparaten."</string>
+ <string name="permdesc_flashlight" msgid="6433045942283802309">"Hiermee kan de app de zaklamp bedienen."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"voorkeuren en rechten voor USB-apparaten beheren"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Hiermee kan de app voorkeuren en rechten voor USB-apparaten beheren."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"hardware testen"</string>
- <string name="permdesc_hardware_test" msgid="3668894686500081699">"Hiermee kan de toepassing verschillende randapparaten beheren om de hardware te testen."</string>
+ <string name="permdesc_hardware_test" msgid="3668894686500081699">"Hiermee kan de app verschillende randapparaten beheren om de hardware te testen."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefoonnummers rechtstreeks bellen"</string>
- <string name="permdesc_callPhone" msgid="3369867353692722456">"Hiermee kan de toepassing telefoonnummers bellen zonder uw tussenkomst. Door schadelijke toepassingen kunnen onverwachte oproepen op uw telefoonrekening verschijnen. De toepassing kan hiermee geen alarmnummers bellen."</string>
+ <string name="permdesc_callPhone" msgid="3369867353692722456">"Hiermee kan de app telefoonnummers bellen zonder uw tussenkomst. Door schadelijke apps kunnen onverwachte oproepen op uw telefoonrekening verschijnen. De app kan hiermee geen alarmnummers bellen."</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"alle telefoonnummers rechtstreeks bellen"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"Hiermee kan een toepassing elk telefoonnummer, inclusief alarmnummers, bellen zonder uw tussenkomst. Schadelijke toepassingen kunnen onnodige en illegale oproepen uitvoeren naar alarmdiensten."</string>
+ <string name="permdesc_callPrivileged" msgid="244405067160028452">"Hiermee kan een app elk telefoonnummer, inclusief alarmnummers, bellen zonder uw tussenkomst. Schadelijke apps kunnen onnodige en illegale oproepen uitvoeren naar alarmdiensten."</string>
<string name="permlab_performCdmaProvisioning" msgid="5604848095315421425">"meteen starten met CDMA-telefooninstelling"</string>
- <string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"Hiermee kan de toepassing starten met CDMA-provisioning. Schadelijke applicaties kunnen de CDMA-provisioning onnodig starten"</string>
+ <string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"Hiermee kan de app starten met CDMA-provisioning. Schadelijke apps kunnen de CDMA-provisioning onnodig starten"</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"meldingen over locatie-updates beheren"</string>
<string name="permdesc_locationUpdates" msgid="2300018303720930256">"Hiermee kunnen updatemeldingen voor locaties van de radio worden ingeschakeld/uitgeschakeld. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_checkinProperties" msgid="7855259461268734914">"toegang tot checkin-eigenschappen"</string>
<string name="permdesc_checkinProperties" msgid="7150307006141883832">"Hiermee wordt lees-/schrijftoegang gegeven tot eigenschappen die door de checkin-service zijn geüpload. Niet voor gebruik door normale toepassingen."</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"widgets kiezen"</string>
- <string name="permdesc_bindGadget" msgid="2098697834497452046">"Hiermee kan een toepassing het systeem melden welke widgets door welke toepassing kunnen worden gebruikt. Met deze toestemming kunnen toepassingen andere toepassingen toegang geven tot persoonlijke gegevens. Niet voor gebruik door normale toepassingen."</string>
+ <string name="permdesc_bindGadget" msgid="2098697834497452046">"Hiermee kan een app het systeem melden welke widgets door welke app kunnen worden gebruikt. Met deze toestemming kunnen apps andere apps toegang geven tot persoonlijke gegevens. Niet voor gebruik door normale apps."</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"telefoonstatus wijzigen"</string>
- <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Hiermee kan de toepassing de telefoonfuncties van het apparaat beheren. Een toepassing met deze machtiging kan schakelen tussen netwerken, de radio van de telefoon in- of uitschakelen en dergelijke zonder dat u hiervan op de hoogte wordt gesteld."</string>
+ <string name="permdesc_modifyPhoneState" msgid="3302284561346956587">"Hiermee kan de app de telefoonfuncties van het apparaat beheren. Een app met deze machtiging kan schakelen tussen netwerken, de radio van de telefoon in- of uitschakelen en dergelijke zonder dat u hiervan op de hoogte wordt gesteld."</string>
<string name="permlab_readPhoneState" msgid="2326172951448691631">"telefoonstatus en -identiteit lezen"</string>
- <string name="permdesc_readPhoneState" msgid="188877305147626781">"Hiermee krijgt de toepassing toegang tot de telefoonfuncties van het apparaat. Een toepassing met de betreffende machtiging kan het telefoonnummer en serienummer van deze telefoon achterhalen, bepalen of een oproep actief is, het gekozen nummer achterhalen en dergelijke."</string>
+ <string name="permdesc_readPhoneState" msgid="188877305147626781">"Hiermee krijgt de app toegang tot de telefoonfuncties van het apparaat. Een app met de betreffende machtiging kan het telefoonnummer en serienummer van deze telefoon achterhalen, bepalen of een oproep actief is, het gekozen nummer achterhalen en dergelijke."</string>
<string name="permlab_wakeLock" msgid="573480187941496130">"voorkomen dat telefoon overschakelt naar slaapmodus"</string>
- <string name="permdesc_wakeLock" msgid="7584036471227467099">"Hiermee kan een toepassing voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
+ <string name="permdesc_wakeLock" msgid="7584036471227467099">"Hiermee kan een app voorkomen dat de telefoon overschakelt naar de slaapmodus."</string>
<string name="permlab_devicePower" msgid="4928622470980943206">"telefoon in- of uitschakelen"</string>
- <string name="permdesc_devicePower" msgid="4577331933252444818">"Hiermee kan de toepassing de telefoon in- of uitschakelen."</string>
+ <string name="permdesc_devicePower" msgid="4577331933252444818">"Hiermee kan de app de telefoon in- of uitschakelen."</string>
<string name="permlab_factoryTest" msgid="3715225492696416187">"uitvoeren in fabriekstestmodus"</string>
<string name="permdesc_factoryTest" msgid="8136644990319244802">"Uitvoeren als fabrikanttest op laag niveau, waardoor toegang wordt gegeven tot de hardware van de telefoon. Alleen beschikbaar als een telefoon zich in de fabrikanttestmodus bevindt."</string>
<string name="permlab_setWallpaper" msgid="6627192333373465143">"achtergrond instellen"</string>
- <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Hiermee kan de toepassing de systeemachtergrond instellen."</string>
+ <string name="permdesc_setWallpaper" msgid="6417041752170585837">"Hiermee kan de app de systeemachtergrond instellen."</string>
<string name="permlab_setWallpaperHints" msgid="3600721069353106851">"grootte achtergrond instellen"</string>
- <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Hiermee kan de toepassing de grootte van de achtergrond instellen."</string>
+ <string name="permdesc_setWallpaperHints" msgid="6019479164008079626">"Hiermee kan de app de grootte van de achtergrond instellen."</string>
<string name="permlab_masterClear" msgid="2315750423139697397">"systeem terugzetten op fabrieksinstellingen"</string>
- <string name="permdesc_masterClear" msgid="5033465107545174514">"Hiermee kan een toepassing het systeem terugzetten op de fabrieksinstellingen, waarbij alle gegevens, configuraties en geïnstalleerde toepassingen worden verwijderd."</string>
+ <string name="permdesc_masterClear" msgid="5033465107545174514">"Hiermee kan een app het systeem terugzetten op de fabrieksinstellingen, waarbij alle gegevens, configuraties en geïnstalleerde apps worden verwijderd."</string>
<string name="permlab_setTime" msgid="2021614829591775646">"tijd instellen"</string>
- <string name="permdesc_setTime" msgid="667294309287080045">"Staat een toepassing toe de kloktijd van de telefoon te wijzigen."</string>
+ <string name="permdesc_setTime" msgid="667294309287080045">"Staat een app toe de kloktijd van de telefoon te wijzigen."</string>
<string name="permlab_setTimeZone" msgid="2945079801013077340">"tijdzone instellen"</string>
- <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Hiermee kan een toepassing de tijdzone van de telefoon wijzigen."</string>
+ <string name="permdesc_setTimeZone" msgid="1902540227418179364">"Hiermee kan een app de tijdzone van de telefoon wijzigen."</string>
<string name="permlab_accountManagerService" msgid="4829262349691386986">"fungeren als de AccountManagerService"</string>
- <string name="permdesc_accountManagerService" msgid="6056903274106394752">"Hiermee kan een toepassing aanroepen plaatsen naar AccountAuthenticators"</string>
+ <string name="permdesc_accountManagerService" msgid="6056903274106394752">"Hiermee kan een app aanroepen plaatsen naar AccountAuthenticators"</string>
<string name="permlab_getAccounts" msgid="4549918644233460103">"bekende accounts zoeken"</string>
- <string name="permdesc_getAccounts" msgid="6839262446413155394">"Hiermee kan een toepassing de lijst met accounts van een telefoon ophalen."</string>
+ <string name="permdesc_getAccounts" msgid="6839262446413155394">"Hiermee kan een app de lijst met accounts van een telefoon ophalen."</string>
<string name="permlab_authenticateAccounts" msgid="3940505577982882450">"fungeren als verificatie-instantie voor het account"</string>
- <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Hiermee kan een toepassing de mogelijkheden voor verificatie-instanties voor het account van de AccountManager gebruiken, waaronder het maken van accounts en het ophalen en instellen van de bijbehorende wachtwoorden."</string>
+ <string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Hiermee kan een app de mogelijkheden voor verificatie-instanties voor het account van de AccountManager gebruiken, waaronder het maken van accounts en het ophalen en instellen van de bijbehorende wachtwoorden."</string>
<string name="permlab_manageAccounts" msgid="4440380488312204365">"de lijst met accounts beheren"</string>
- <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Hiermee kan een toepassing bewerkingen uitvoeren, zoals het toevoegen en verwijderen van accounts en het verwijderen van de bijbehorende wachtwoorden."</string>
+ <string name="permdesc_manageAccounts" msgid="8804114016661104517">"Hiermee kan een app bewerkingen uitvoeren, zoals het toevoegen en verwijderen van accounts en het verwijderen van de bijbehorende wachtwoorden."</string>
<string name="permlab_useCredentials" msgid="6401886092818819856">"de verificatiegegevens van een account gebruiken"</string>
- <string name="permdesc_useCredentials" msgid="7416570544619546974">"Hiermee kan een toepassing verificatietokens aanvragen."</string>
+ <string name="permdesc_useCredentials" msgid="7416570544619546974">"Hiermee kan een app verificatietokens aanvragen."</string>
<string name="permlab_accessNetworkState" msgid="6865575199464405769">"netwerkstatus bekijken"</string>
- <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Hiermee kan een toepassing de status van alle netwerken bekijken."</string>
+ <string name="permdesc_accessNetworkState" msgid="558721128707712766">"Hiermee kan een app de status van alle netwerken bekijken."</string>
<string name="permlab_createNetworkSockets" msgid="9121633680349549585">"volledige internettoegang"</string>
- <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Hiermee kan een toepassing netwerksockets maken."</string>
+ <string name="permdesc_createNetworkSockets" msgid="4593339106921772192">"Hiermee kan een app netwerksockets maken."</string>
<string name="permlab_writeApnSettings" msgid="7823599210086622545">"instellingen voor toegangspuntnaam schrijven"</string>
- <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Hiermee kan een toepassing de APN-instellingen, zoals proxy en poort, van elke APN wijzigen."</string>
+ <string name="permdesc_writeApnSettings" msgid="7443433457842966680">"Hiermee kan een app de APN-instellingen, zoals proxy en poort, van elke APN wijzigen."</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"netwerkverbinding wijzigen"</string>
- <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Staat een toepassing toe de status van de netwerkverbinding te wijzigen."</string>
+ <string name="permdesc_changeNetworkState" msgid="4199958910396387075">"Staat een app toe de status van de netwerkverbinding te wijzigen."</string>
<string name="permlab_changeTetherState" msgid="2702121155761140799">"Getetherde verbinding wijzigen"</string>
- <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Staat een toepassing toe de status van de getetherde netwerkverbinding te wijzigen."</string>
+ <string name="permdesc_changeTetherState" msgid="8905815579146349568">"Staat een app toe de status van de getetherde netwerkverbinding te wijzigen."</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"instelling voor gebruik van achtergrondgegevens van gegevens wijzigen"</string>
- <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Hiermee kan een toepassing de instelling voor gebruik van achtergrondgegevens wijzigen."</string>
+ <string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"Hiermee kan een app de instelling voor gebruik van achtergrondgegevens wijzigen."</string>
<string name="permlab_accessWifiState" msgid="8100926650211034400">"Wi-Fi-status bekijken"</string>
- <string name="permdesc_accessWifiState" msgid="485796529139236346">"Hiermee kan een toepassing informatie over de Wi-Fi-status bekijken."</string>
+ <string name="permdesc_accessWifiState" msgid="485796529139236346">"Hiermee kan een app informatie over de Wi-Fi-status bekijken."</string>
<string name="permlab_changeWifiState" msgid="7280632711057112137">"Wi-Fi-status wijzigen"</string>
- <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Hiermee kan een toepassing zich koppelen aan en loskoppelen van Wi-Fi toegangspunten en wijzigingen aanbrengen in geconfigureerde Wi-Fi-netwerken."</string>
+ <string name="permdesc_changeWifiState" msgid="2950383153656873267">"Hiermee kan een app zich koppelen aan en loskoppelen van Wi-Fi toegangspunten en wijzigingen aanbrengen in geconfigureerde Wi-Fi-netwerken."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Wi-Fi Multicast-ontvangst toestaan"</string>
- <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Hiermee kan een toepassing pakketten ontvangen die niet rechtstreeks zijn geadresseerd aan uw apparaat. Dit kan handig zijn wanneer services in de buurt worden ontdekt. Dit verbruikt meer energie dan de niet-multicastmodus."</string>
+ <string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Hiermee kan een app pakketten ontvangen die niet rechtstreeks zijn geadresseerd aan uw apparaat. Dit kan handig zijn wanneer services in de buurt worden ontdekt. Dit verbruikt meer energie dan de niet-multicastmodus."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"WiMAX-status bekijken"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Hiermee kan een app informatie over de WiMAX-status bekijken."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"WiMAX-status wijzigen"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Hiermee kan een app verbinding maken met een WiMAX-netwerk en deze verbreken."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth-beheer"</string>
- <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Hiermee kan een toepassing de lokale Bluetooth-telefoon configureren en externe apparaten zoeken en aansluiten."</string>
+ <string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Hiermee kan een app de lokale Bluetooth-telefoon configureren en externe apparaten zoeken en aansluiten."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth-verbindingen maken"</string>
- <string name="permdesc_bluetooth" msgid="762515380679392945">"Hiermee kan een toepassing de configuratie van een lokale Bluetooth-telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
+ <string name="permdesc_bluetooth" msgid="762515380679392945">"Hiermee kan een app de configuratie van een lokale Bluetooth-telefoon bekijken en verbindingen met gekoppelde apparaten maken en accepteren."</string>
<string name="permlab_nfc" msgid="4423351274757876953">"Near Field Communication regelen"</string>
- <string name="permdesc_nfc" msgid="9171401851954407226">"Hiermee kan een toepassing communiceren met NFC-tags (Near Field Communication), kaarten en lezers."</string>
+ <string name="permdesc_nfc" msgid="9171401851954407226">"Hiermee kan een app communiceren met NFC-tags (Near Field Communication), kaarten en lezers."</string>
<string name="permlab_disableKeyguard" msgid="4977406164311535092">"toetsvergrendeling uitschakelen"</string>
- <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Hiermee kan een toepassing de toetsvergrendeling en bijbehorende wachtwoordbeveiliging uitschakelen. Een voorbeeld: de telefoon schakelt de toetsvergrendeling uit als er een oproep binnenkomt en schakelt de toetsvergrendeling weer in als de oproep is beëindigd."</string>
+ <string name="permdesc_disableKeyguard" msgid="3189763479326302017">"Hiermee kan een app de toetsvergrendeling en bijbehorende wachtwoordbeveiliging uitschakelen. Een voorbeeld: de telefoon schakelt de toetsvergrendeling uit wanneer een oproep binnenkomt en schakelt de toetsvergrendeling weer in zodra de oproep wordt beëindigd."</string>
<string name="permlab_readSyncSettings" msgid="6201810008230503052">"synchronisatie-instellingen lezen"</string>
- <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Hiermee kan een toepassing de synchronisatie-instellingen lezen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
+ <string name="permdesc_readSyncSettings" msgid="5315925706353341823">"Hiermee kan een app de synchronisatie-instellingen lezen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
<string name="permlab_writeSyncSettings" msgid="6297138566442486462">"synchronisatie-instellingen schrijven"</string>
- <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Hiermee kan een toepassing uw synchronisatie-instellingen wijzigen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
+ <string name="permdesc_writeSyncSettings" msgid="2498201614431360044">"Hiermee kan een app uw synchronisatie-instellingen wijzigen, bijvoorbeeld of de synchronisatie van contacten is ingeschakeld."</string>
<string name="permlab_readSyncStats" msgid="7396577451360202448">"synchronisatiestatistieken lezen"</string>
- <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Hiermee kan een toepassing de synchronisatiestatistieken lezen, zoals de geschiedenis van uitgevoerde synchronisaties."</string>
+ <string name="permdesc_readSyncStats" msgid="7511448343374465000">"Hiermee kan een app de synchronisatiestatistieken lezen, zoals de geschiedenis van uitgevoerde synchronisaties."</string>
<string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"geabonneerde feeds lezen"</string>
- <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Hiermee kan een toepassing details over de huidige gesynchroniseerde feeds achterhalen."</string>
+ <string name="permdesc_subscribedFeedsRead" msgid="3622200625634207660">"Hiermee kan een app details over de huidige gesynchroniseerde feeds achterhalen."</string>
<string name="permlab_subscribedFeedsWrite" msgid="9015246325408209296">"geabonneerde feeds schrijven"</string>
- <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Hiermee kan een toepassing uw huidige gesynchroniseerde feeds wijzigen. Een schadelijke toepassing kan op deze manier uw gesynchroniseerde feeds wijzigen."</string>
+ <string name="permdesc_subscribedFeedsWrite" msgid="8121607099326533878">"Hiermee kan een app uw huidige gesynchroniseerde feeds wijzigen. Een schadelijke app kan op deze manier uw gesynchroniseerde feeds wijzigen."</string>
<string name="permlab_readDictionary" msgid="432535716804748781">"door gebruiker gedefinieerd woordenboek lezen"</string>
- <string name="permdesc_readDictionary" msgid="1082972603576360690">"Hiermee kan een toepassing privéwoorden, namen en woordcombinaties lezen die de gebruiker heeft opgeslagen in het gebruikerswoordenboek."</string>
+ <string name="permdesc_readDictionary" msgid="1082972603576360690">"Hiermee kan een app privéwoorden, namen en woordcombinaties lezen die de gebruiker heeft opgeslagen in het gebruikerswoordenboek."</string>
<string name="permlab_writeDictionary" msgid="6703109511836343341">"schrijven naar door gebruiker gedefinieerd woordenboek"</string>
- <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Hiermee kan een toepassing nieuwe woorden schrijven naar het gebruikerswoordenboek."</string>
+ <string name="permdesc_writeDictionary" msgid="2241256206524082880">"Hiermee kan een app nieuwe woorden schrijven naar het gebruikerswoordenboek."</string>
<string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"inhoud van USB-opslag aanpassen/verwijderen"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"inhoud op de SD-kaart aanpassen/verwijderen"</string>
- <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Hiermee kan een toepassing schrijven naar de USB-opslag."</string>
- <string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Hiermee kan een toepassing schrijven naar de SD-kaart."</string>
+ <string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Hiermee kan een app schrijven naar de USB-opslag."</string>
+ <string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Hiermee kan een app schrijven naar de SD-kaart."</string>
<string name="permlab_cache_filesystem" msgid="5656487264819669824">"het cachebestandssysteem openen"</string>
- <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Staat een toepassing toe het cachebestandssysteem te lezen en te schrijven."</string>
+ <string name="permdesc_cache_filesystem" msgid="1624734528435659906">"Staat een app toe het cachebestandssysteem te lezen en te schrijven."</string>
<string name="permlab_use_sip" msgid="5986952362795870502">"internetoproepen starten/ontvangen"</string>
- <string name="permdesc_use_sip" msgid="6320376185606661843">"Hiermee kan een toepassing de SIP-service gebruiken om internetoproepen te starten/te ontvangen."</string>
+ <string name="permdesc_use_sip" msgid="6320376185606661843">"Hiermee kan een app de SIP-service gebruiken om internetoproepen te starten/te ontvangen."</string>
<string name="policylab_limitPassword" msgid="4497420728857585791">"Wachtwoordregels instellen"</string>
<string name="policydesc_limitPassword" msgid="9083400080861728056">"De lengte en tekens beheren die zijn toegestaan in wachtwoorden voor schermontgrendeling"</string>
<string name="policylab_watchLogin" msgid="914130646942199503">"Pogingen voor schermontgrendeling bijhouden"</string>
@@ -595,13 +599,13 @@
<string name="save_password_label" msgid="6860261758665825069">"Bevestigen"</string>
<string name="double_tap_toast" msgid="1068216937244567247">"Tip: tik tweemaal om in of uit te zoomen."</string>
<string name="permlab_readHistoryBookmarks" msgid="1284843728203412135">"browsergeschiedenis en bladwijzers lezen"</string>
- <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Hiermee kan een toepassing de URL\'s lezen die u via de browser heeft bezocht, evenals alle bladwijzers van de browser."</string>
+ <string name="permdesc_readHistoryBookmarks" msgid="4981489815467617191">"Hiermee kan een app de URL\'s lezen die u via de browser heeft bezocht, evenals alle bladwijzers van de browser."</string>
<string name="permlab_writeHistoryBookmarks" msgid="9009434109836280374">"browsergeschiedenis en bladwijzers schrijven"</string>
- <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Hiermee kan een toepassing de op uw telefoon opgeslagen browsergeschiedenis of bladwijzers wijzigen. Schadelijke toepassingen kunnen hiermee uw browsergegevens verwijderen of wijzigen."</string>
+ <string name="permdesc_writeHistoryBookmarks" msgid="945571990357114950">"Hiermee kan een app de op uw telefoon opgeslagen browsergeschiedenis of bladwijzers wijzigen. Schadelijke apps kunnen hiermee uw browsergegevens verwijderen of wijzigen."</string>
<string name="permlab_setAlarm" msgid="5924401328803615165">"alarm instellen in wekker"</string>
- <string name="permdesc_setAlarm" msgid="5966966598149875082">"Hiermee kan de toepassing een alarm instellen in een geïnstalleerde wekkertoepassing. Deze functie wordt door sommige wekkertoepassingen niet geïmplementeerd."</string>
+ <string name="permdesc_setAlarm" msgid="5966966598149875082">"Hiermee kan de app een alarm instellen in een geïnstalleerde wekker-app. Deze functie wordt door sommige wekker-apps niet geïmplementeerd."</string>
<string name="permlab_writeGeolocationPermissions" msgid="4715212655598275532">"Geolocatierechten voor browser aanpassen"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="4011908282980861679">"Staat een toepassing toe de geolocatierechten van de browser aan te passen. Schadelijke toepassingen kunnen dit gebruiken om locatiegegevens te verzenden naar willekeurige websites."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="4011908282980861679">"Staat een app toe de geolocatierechten van de browser aan te passen. Schadelijke apps kunnen dit gebruiken om locatiegegevens te verzenden naar willekeurige websites."</string>
<string name="save_password_message" msgid="767344687139195790">"Wilt u dat de browser dit wachtwoord onthoudt?"</string>
<string name="save_password_notnow" msgid="6389675316706699758">"Niet nu"</string>
<string name="save_password_remember" msgid="6491879678996749466">"Onthouden"</string>
@@ -733,31 +737,32 @@
<string name="alwaysUse" msgid="4583018368000610438">"Standaard gebruiken voor deze actie."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Wis standaardinstelling via startscherm: \'Instellingen\' &gt; \'Toepassingen\' &gt; \'Toepassingen beheren\'."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Een actie selecteren"</string>
- <string name="noApplications" msgid="1691104391758345586">"Geen enkele toepassing kan deze actie uitvoeren."</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Selecteer een app voor het USB-apparaat"</string>
+ <string name="noApplications" msgid="1691104391758345586">"Geen enkele app kan deze actie uitvoeren."</string>
<string name="aerr_title" msgid="653922989522758100">"Helaas!"</string>
- <string name="aerr_application" msgid="4683614104336409186">"De toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) is onverwachts gestopt. Probeer het opnieuw."</string>
+ <string name="aerr_application" msgid="4683614104336409186">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) is onverwachts gestopt. Probeer het opnieuw."</string>
<string name="aerr_process" msgid="1551785535966089511">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> is onverwachts gestopt. Probeer het opnieuw."</string>
<string name="anr_title" msgid="3100070910664756057">"Helaas!"</string>
- <string name="anr_activity_application" msgid="3538242413112507636">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in toepassing <xliff:g id="APPLICATION">%2$s</xliff:g>) reageert niet."</string>
+ <string name="anr_activity_application" msgid="3538242413112507636">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in app <xliff:g id="APPLICATION">%2$s</xliff:g>) reageert niet."</string>
<string name="anr_activity_process" msgid="5420826626009561014">"Activiteit <xliff:g id="ACTIVITY">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
- <string name="anr_application_process" msgid="4185842666452210193">"Toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
+ <string name="anr_application_process" msgid="4185842666452210193">"App <xliff:g id="APPLICATION">%1$s</xliff:g> (in proces <xliff:g id="PROCESS">%2$s</xliff:g>) reageert niet."</string>
<string name="anr_process" msgid="1246866008169975783">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> reageert niet."</string>
<string name="force_close" msgid="3653416315450806396">"Nu sluiten"</string>
<string name="report" msgid="4060218260984795706">"Rapport"</string>
<string name="wait" msgid="7147118217226317732">"Wachten"</string>
- <string name="launch_warning_title" msgid="8323761616052121936">"Toepassing omgeleid"</string>
+ <string name="launch_warning_title" msgid="8323761616052121936">"App omgeleid"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> is nu actief."</string>
<string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> was het eerst gestart."</string>
- <string name="smv_application" msgid="295583804361236288">"De toepassing <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
+ <string name="smv_application" msgid="295583804361236288">"De app <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
<string name="smv_process" msgid="5120397012047462446">"Het proces <xliff:g id="PROCESS">%1$s</xliff:g> heeft het zelf afgedwongen StrictMode-beleid geschonden."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> wordt uitgevoerd"</string>
- <string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Selecteren om over te schakelen naar toepassing"</string>
+ <string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Selecteren om over te schakelen naar app"</string>
<string name="heavy_weight_switcher_title" msgid="1135403633766694316">"Toepassingen wijzigen?"</string>
- <string name="heavy_weight_switcher_text" msgid="4592075610079319667">"Er wordt al een andere toepassing uitgevoerd die moet worden gestopt voordat u een nieuwe toepassing kunt starten."</string>
+ <string name="heavy_weight_switcher_text" msgid="4592075610079319667">"Er wordt al een andere app uitgevoerd die moet worden gestopt voordat u een nieuwe app kunt starten."</string>
<string name="old_app_action" msgid="493129172238566282">"Terug naar <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
- <string name="old_app_description" msgid="942967900237208466">"De nieuwe toepassing niet starten."</string>
+ <string name="old_app_description" msgid="942967900237208466">"De nieuwe app niet starten."</string>
<string name="new_app_action" msgid="5472756926945440706">"<xliff:g id="OLD_APP">%1$s</xliff:g> starten"</string>
- <string name="new_app_description" msgid="6830398339826789493">"De oude toepassing stoppen zonder opslaan."</string>
+ <string name="new_app_description" msgid="6830398339826789493">"De oude app stoppen zonder opslaan."</string>
<string name="sendText" msgid="5132506121645618310">"Selecteer een actie voor tekst"</string>
<string name="volume_ringtone" msgid="6885421406845734650">"Belvolume"</string>
<string name="volume_music" msgid="5421651157138628171">"Mediavolume"</string>
@@ -782,7 +787,7 @@
<item quantity="other" msgid="7915895323644292768">"Open Wi-Fi-netwerken beschikbaar"</item>
</plurals>
<string name="select_character" msgid="3365550120617701745">"Teken invoegen"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Onbekende toepassing"</string>
+ <string name="sms_control_default_app_name" msgid="7630529934366549163">"Onbekende app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"SMS-berichten verzenden"</string>
<string name="sms_control_message" msgid="1289331457999236205">"Er wordt een groot aantal SMS-berichten verzonden. Selecteer \'OK\' om door te gaan of \'Annuleren\' om de verzending te stoppen."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index de72e8c..a70bcbf 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -50,7 +50,7 @@
<string name="needPuk2" msgid="4526033371987193070">"Wprowadź kod PUK2, aby odblokować kartę SIM."</string>
<string name="ClipMmi" msgid="6952821216480289285">"Identyfikator rozmówcy przy połączeniach przychodzących"</string>
<string name="ClirMmi" msgid="7784673673446833091">"Identyfikator rozmówcy przy połączeniach wychodzących"</string>
- <string name="CfMmi" msgid="5123218989141573515">"Przekierowania połączeń"</string>
+ <string name="CfMmi" msgid="5123218989141573515">"Przekazywanie połączeń"</string>
<string name="CwMmi" msgid="9129678056795016867">"Połączenia oczekujące"</string>
<string name="BaMmi" msgid="455193067926770581">"Blokada dzwonienia"</string>
<string name="PwdMmi" msgid="7043715687905254199">"Zmiana hasła"</string>
@@ -241,8 +241,8 @@
<string name="permdesc_injectEvents" msgid="3946098050410874715">"Pozwala aplikacjom na dostarczanie własnych zdarzeń wprowadzania danych (naciśnięcie klawisza itp.) do innych aplikacji. Szkodliwe aplikacje mogą to wykorzystać do przejęcia kontroli nad telefonem."</string>
<string name="permlab_readInputState" msgid="469428900041249234">"zapamiętywanie wpisywanych znaków oraz wykonywanych czynności"</string>
<string name="permdesc_readInputState" msgid="5132879321450325445">"Pozwala aplikacjom na śledzenie naciskanych klawiszy, nawet podczas pracy z innym programem (na przykład podczas wpisywania hasła). Nigdy nie powinno być potrzebne normalnym aplikacjom."</string>
- <string name="permlab_bindInputMethod" msgid="3360064620230515776">"tworzenie powiązania z metodą wejściową"</string>
- <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Pozwala na tworzenie powiązania z interfejsem najwyższego poziomu metody wejściowej. To uprawnienie nie powinno być nigdy wymagane przez zwykłe aplikacje."</string>
+ <string name="permlab_bindInputMethod" msgid="3360064620230515776">"powiązanie ze sposobem wprowadzania tekstu"</string>
+ <string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Pozwala na powiązanie wybranego sposobu wprowadzania tekstu z interfejsem najwyższego poziomu. To uprawnienie nie powinno być nigdy wymagane przez zwykłe aplikacje."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"powiązanie z tapetą"</string>
<string name="permdesc_bindWallpaper" msgid="5287754520361915347">"Umożliwia posiadaczowi powiązać interfejs najwyższego poziomu dla tapety. Nie powinno być nigdy potrzebne w przypadku zwykłych aplikacji."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"interakcja z administratorem urządzenia"</string>
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Pozwala aplikacjom na kontrolowanie wibracji."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"kontrolowanie latarki"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Pozwala aplikacji kontrolować latarkę."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"dostęp do urządzeń USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Zezwala aplikacji na dostęp do urządzeń USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"zarządzanie ustawieniami i uprawnieniami urządzeń USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Umożliwia aplikacji zarządzanie ustawieniami i uprawnieniami urządzeń USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testowanie sprzętu"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Pozwala aplikacji na kontrolowanie różnych urządzeń peryferyjnych w celu testowania sprzętu."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"bezpośrednie wybieranie numerów telefonów"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Pozwala aplikacji na łączenie i rozłączanie z punktami dostępowymi Wi-Fi oraz na dokonywanie zmian skonfigurowanych sieci Wi-Fi."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"zezwolenie na odbiór grupowych połączeń Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Umożliwia aplikacji odbieranie pakietów nieskierowanych bezpośrednio do Twojego urządzenia. Może to być przydatne przy wykrywaniu usług oferowanych w okolicy. Powoduje większe zapotrzebowanie na energię niż w trybie innym niż grupowy."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"wyświetlanie stanu WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Zezwala aplikacji na dostęp do informacji o stanie połączenia WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"zmiana stanu WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Zezwala aplikacji na łączenie się i rozłączanie z siecią WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administrowanie Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Pozwala aplikacji na konfigurowanie lokalnego telefonu Bluetooth, wyszukiwanie urządzeń zdalnych i łączenie się z nimi."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"tworzenie połączeń Bluetooth"</string>
@@ -717,7 +721,7 @@
<string name="copy" msgid="2681946229533511987">"Kopiuj"</string>
<string name="paste" msgid="5629880836805036433">"Wklej"</string>
<string name="copyUrl" msgid="2538211579596067402">"Kopiuj adres URL"</string>
- <string name="inputMethod" msgid="1653630062304567879">"Metoda wprowadzania"</string>
+ <string name="inputMethod" msgid="1653630062304567879">"Sposób wprowadzania tekstu"</string>
<string name="addToDictionary" msgid="8793624991686948709">"Dodaj termin „<xliff:g id="WORD">%s</xliff:g>” do słownika"</string>
<string name="editTextMenuTitle" msgid="1672989176958581452">"Edytuj tekst"</string>
<string name="low_internal_storage_view_title" msgid="1399732408701697546">"Mało miejsca"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Używaj domyślnie dla tej czynności."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Wyczyść domyślne w: Ustawienia strony głównej &gt; Aplikacje &gt; Zarządzaj aplikacjami."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Wybierz czynność"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Wybierz aplikację dla urządzenia USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Żadna z aplikacji nie może wykonać tej czynności."</string>
<string name="aerr_title" msgid="653922989522758100">"Przepraszamy!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Aplikacja <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) została niespodziewanie zatrzymana. Spróbuj ponownie."</string>
@@ -819,7 +824,7 @@
<string name="extmedia_format_button_format" msgid="4131064560127478695">"Formatuj"</string>
<string name="adb_active_notification_title" msgid="6729044778949189918">"Podłączono moduł debugowania USB"</string>
<string name="adb_active_notification_message" msgid="8470296818270110396">"Wybierz, aby wyłączyć debugowanie USB."</string>
- <string name="select_input_method" msgid="6865512749462072765">"Wybierz metodę wprowadzania"</string>
+ <string name="select_input_method" msgid="6865512749462072765">"Wybierz sposób wprowadzania tekstu"</string>
<string name="fast_scroll_alphabet" msgid="5433275485499039199">" AĄBCĆDEĘFGHIJKLŁMNŃOÓPQRSŚTUVWXYZŹŻ"</string>
<string name="fast_scroll_numeric_alphabet" msgid="4030170524595123610">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string>
<string name="candidates_style" msgid="4333913089637062257"><u>"kandydaci"</u></string>
@@ -870,7 +875,7 @@
<string name="deny" msgid="2081879885755434506">"Odmów"</string>
<string name="permission_request_notification_title" msgid="5390555465778213840">"Żądane pozwolenie"</string>
<string name="permission_request_notification_with_subtitle" msgid="4325409589686688000">"Prośba o pozwolenie"\n"dotyczące konta <xliff:g id="ACCOUNT">%s</xliff:g>"</string>
- <string name="input_method_binding_label" msgid="1283557179944992649">"Metoda wprowadzania"</string>
+ <string name="input_method_binding_label" msgid="1283557179944992649">"Sposób wprowadzania tekstu"</string>
<string name="sync_binding_label" msgid="3687969138375092423">"Synchronizacja"</string>
<string name="accessibility_binding_label" msgid="4148120742096474641">"Ułatwienia dostępu"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Tapeta"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 3a8759a..e272223 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Permite à aplicação controlar o vibrador."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Permite à aplicação controlar a lanterna."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"aceder a dispositivos USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permite à aplicação aceder a dispositivos USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"gerir preferências e permissões para dispositivos USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permite à aplicação gerir as preferências e permissões para dispositivos USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testar hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite à aplicação controlar vários periféricos para fins de teste de hardware."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone directamente"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite a uma aplicação ligar e desligar de pontos de acesso de Wi-Fi, bem como efectuar alterações a redes Wi-Fi configuradas."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recepção Multicast Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite que uma aplicação receba pacotes não enviados directamente para o dispositivo. Esta opção pode ser útil para descobrir serviços oferecidos na vizinhança. Utiliza mais energia do que o modo não multicast."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"ver estado do WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Permite a uma aplicação ver as informações acerca do estado do Wi-Fi."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"alterar estado do WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Permite a uma aplicação ligar-se e desligar-se da rede WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administração de Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permite a uma aplicação configurar o telefone Bluetooth local, bem como descobrir e emparelhar com dispositivos remotos."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"criar ligações Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Utilizar por predefinição para esta acção."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Limpar predefinição em Definições iniciais &gt; Aplicações &gt; Gerir aplicações."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Seleccionar uma acção"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Selecione uma aplicação para o dispositivo USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Nenhuma aplicação pode efectuar esta acção."</string>
<string name="aerr_title" msgid="653922989522758100">"Lamentamos."</string>
<string name="aerr_application" msgid="4683614104336409186">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou de forma inesperada. Tente novamente."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 5926941..726a64e 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Permite que o aplicativo controle o vibrador."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Permite que o aplicativo controle a lanterna."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"acessar dispositivos USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permitir que o aplicativo acesse dispositivos USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"gerenciar preferências e permissões de aplicativos USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permite que o aplicativo gerencie as preferências e as permissões de aplicativos USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testar hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite que o aplicativo controle diversos periféricos para teste do hardware."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"chamar diretamente os números de telefone"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite que um aplicativo se conecte e desconecte dos pontos de acesso Wi-Fi e faça alterações nas redes Wi-Fi configuradas."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitir recebimento de multicast Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite que um aplicativo receba pacotes não endereçados diretamente para o seu aparelho. Isso pode ser útil ao detectar os serviços oferecidos nas proximidades. Ele consome mais energia do que o modo não-multicast."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"visualizar estado do WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Permite que um aplicativo veja as informações sobre o estado do WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"alterar estado do WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Permite que um aplicativo seja conectado e desconectado à uma rede WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administração de Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permite que um aplicativo configure o telefone Bluetooth local, descubra e pareie com dispositivos remotos."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"criar conexões Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Usar como padrão para esta ação."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Limpar o padrão em Configurações da página inicial &gt; Aplicativos &gt; Gerenciar aplicativos."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Selecionar uma ação"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Selecione um aplicativo para o dispositivo USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Nenhum aplicativo pode realizar esta ação."</string>
<string name="aerr_title" msgid="653922989522758100">"Desculpe!"</string>
<string name="aerr_application" msgid="4683614104336409186">"O aplicativo <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) parou inesperadamente. Tente novamente."</string>
diff --git a/core/res/res/values-rm/strings.xml b/core/res/res/values-rm/strings.xml
index de4b04b..090661b 100644
--- a/core/res/res/values-rm/strings.xml
+++ b/core/res/res/values-rm/strings.xml
@@ -336,8 +336,10 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Permetta a l\'applicaziun da controllar la vibraziun."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"controllar la glischina"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Permetta a l\'applicaziun da controllar la glischina."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"acceder ad apparats USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permetta a l\'applicaziun dad acceder als apparats periferics USB."</string>
+ <!-- no translation found for permlab_manageUsb (1113453430645402723) -->
+ <skip />
+ <!-- no translation found for permdesc_manageUsb (6148489202092166164) -->
+ <skip />
<string name="permlab_hardware_test" msgid="4148290860400659146">"testar la hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Permetta ad ina applicaziun da controllar differents apparats periferics per motivs da test da hardware."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefonar directamain a numers da telefon"</string>
@@ -400,6 +402,14 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"\"Permetta ad ina applicaziun da stabilir ina connexiun a puncts d\'access WLAN, da sa deconnectar da quels e da modifitgar ils parameters da raits WLAN configuradas.\""</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permetter la recepziun da multicast WLAN"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permetta ad ina applicaziun da retschaiver pachets da datas che n\'èn betg adressads directamain a Voss apparat. Quai po esser nizzaivel per tschertgar servetschs che vegnan mess a disposiziun en il conturn. Consumescha dapli energia ch\'il modus betg-multicast."</string>
+ <!-- no translation found for permlab_accessWimaxState (2800410363171809280) -->
+ <skip />
+ <!-- no translation found for permdesc_accessWimaxState (8298035866227524023) -->
+ <skip />
+ <!-- no translation found for permlab_changeWimaxState (340465839241528618) -->
+ <skip />
+ <!-- no translation found for permdesc_changeWimaxState (474918005058989421) -->
+ <skip />
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administraziun bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"\"Permetta ad ina applicaziun da configurar il telefon bluetooth local, dad identifitgar apparats periferics a distanza e d\'als associar cun il telefon.\""</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"stabilir connexiuns bluetooth"</string>
@@ -745,6 +755,8 @@
<string name="alwaysUse" msgid="4583018368000610438">"Utilisar questa applicaziun sco standard per questa acziun."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Stizzar ils parameters da standard en Parameters da la pagina da partenza &gt; Applicaziuns &gt; Administrar las applicaziuns."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Tscherner ina acziun"</string>
+ <!-- no translation found for chooseUsbActivity (7892597146032121735) -->
+ <skip />
<string name="noApplications" msgid="1691104391758345586">"Nagina applicaziun po exequir questa acziun."</string>
<string name="aerr_title" msgid="653922989522758100">"Perstgisai!"</string>
<string name="aerr_application" msgid="4683614104336409186">"L\'applicaziun <xliff:g id="APPLICATION">%1$s</xliff:g> (process <xliff:g id="PROCESS">%2$s</xliff:g>) è vegnida serrada nunspetgadamain. Empruvai anc ina giada."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index c58e2fb..7b50b2e 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Permite aplicaţiei să controleze mecanismul de vibrare."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"control lanternă"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Permite aplicaţiei să controleze lanterna."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"accesare dispozitive USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Permite aplicaţiei să acceseze dispozitive USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"gestionaţi preferinţele şi permisiunile pentru dispozitivele USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Permite aplicaţiei să gestioneze preferinţele şi permisiunile pentru dispozitivele USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testare hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Permite aplicaţiei să controleze diverse periferice în scopul testării componentelor hardware."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"apelare directă numere de telefon"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Permite unei aplicaţii să se conecteze la şi să se deconecteze de la punctele de acces Wi-Fi, precum şi să efectueze modificări în reţelele Wi-Fi configurate."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"permitere recepţionare difuzare multiplă Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Permite unei aplicaţii să primească pachete care nu sunt direct adresate dispozitivului dvs. Această permisiune poate fi utilă la descoperirea serviciilor oferite în apropiere. Consumă mai multă energie decât modul fără difuzare multiplă."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"vizualizaţi starea WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Permite unei aplicaţii să vizualizeze informaţiile despre starea WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"schimbaţi starea WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Permite unei aplicaţii să se conecteze şi să se deconecteze de la reţeaua WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administrare bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Permite unei aplicaţii să configureze telefonul Bluetooth local, să descopere şi să se asocieze cu dispozitive la distanţă."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"creare conexiuni Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Se utilizează în mod prestabilit pentru această acţiune."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Ştergeţi setările prestabilite din Setări pagină de pornire &gt; Aplicaţii &gt; Gestionare aplicaţii."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Selectaţi o acţiune"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Selectaţi o aplicaţie pentru dispozitivul USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Această acţiune nu poate fi efectuată de nicio aplicaţie."</string>
<string name="aerr_title" msgid="653922989522758100">"Ne pare rău!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) s-a oprit în mod neaşteptat. Încercaţi din nou."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index dc095c5..447c856 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Позволяет приложению управлять виброзвонком."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"управлять вспышкой"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Позволяет приложению управлять вспышкой."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"доступ к USB-устройствам"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Позволяет приложению получать доступ к USB-устройствам."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"управлять настройками и разрешениями для USB-устройств"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Приложение может управлять настройками и разрешениями для USB-устройств."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"проверять аппаратное обеспечение"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Позволяет приложению управлять различными периферийными устройствами для проверки аппаратного обеспечения."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"посылать прямые вызовы на номера телефонов"</string>
@@ -379,7 +379,7 @@
<string name="permdesc_authenticateAccounts" msgid="4006839406474208874">"Разрешает приложению использовать возможности аутентификации диспетчера аккаунта, в том числе создавать аккаунты, получать и устанавливать пароли для них."</string>
<string name="permlab_manageAccounts" msgid="4440380488312204365">"управление списком аккаунтов"</string>
<string name="permdesc_manageAccounts" msgid="8804114016661104517">"Разрешает приложению добавлять и удалять аккаунты и стирать их пароли."</string>
- <string name="permlab_useCredentials" msgid="6401886092818819856">"использование регистрационных данных аккаунта для аутентификации"</string>
+ <string name="permlab_useCredentials" msgid="6401886092818819856">"использование учетных данных аккаунта для аутентификации"</string>
<string name="permdesc_useCredentials" msgid="7416570544619546974">"Разрешает приложению запрашивать маркеры аутентификации."</string>
<string name="permlab_accessNetworkState" msgid="6865575199464405769">"просматривать состояние сети"</string>
<string name="permdesc_accessNetworkState" msgid="558721128707712766">"Позволяет приложению просматривать состояние всех сетей."</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Позволяет приложению подключаться к точкам доступа Wi-Fi и отключаться от них, а также вносить изменения в конфигурацию сетей Wi-Fi."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"разрешить принимать многоадресный сигнал Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Разрешает приложению получать пакеты, не адресованные напрямую вашему устройству. Это может быть полезно при поиске находящихся рядом служб. Расход заряда батареи при этом выше, чем при одноадресной передаче."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"получать сведения о состоянии WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Позволяет приложению получать сведения о состоянии WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"изменять состояние WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Позволяет приложению подключаться к сети WiMAX и отключаться от нее."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"управление Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Позволяет приложению настраивать локальный телефон Bluetooth, обнаруживать и выполнять сопряжение удаленных устройств."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"создавать подключения Bluetooth"</string>
@@ -421,7 +425,7 @@
<string name="permdesc_readDictionary" msgid="1082972603576360690">"Позволяет приложению считывать любые слова, имена и фразы личного пользования, которые могут храниться в пользовательском словаре."</string>
<string name="permlab_writeDictionary" msgid="6703109511836343341">"записывать в словарь пользователя"</string>
<string name="permdesc_writeDictionary" msgid="2241256206524082880">"Позволяет приложению записывать новые слова в словарь пользователя."</string>
- <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"изменять и удалять содержимое USB-накопителя"</string>
+ <string name="permlab_sdcardWrite" product="nosdcard" msgid="85430876310764752">"изм./удал. содерж. накопителя"</string>
<string name="permlab_sdcardWrite" product="default" msgid="8079403759001777291">"изменять/удалять содержимое SD-карты"</string>
<string name="permdesc_sdcardWrite" product="nosdcard" msgid="6594393334785738252">"Разрешает приложению запись на USB-накопитель."</string>
<string name="permdesc_sdcardWrite" product="default" msgid="6643963204976471878">"Разрешает приложению запись на SD-карту"</string>
@@ -547,13 +551,13 @@
<string name="lockscreen_screen_locked" msgid="7288443074806832904">"Экран заблокирован."</string>
<string name="lockscreen_instructions_when_pattern_enabled" msgid="46154051614126049">"Нажмите \"Меню\", чтобы разблокировать экран или вызвать службу экстренной помощи."</string>
<string name="lockscreen_instructions_when_pattern_disabled" msgid="686260028797158364">"Для разблокировки нажмите \"Меню\"."</string>
- <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Для разблокировки введите графический ключ"</string>
+ <string name="lockscreen_pattern_instructions" msgid="7478703254964810302">"Введите графический ключ"</string>
<string name="lockscreen_emergency_call" msgid="5347633784401285225">"Экстренный вызов"</string>
<string name="lockscreen_return_to_call" msgid="5244259785500040021">"Вернуться к вызову"</string>
<string name="lockscreen_pattern_correct" msgid="9039008650362261237">"Правильно!"</string>
<string name="lockscreen_pattern_wrong" msgid="4817583279053112312">"Повторите попытку"</string>
<string name="lockscreen_plugged_in" msgid="613343852842944435">"Идет зарядка (<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>)"</string>
- <string name="lockscreen_charged" msgid="4938930459620989972">"Заряжена."</string>
+ <string name="lockscreen_charged" msgid="4938930459620989972">"Батарея заряжена"</string>
<string name="lockscreen_battery_short" msgid="3617549178603354656">"<xliff:g id="NUMBER">%d</xliff:g><xliff:g id="PERCENT">%%</xliff:g>"</string>
<string name="lockscreen_low_battery" msgid="1482873981919249740">"Подключите зарядное устройство."</string>
<string name="lockscreen_missing_sim_message_short" msgid="7381499217732227295">"Нет SIM-карты."</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"По умолчанию для этого действия"</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Удалить настройки по умолчанию: главный экран &gt; \"Настройки\" &gt; \"Приложения\" &gt; \"Управление приложениями\"."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Выберите действие"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Выбор приложения для USB-устройства"</string>
<string name="noApplications" msgid="1691104391758345586">"Это действие не может выполнять ни одно приложение."</string>
<string name="aerr_title" msgid="653922989522758100">"Ошибка приложения!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Произошла неожиданная остановка приложения <xliff:g id="APPLICATION">%1$s</xliff:g> (процесс <xliff:g id="PROCESS">%2$s</xliff:g>). Повторите попытку."</string>
@@ -743,7 +748,7 @@
<string name="anr_application_process" msgid="4185842666452210193">"Приложение <xliff:g id="APPLICATION">%1$s</xliff:g> (в процессе <xliff:g id="PROCESS">%2$s</xliff:g>) не отвечает."</string>
<string name="anr_process" msgid="1246866008169975783">"Процесс <xliff:g id="PROCESS">%1$s</xliff:g> не отвечает."</string>
<string name="force_close" msgid="3653416315450806396">"Закрыть"</string>
- <string name="report" msgid="4060218260984795706">"Отчет"</string>
+ <string name="report" msgid="4060218260984795706">"Отзыв"</string>
<string name="wait" msgid="7147118217226317732">"Подождать"</string>
<string name="launch_warning_title" msgid="8323761616052121936">"Приложение перенаправлено"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"Приложение <xliff:g id="APP_NAME">%1$s</xliff:g> выполняется."</string>
@@ -834,7 +839,7 @@
<string name="ext_media_unmountable_notification_title" product="default" msgid="6410723906019100189">"Поврежденная карта SD"</string>
<string name="ext_media_unmountable_notification_message" product="nosdcard" msgid="529021299294450667">"USB-накопитель поврежден. Попробуйте отформатировать его."</string>
<string name="ext_media_unmountable_notification_message" product="default" msgid="6902531775948238989">"SD-карта повреждена. Попробуйте отформатировать ее."</string>
- <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"USB-накопитель неожиданно отключен"</string>
+ <string name="ext_media_badremoval_notification_title" product="nosdcard" msgid="1661683031330951073">"Накопитель неожиданно отключен"</string>
<string name="ext_media_badremoval_notification_title" product="default" msgid="6872152882604407837">"Карта SD неожиданно извлечена"</string>
<string name="ext_media_badremoval_notification_message" product="nosdcard" msgid="4329848819865594241">"Перед извлечением USB-накопителя отключите его во избежание потери данных."</string>
<string name="ext_media_badremoval_notification_message" product="default" msgid="7260183293747448241">"Перед извлечением карты SD отключите ее во избежание потери данных."</string>
@@ -874,17 +879,17 @@
<string name="sync_binding_label" msgid="3687969138375092423">"Синхр."</string>
<string name="accessibility_binding_label" msgid="4148120742096474641">"Спец. возможности"</string>
<string name="wallpaper_binding_label" msgid="1240087844304687662">"Фоновый рисунок"</string>
- <string name="chooser_wallpaper" msgid="7873476199295190279">"Изменить фоновый рисунок"</string>
+ <string name="chooser_wallpaper" msgid="7873476199295190279">"Сменить обои"</string>
<string name="pptp_vpn_description" msgid="2688045385181439401">"Протокол PPTP"</string>
<string name="l2tp_vpn_description" msgid="3750692169378923304">"Протокол L2TP"</string>
- <string name="l2tp_ipsec_psk_vpn_description" msgid="3945043564008303239">"L2TP/IPSec VPN (на основе предв. общ. ключа)"</string>
- <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"L2TP/IPSec VPN (на основе сертификата)"</string>
+ <string name="l2tp_ipsec_psk_vpn_description" msgid="3945043564008303239">"L2TP/IPSec VPN с использованием общего ключа"</string>
+ <string name="l2tp_ipsec_crt_vpn_description" msgid="5382714073103653577">"L2TP/IPSec VPN с использованием сертификатов"</string>
<string name="upload_file" msgid="2897957172366730416">"Выбрать файл"</string>
<string name="reset" msgid="2448168080964209908">"Сбросить"</string>
<string name="submit" msgid="1602335572089911941">"Отправить"</string>
<string name="description_star" msgid="2654319874908576133">"избранное"</string>
- <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Режим громкой связи включен"</string>
- <string name="car_mode_disable_notification_message" msgid="668663626721675614">"Выберите для выхода из режима громкой связи."</string>
+ <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Включен режим \"Штурман\""</string>
+ <string name="car_mode_disable_notification_message" msgid="668663626721675614">"Чтобы закрыть приложение, нажмите здесь."</string>
<string name="tethered_notification_title" msgid="3146694234398202601">"USB-модем или точка доступа Wi-Fi активны"</string>
<string name="tethered_notification_message" msgid="3067108323903048927">"Нажмите для настройки"</string>
<string name="throttle_warning_notification_title" msgid="4890894267454867276">"Активная передача данных"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index d72c026..a783f0b 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Umožňuje aplikácii ovládať vibrácie."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"ovládanie kontrolky"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Umožňuje aplikácii ovládať kontrolku."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"prístup k zariadeniam USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Umožní aplikácii prístup k zariadeniam USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"spravovať predvoľby a povolenia zariadení USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Povolí aplikácii spravovať predvoľby a povolenia zariadení USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testovanie hardvéru"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Umožňuje aplikácii ovládať rôzne periférie na účely testovania hardvéru."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"priame volanie na telefónne čísla"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Umožňuje aplikácii pripojiť sa k prístupovým bodom Wi-Fi alebo sa od nich odpojiť a uskutočňovať zmeny nakonfigurovaných sietí Wi-Fi."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Povoliť príjem viacsmerového vysielania Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Umožňuje aplikácii prijímať pakety, ktoré neboli adresované priamo vášmu zariadeniu. Pomocou tejto možnosti môžete objaviť služby ponúkané vo vašej blízkosti. Spotreba energie je vyššia ako v režime bez viacsmerového vysielania."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"zobraziť stav WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Umožňuje aplikácii zobraziť informácie o stave siete WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"zmeniť stav WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Umožňuje aplikácii pripojiť sa a odpojiť zo siete WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"správa rozhrania Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Umožňuje aplikácii konfigurovať miestny telefón s rozhraním Bluetooth a vyhľadávať a párovať vzdialené zariadenia."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"vytvorenie pripojenia Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Použiť ako predvolené nastavenie pre túto akciu."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Vymazanie predvolených hodnôt v časti Nastavenia plochy &gt; Aplikácie &gt; Správa aplikácií."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Vyberte akciu"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Vyberte aplikáciu pre zariadenia USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Túto akciu nemôžu vykonávať žiadne aplikácie."</string>
<string name="aerr_title" msgid="653922989522758100">"Je nám ľúto!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Aplikácia <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) bola neočakávane zastavená. Skúste to znova."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index 5799fa4..53e155b 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Programu dovoljuje nadzor vibriranja."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"nadzor svetilke"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Programu dovoljuje nadzor svetilke."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"dostop do naprav USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Programu omogoča dostop do naprav USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"upravljanje nastavitev in dovoljenj za naprave USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Omogoči programu upravljanje nastavitev in dovoljenj za naprave USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"preskušanje strojne opreme"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Programu dovoljuje nadzor različnih zunanjih naprav za preskušanje strojne opreme."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"neposredno klicanje telefonskih številk"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Programu dovoljuje vzpostavljanje povezave z dostopnimi točkami brezžičnega omrežja in prekinitev povezave z njimi ter spreminjanje konfiguriranih brezžičnih omrežij."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"dovoljevanje sprejema večvrstnega brezžičnega oddajanja"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Programu dovoljuje prejemanje paketov, ki niso naslovljeni neposredno na vašo napravo. To je lahko uporabno, ko odkrivate storitve, ki so dane na voljo v bližini. Poraba je večja od načina delovanja brez večvrstnega oddajanja."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"prikaz stanja omrežja WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Programu omogoča prikaz podatkov o stanju omrežja WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"sprememba stanja omrežja WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Programu omogoča povezovanje v omrežje WiMAX in prekinitev povezave."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"skrbništvo storitve Bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Programu dovoljuje konfiguriranje lokalnega telefona s tehnologijo Bluetooth ter odkrivanje oddaljenih naprav in povezovanje z njimi."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"ustvarjanje povezav Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Privzeta uporaba za to dejanje."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Počistite privzete nastavitve v razdelku Osnovne nastavitve &gt; Programi &gt; Upravljanje programov."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Izberite dejanje"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Izberite program za napravo USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Tega dejanja ne more izvesti noben program."</string>
<string name="aerr_title" msgid="653922989522758100">"Oprostite."</string>
<string name="aerr_application" msgid="4683614104336409186">"Program <xliff:g id="APPLICATION">%1$s</xliff:g> (postopek <xliff:g id="PROCESS">%2$s</xliff:g>) se je nepričakovano ustavil. Poskusite znova."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index c21fa1b..767744e 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Омогућава да апликација контролише вибрације."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"контрола осветљења"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Омогућава да апликација контролише осветљење."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"приступ USB уређајима"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Омогућава апликацији приступ USB уређајима."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"управљање подешавањима и дозволама за USB уређаје"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Омогућава да апликација управља подешавањима и дозволама за USB уређаје."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"тестирање хардвера"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Омогућава да апликација контролише разноврсне периферне уређаје у сврхе тестирања хардвера."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"директно позивање бројева телефона"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Омогућава да се апликација повезује са Wi-Fi приступним тачкама и да прекине везу са њима, као и да уноси промене у конфигурисане Wi-Fi мреже."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"омогућавање пријема вишесмерног Wi-Fi саобраћаја"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Омогућава да апликација прима пакете који нису директно намењени вашем уређају. То може бити корисно при откривању услуга које се нуде у вашој близини. Користи више напајања од режима једносмерног саобраћаја."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"прикажи WiMAX статуса"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Омогућава апликацији преглед информација о WiMAX статусу."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"промени WiMAX статуса"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Омогућава апликацији повезивање и прекид везе са WiMAX мрежом."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"администрирање преко bluetooth-а"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Омогућава да апликација конфигурише локални Bluetooth телефон, као и да открије удаљене уређаје и упари се са њима."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"креирање Bluetooth веза"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Подразумевано користи за ову радњу."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Обришите подразумевана подешавања у оквиру ставки Подешавања почетне странице &gt; Апликације &gt; Управљање апликацијама."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Избор радње"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Избор апликације за USB уређај"</string>
<string name="noApplications" msgid="1691104391758345586">"Ниједна апликација не може да изврши ову радњу."</string>
<string name="aerr_title" msgid="653922989522758100">"Жао нам је!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Апликација <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) је неочекивано заустављена. Покушајте поново."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 78fe64b..1731567 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -136,7 +136,7 @@
<string name="shutdown_progress" msgid="2281079257329981203">"Avslutar…"</string>
<string name="shutdown_confirm" msgid="649792175242821353">"Din telefon stängs av."</string>
<string name="recent_tasks_title" msgid="3691764623638127888">"Senaste"</string>
- <string name="no_recent_tasks" msgid="279702952298056674">"Inga nya program."</string>
+ <string name="no_recent_tasks" msgid="279702952298056674">"Inga nya appar."</string>
<string name="global_actions" msgid="2406416831541615258">"Telefonalternativ"</string>
<string name="global_action_lock" msgid="2844945191792119712">"Skärmlås"</string>
<string name="global_action_power_off" msgid="4471879440839879722">"Stäng av"</string>
@@ -191,11 +191,11 @@
<string name="permdesc_writeSms" msgid="6299398896177548095">"Tillåter att program skriver till SMS-meddelanden som lagrats på din telefon eller SIM-kort. Skadliga program kan radera dina meddelanden."</string>
<string name="permlab_receiveWapPush" msgid="8258226427716551388">"ta emot WAP"</string>
<string name="permdesc_receiveWapPush" msgid="5979623826128082171">"Tillåter att program tar emot och bearbetar WAP-meddelanden. Skadliga program kan övervaka dina meddelanden eller ta bort dem utan att visa dem för dig."</string>
- <string name="permlab_getTasks" msgid="5005277531132573353">"hämta program som körs"</string>
+ <string name="permlab_getTasks" msgid="5005277531132573353">"hämta appar som körs"</string>
<string name="permdesc_getTasks" msgid="7048711358713443341">"Tillåter att program hämtar information om uppgifter som körs och har körts. Skadliga program kan upptäcka privat information om andra program."</string>
- <string name="permlab_reorderTasks" msgid="5669588525059921549">"byt ordning på program som körs"</string>
+ <string name="permlab_reorderTasks" msgid="5669588525059921549">"byt ordning på appar som körs"</string>
<string name="permdesc_reorderTasks" msgid="126252774270522835">"Tillåter att ett program flyttar uppgifter till förgrunden eller bakgrunden. Skadliga program kan tvinga sig till förgrunden utan att du kan styra det."</string>
- <string name="permlab_setDebugApp" msgid="4339730312925176742">"aktivera felsökning av program"</string>
+ <string name="permlab_setDebugApp" msgid="4339730312925176742">"aktivera felsökning av appar"</string>
<string name="permdesc_setDebugApp" msgid="5584310661711990702">"Tillåter att ett program aktiverar felsökning för ett annat program. Skadliga program kan använda detta för att avsluta andra program."</string>
<string name="permlab_changeConfiguration" msgid="8214475779521218295">"ändra dina gränssnittsinställningar"</string>
<string name="permdesc_changeConfiguration" msgid="3465121501528064399">"Tillåter att ett program ändrar den aktuella konfigurationen, till exempel språk eller övergripande teckenformat."</string>
@@ -203,17 +203,17 @@
<string name="permdesc_enableCarMode" msgid="5673461159384850628">"Tillåter att ett program aktiverar trafikläge."</string>
<string name="permlab_killBackgroundProcesses" msgid="8373714752793061963">"avbryt bakgrundsprocesser"</string>
<string name="permdesc_killBackgroundProcesses" msgid="2908829602869383753">"Tillåter att ett program avslutar bakgrundsprocesser för andra program även om det inte finns för lite ledigt minne."</string>
- <string name="permlab_forceStopPackages" msgid="1447830113260156236">"framtvinga avslutning av andra program"</string>
+ <string name="permlab_forceStopPackages" msgid="1447830113260156236">"framtvinga avslutning av andra appar"</string>
<string name="permdesc_forceStopPackages" msgid="7263036616161367402">"Tillåter att ett program framtvingar avslutning av andra program."</string>
- <string name="permlab_forceBack" msgid="1804196839880393631">"tvinga program att avsluta"</string>
+ <string name="permlab_forceBack" msgid="1804196839880393631">"tvinga appar att avsluta"</string>
<string name="permdesc_forceBack" msgid="6534109744159919013">"Tillåter att ett program tvingar en aktivitet som finns i förgrunden att avsluta och gå tillbaka. Behövs inte för vanliga program."</string>
<string name="permlab_dump" msgid="1681799862438954752">"hämta systemets interna status"</string>
<string name="permdesc_dump" msgid="2198776174276275220">"Tillåter att ett program hämtar systemets interna status. Skadliga program kan hämta privat och skyddad information som de normalt aldrig ska behöva."</string>
<string name="permlab_shutdown" msgid="7185747824038909016">"avsluta delvis"</string>
<string name="permdesc_shutdown" msgid="7046500838746291775">"Sätter aktivitetshanteraren i avstängningsläge. Utför inte en fullständig avstängning."</string>
<string name="permlab_stopAppSwitches" msgid="4138608610717425573">"förhindrar programbyten"</string>
- <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hindrar att användaren byter till ett annat program."</string>
- <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"övervaka och styra alla program som öppnas"</string>
+ <string name="permdesc_stopAppSwitches" msgid="3857886086919033794">"Hindrar att användaren byter till en annan app."</string>
+ <string name="permlab_runSetActivityWatcher" msgid="7811586187574696296">"övervaka och styra alla appar som öppnas"</string>
<string name="permdesc_runSetActivityWatcher" msgid="3228701938345388092">"Tillåter att ett program övervakar och styr hur systemet startar aktiviteter. Skadliga program kan bryta systemet helt. Den här behörigheten behövs bara för programmering, aldrig för vanlig telefonanvändning."</string>
<string name="permlab_broadcastPackageRemoved" msgid="2576333434893532475">"skicka meddelande om borttaget paket"</string>
<string name="permdesc_broadcastPackageRemoved" msgid="3453286591439891260">"Tillåter att ett program skickar ett meddelande om att ett programpaket har tagits bort. Skadliga program kan använda detta för att avsluta alla andra program som körs."</string>
@@ -244,16 +244,16 @@
<string name="permlab_bindInputMethod" msgid="3360064620230515776">"binda till en metod för indata"</string>
<string name="permdesc_bindInputMethod" msgid="3734838321027317228">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en inmatningsmetod. Ska inte behövas för vanliga program."</string>
<string name="permlab_bindWallpaper" msgid="8716400279937856462">"binda till en bakgrund"</string>
- <string name="permdesc_bindWallpaper" msgid="5287754520361915347">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en bakgrund. Ska inte behövas för vanliga program."</string>
+ <string name="permdesc_bindWallpaper" msgid="5287754520361915347">"Innehavaren tillåts att binda till den översta nivåns gränssnitt för en bakgrund. Ska inte behövas för vanliga appar."</string>
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"arbeta med en enhetsadministratör"</string>
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"Tillåter att innehavaren skickar avsikter till en enhetsadministratör. Vanliga program behöver aldrig göra detta."</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"ändra bildskärmens rikting"</string>
<string name="permdesc_setOrientation" msgid="6335814461615851863">"Tillåter att ett program när som helst ändrar skärmens rotering. Behövs inte för vanliga program."</string>
- <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"skicka Linux-signaler till program"</string>
+ <string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"skicka Linux-signaler till appar"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"Tillåter att programmet begär att den angivna signalen skickas till alla beständiga processer."</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"se till att programmet alltid körs"</string>
<string name="permdesc_persistentActivity" msgid="5037199778265006008">"Tillåter att ett program gör vissa delar beständiga så att systemet inte kan använda det för andra program."</string>
- <string name="permlab_deletePackages" msgid="3343439331576348805">"ta bort program"</string>
+ <string name="permlab_deletePackages" msgid="3343439331576348805">"ta bort appar"</string>
<string name="permdesc_deletePackages" msgid="3634943677518723314">"Tillåter att ett program tar bort Android-paket. Skadliga program kan använda detta för att ta bort viktiga program."</string>
<string name="permlab_clearAppUserData" msgid="2192134353540277878">"ta bort de andra programmens uppgifter"</string>
<string name="permdesc_clearAppUserData" msgid="7546345080434325456">"Tillåter att ett program tar bort användardata."</string>
@@ -261,9 +261,9 @@
<string name="permdesc_deleteCacheFiles" msgid="2283074077168165971">"Tillåter att ett program raderar cachefiler."</string>
<string name="permlab_getPackageSize" msgid="4799785352306641460">"mäta telefonens lagringsutrymme"</string>
<string name="permdesc_getPackageSize" msgid="5557253039670753437">"Tillåter att ett program hämtar kod, data och cachestorlekar"</string>
- <string name="permlab_installPackages" msgid="335800214119051089">"installera program direkt"</string>
+ <string name="permlab_installPackages" msgid="335800214119051089">"installera appar direkt"</string>
<string name="permdesc_installPackages" msgid="526669220850066132">"Tillåter att ett program installerar nya eller uppdaterade Android-paket. Skadliga program kan använda detta för att lägga till nya program med godtyckliga och starka behörigheter."</string>
- <string name="permlab_clearAppCache" msgid="4747698311163766540">"ta bort cacheinformation för alla program"</string>
+ <string name="permlab_clearAppCache" msgid="4747698311163766540">"ta bort cacheinformation för alla appar"</string>
<string name="permdesc_clearAppCache" msgid="7740465694193671402">"Tillåter att ett program frigör lagringsutrymme i telefonen genom att ta bort filer i programmets katalog för cachelagring. Åtkomst är mycket begränsad, vanligtvis till systemprocesser."</string>
<string name="permlab_movePackage" msgid="728454979946503926">"Flytta programresurser"</string>
<string name="permdesc_movePackage" msgid="6323049291923925277">"Tillåter att ett program flyttar programresurser från interna till externa medier och tvärt om."</string>
@@ -273,7 +273,7 @@
<string name="permdesc_diagnostic" msgid="3121238373951637049">"Tillåter att ett program läser och skriver till en resurs som ägs av diag-gruppen; till exempel filer i /dev. Detta kan eventuellt påverka systemets stabilitet och säkerhet. Detta bör ENDAST används av tillverkaren eller operatören för maskinvaruspecifik diagnostik."</string>
<string name="permlab_changeComponentState" msgid="79425198834329406">"aktivera eller inaktivera programkomponenter"</string>
<string name="permdesc_changeComponentState" msgid="4569107043246700630">"Tillåter att ett program ändrar inställningen för om en komponent i ett annat program har aktiverats eller inte. Skadliga program kan använda detta för att inaktivera viktiga telefonfunktioner. Var försiktig med behörigheten, eftersom programkomponenter kan bli oanvändbara, inkonsekventa eller ostabila."</string>
- <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"ange önskade program"</string>
+ <string name="permlab_setPreferredApplications" msgid="3393305202145172005">"ange önskade appar"</string>
<string name="permdesc_setPreferredApplications" msgid="760008293501937546">"Tillåter att ett program ändrar dina önskade program. Skadliga program kan utan varning ändra de program som körs och förfalska dina befintliga program så att de samlar privata data från dig."</string>
<string name="permlab_writeSettings" msgid="1365523497395143704">"ändra globala systeminställningar"</string>
<string name="permdesc_writeSettings" msgid="838789419871034696">"Tillåter att ett program ändrar systemets inställningar. Skadliga program kan skada systemets konfiguration."</string>
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Tillåter att programmet styr vibratorn."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"styra lampa"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Tillåter att programmet styr lampan."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"åtkomst till USB-enheter"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Tillåter att programmet använder USB-enheter."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"hantera inställningar och behörighet för USB-enheter"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Tillåter att programmet hanterar inställningar och behörigheter för USB-enheter."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"testa maskinvara"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Tillåter att ett program styr kringutrustning i syfte att testa maskinvara."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"ringa telefonnummer direkt"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Tillåter att ett program ansluter till och kopplar från Wi-Fi-åtkomstpunkter och gör ändringar i konfigurerade Wi-Fi-nätverk."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"tillåt Wi-Fi multicast-mottagning"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Tillåter att ett program tar emot paket som inte är adresserade direkt till din enhet. Detta är användbart om du vill upptäcka tillgängliga tjänster i närheten. Det drar mer batteri än om telefonen inte är i multicast-läge."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"visa WiMAX-status"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Gör att en app kan visa information om WiMAX-status."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"ändra WiMAX-status"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Gör att en app kan anslutas till och kopplas ifrån WiMAX-nätverk."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"administrera bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Tillåter att ett program konfigurerar den lokala Bluetooth-telefonen samt upptäcker och parkopplar den med fjärranslutna enheter."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"skapa Bluetooth-anslutningar"</string>
@@ -733,7 +737,8 @@
<string name="alwaysUse" msgid="4583018368000610438">"Använd som standard för denna åtgärd."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Rensa standardinställning i Startinställningar &gt; Appar &gt; Hantera appar."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Välj en åtgärd"</string>
- <string name="noApplications" msgid="1691104391758345586">"Inga program kan utföra den här åtgärden."</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Välj ett program för USB-enheten"</string>
+ <string name="noApplications" msgid="1691104391758345586">"Inga appar kan utföra den här åtgärden."</string>
<string name="aerr_title" msgid="653922989522758100">"Tyvärr!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Processen <xliff:g id="PROCESS">%2$s</xliff:g> för programmet <xliff:g id="APPLICATION">%1$s</xliff:g> stoppades oväntat. Försök igen."</string>
<string name="aerr_process" msgid="1551785535966089511">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> avslutades oväntat. Försök igen."</string>
@@ -742,7 +747,7 @@
<string name="anr_activity_process" msgid="5420826626009561014">"Aktiviteten <xliff:g id="ACTIVITY">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
<string name="anr_application_process" msgid="4185842666452210193">"Programmet <xliff:g id="APPLICATION">%1$s</xliff:g> (i processen <xliff:g id="PROCESS">%2$s</xliff:g>) svarar inte."</string>
<string name="anr_process" msgid="1246866008169975783">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> svarar inte."</string>
- <string name="force_close" msgid="3653416315450806396">"Tvinga fram en stängning"</string>
+ <string name="force_close" msgid="3653416315450806396">"Tvinga stängning"</string>
<string name="report" msgid="4060218260984795706">"Rapportera"</string>
<string name="wait" msgid="7147118217226317732">"Vänta"</string>
<string name="launch_warning_title" msgid="8323761616052121936">"Programmet omdirigerades"</string>
@@ -752,8 +757,8 @@
<string name="smv_process" msgid="5120397012047462446">"Processen <xliff:g id="PROCESS">%1$s</xliff:g> har brutit mot sin egen StrictMode-policy."</string>
<string name="heavy_weight_notification" msgid="9087063985776626166">"<xliff:g id="APP">%1$s</xliff:g> körs"</string>
<string name="heavy_weight_notification_detail" msgid="2423977499339403402">"Välj om du vill växla till programmet"</string>
- <string name="heavy_weight_switcher_title" msgid="1135403633766694316">"Vill du byta program?"</string>
- <string name="heavy_weight_switcher_text" msgid="4592075610079319667">"Ett annat program som körs måste avslutas innan du kan starta ett nytt."</string>
+ <string name="heavy_weight_switcher_title" msgid="1135403633766694316">"Vill du byta app?"</string>
+ <string name="heavy_weight_switcher_text" msgid="4592075610079319667">"En annan app som körs måste avslutas innan du kan starta en ny."</string>
<string name="old_app_action" msgid="493129172238566282">"Gå tillbaka till <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
<string name="old_app_description" msgid="942967900237208466">"Starta inte det nya programmet."</string>
<string name="new_app_action" msgid="5472756926945440706">"Starta <xliff:g id="OLD_APP">%1$s</xliff:g>"</string>
@@ -782,7 +787,7 @@
<item quantity="other" msgid="7915895323644292768">"Öppna Wi-Fi-nätverk är tillgängliga"</item>
</plurals>
<string name="select_character" msgid="3365550120617701745">"Infoga tecken"</string>
- <string name="sms_control_default_app_name" msgid="7630529934366549163">"Okänt program"</string>
+ <string name="sms_control_default_app_name" msgid="7630529934366549163">"Okänd app"</string>
<string name="sms_control_title" msgid="7296612781128917719">"Skickar SMS"</string>
<string name="sms_control_message" msgid="1289331457999236205">"Flera SMS-meddelanden skickas. Tryck på OK om du vill fortsätta eller på Avbryt om du vill avsluta sändningen."</string>
<string name="sms_control_yes" msgid="2532062172402615953">"OK"</string>
@@ -809,7 +814,7 @@
<string name="usb_storage_stop_button_mount" msgid="7060218034900696029">"Inaktivera USB-lagring"</string>
<string name="usb_storage_stop_error_message" msgid="143881914840412108">"Ett problem uppstod när USB-lagringsplatsen skulle inaktiveras. Kontrollera att USB-värden har demonterats och försök igen."</string>
<string name="dlg_confirm_kill_storage_users_title" msgid="963039033470478697">"Aktivera USB-lagring"</string>
- <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Om du aktiverar USB-lagring avbryts några av de program som körs och de kanske inte blir tillgängliga igen förrän du inaktiverar USB-lagring."</string>
+ <string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"Om du aktiverar USB-lagring avbryts några av de appar som körs och de kanske inte blir tillgängliga igen förrän du inaktiverar USB-lagring."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB-åtgärd misslyckades"</string>
<string name="dlg_ok" msgid="7376953167039865701">"OK"</string>
<string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"Formatera USB-enhet"</string>
@@ -849,8 +854,8 @@
<string name="activity_list_empty" msgid="4168820609403385789">"Inga matchande aktiviteter hittades"</string>
<string name="permlab_pkgUsageStats" msgid="8787352074326748892">"uppdatera statistik över användning av komponenter"</string>
<string name="permdesc_pkgUsageStats" msgid="891553695716752835">"Tillåter att samlad komponentstatistik ändras. Används inte av vanliga program."</string>
- <string name="permlab_copyProtectedData" msgid="1660908117394854464">"Tillåter att innehåll kopieras genom att standardbehållartjänsten startas. Vanliga program behöver aldrig göra detta."</string>
- <string name="permdesc_copyProtectedData" msgid="537780957633976401">"Tillåter att innehåll kopieras genom att standardbehållartjänsten startas. Vanliga program behöver aldrig göra detta."</string>
+ <string name="permlab_copyProtectedData" msgid="1660908117394854464">"Tillåter att innehåll kopieras genom att standardbehållartjänsten startas. Vanliga appar behöver aldrig göra detta."</string>
+ <string name="permdesc_copyProtectedData" msgid="537780957633976401">"Tillåter att innehåll kopieras genom att standardbehållartjänsten startas. Vanliga appar behöver aldrig göra detta."</string>
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1311810005957319690">"Peka två gånger för zoomkontroll"</string>
<string name="gadget_host_error_inflating" msgid="2613287218853846830">"Fel när widgeten expanderades"</string>
<string name="ime_action_go" msgid="8320845651737369027">"Kör"</string>
@@ -863,7 +868,7 @@
<string name="create_contact_using" msgid="4947405226788104538">"Skapa kontakt"\n"med <xliff:g id="NUMBER">%s</xliff:g>"</string>
<string name="accessibility_compound_button_selected" msgid="5612776946036285686">"markerad"</string>
<string name="accessibility_compound_button_unselected" msgid="8864512895673924091">"inte markerad"</string>
- <string name="grant_credentials_permission_message_header" msgid="6824538733852821001">"Följande program begär behörighet till konto, både nu och i framtiden."</string>
+ <string name="grant_credentials_permission_message_header" msgid="6824538733852821001">"Följande appar begär behörighet till konto, både nu och i framtiden."</string>
<string name="grant_credentials_permission_message_footer" msgid="3125211343379376561">"Vill du tillåta den här begäran?"</string>
<string name="grant_permissions_header_text" msgid="2722567482180797717">"Begäran om åtkomst"</string>
<string name="allow" msgid="7225948811296386551">"Tillåt"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index e618941..3dad236 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"อนุญาตให้แอปพลิเคชันควบคุมการสั่นเตือน"</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"ควบคุมไฟฉาย"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"อนุญาตให้แอปพลิเคชันควบคุมไฟฉาย"</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"เข้าถึงอุปกรณ์ USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"อนุญาตให้แอปพลิเคชันเข้าถึงอุปกรณ์ USB"</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"จัดการค่ากำหนดและการอนุญาตสำหรับอุปกรณ์ USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"อนุญาตให้แอปพลิเคชันจัดการค่ากำหนดและการอนุญาตสำหรับอุปกรณ์ USB"</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"ทดสอบฮาร์ดแวร์"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"อนุญาตให้แอปพลิเคชันควบคุมอุปกรณ์ต่อพ่วงหลายอย่างเพื่อการทดสอบฮาร์ดแวร์"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"โทรติดต่อหมายเลขโทรศัพท์โดยตรง"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"อนุญาตให้แอปพลิเคชันเชื่อมต่อและตัดการเชื่อมต่อจากจุดเข้าใช้งาน Wi-Fi และเปลี่ยนแปลงเครือข่าย Wi-Fi ที่กำหนดค่าไว้"</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"อนุญาตให้รับมัลติแคสต์ผ่าน Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"อนุญาตให้แอปพลิเคชันรับแพ็คเก็ตที่ไม่ได้ส่งถึงอุปกรณ์ของคุณโดยตรง วิธีนี้อาจเป็นประโยชน์เมื่อพบบริการที่นำเสนออยู่ใกล้ๆ แต่จะใช้พลังงานมากกว่าโหมดที่ไม่ใช่มัลติแคสต์"</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"ดูสถานะของ WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"อนุญาตให้แอปพลิเคชันดูข้อมูลเกี่ยวกับสถานะของ WiMAX"</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"เปลี่ยนสถานะของ WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"อนุญาตให้แอปพลิเคชันเชื่อมต่อและยกเลิกการเชื่อมต่อกับเครือข่าย WiMAX"</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"การใช้บลูทูธ"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"อนุญาตให้แอปพลิเคชันกำหนดค่าโทรศัพท์บลูทูธในพื้นที่ ตลอดจนค้นหาและจับคู่กับอุปกรณ์ที่อยู่ระยะไกล"</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"สร้างการเชื่อมต่อบลูทูธ"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"ใช้ค่าเริ่มต้นสำหรับการทำงานนี้"</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"ล้างข้อมูลค่าเริ่มต้นในการตั้งค่าหน้าแรก &gt; แอปพลิเคชัน &gt; จัดการแอปพลิเคชัน"</string>
<string name="chooseActivity" msgid="1009246475582238425">"เลือกการทำงาน"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"เลือกแอปพลิเคชันสำหรับอุปกรณ์ USB"</string>
<string name="noApplications" msgid="1691104391758345586">"ไม่มีแอปพลิเคชันใดทำงานนี้ได้"</string>
<string name="aerr_title" msgid="653922989522758100">"ขออภัย!"</string>
<string name="aerr_application" msgid="4683614104336409186">"แอปพลิเคชัน <xliff:g id="APPLICATION">%1$s</xliff:g> (กระบวนการ <xliff:g id="PROCESS">%2$s</xliff:g> หยุดทำงานโดยไม่คาดหมาย โปรดลองอีกครั้ง"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index fd4ede5..762464c 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Pinapayagan ang application na kontrolin ang vibrator."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"kontrolin ang flashlight"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Pinapayagan ang application na kontrolin ang flashlight."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"i-access ang mga USB device"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Pinapayagan ang application na i-access ang mga USB device."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"pamahalaan ang mga kagustuhan at pahintulot para sa mga USB device"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Pinapayagan ang application na pamahalaan ang mga kagustuhan at pahintulot para sa mga USB device."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"subukan ang hardware"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Pinapayagan ang application na kontrolin ang iba\'t ibang peripheral para sa layunin ng pagsubok ng hardware."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"direktang tawagan ang mga numero ng telepono"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Pinapayagan ang isang application na kumonekta sa at i-disconnect mula sa mga Wi-Fi access point, at magsagawa ng mga pagbabago sa mga na-configure na Wi-Fi network."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"payagan ang pagtanggap ng Wi-Fi Multicast"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Pinapayagan ang isang application na tumanggap ng mga packet na hindi direktang nakatugon sa iyong device. Magiging kapaki-pakinabang ito kapag tumutuklas ng mga serbisyong inaalok sa malapit. Gumagamit ito ng higit pang baterya kaysa sa non-multicast mode."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"tingnan ang katayuan ng WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Pinapayagan ang application na tingnan ang impormasyon tungkol sa katayuan ng WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"baguhin ang katayuan ng WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Pinapayagan ang isang application na makakonekta sa at maalis sa pagkakakonekta mula sa network ng WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"pangangasiwa ng bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Pinapayagan ang isang application na i-configure ang lokal na Bluetooth na telepono, at upang tumuklas at mapareha sa mga remote na device."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"lumikha ng mga koneksyon ng Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Gamitin bilang default para sa pagkilos na ito."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"I-clear ang default sa Mga Setting ng Home &gt; Mga Application &gt; Pamahalaan ang mga application."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Pumili ng pagkilos"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Pumili ng application para sa USB device"</string>
<string name="noApplications" msgid="1691104391758345586">"Walang mga application ang makakapagsagawa ng pagkilos na ito."</string>
<string name="aerr_title" msgid="653922989522758100">"Paumanhin!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Hindi inaasahang humito ang <xliff:g id="APPLICATION">%1$s</xliff:g> (proseso <xliff:g id="PROCESS">%2$s</xliff:g>) ng application. Pakisubukang muli."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 0174024..e41112b 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Uygulamanın titreşimi denetlemesine izin verir."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"flaşı denetle"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Uygulamaların flaş ışığını denetlemesine izin verir."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"USB cihazlarına erişme"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Uygulamaların USB cihazlarına erişimine izin verir"</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"USB cihazları için tercihleri ve izinleri yönet"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Uygulamanın USB cihazları için tercihleri ve izinleri yönetmesine izin verir."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"donanımı test et"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Uygulamanın donanım testi için çeşitli çevre birimlerini denetlemesine izin verir."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"telefon numaralarına doğrudan çağrı yap"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Uygulamaların kablosuz erişim noktalarına bağlanıp bunlarla bağlantısını kesmesine ve yapılandırılmış kablosuz ağlarda değişiklikler yapmasına izin verir."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"Kablosuz Çoklu Yayın alımına izin ver"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Bir uygulamaya doğrudan cihazınıza yönlendirilmemiş paketleri alma izni verir. Yakın yerlerde sunulan hizmetlerin keşfedilmesi sırasında faydalı olabilir. Birden fazla noktaya yayın yapmayan moda göre daha fazla güç harcar."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"WiMAX durumunu görüntüle"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Uygulamanın, WiMAX\'ın durumuyla ilgili bilgileri görüntülemesine izin verir."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"WiMAX durumunu değiştir"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Uygulamanın, WiMAX ağına bağlanmasına veya bağlantısını kesmesine izin verir."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"bluetooth yönetimi"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Uygulamaların yerel Bluetooth telefonunu yapılandırmasına ve uzak cihazları keşfedip bunlar ile eşleşmesine izin verir."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"Bluetooth bağlantıları oluştur"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Varsayılan olarak bu işlem için kullan."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Giriş Ayarları &gt; Uygulamalar &gt; Uygulamaları yönet\'te varsayılanı temizleyin."</string>
<string name="chooseActivity" msgid="1009246475582238425">"İşlem seç"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"USB cihazı için bir uygulama seçin"</string>
<string name="noApplications" msgid="1691104391758345586">"Hiçbir uygulama bu işlemi yapamaz."</string>
<string name="aerr_title" msgid="653922989522758100">"Üzgünüz!"</string>
<string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işlemi) beklenmedik biçimde durdu. Lütfen yeniden deneyin."</string>
@@ -743,7 +748,7 @@
<string name="anr_application_process" msgid="4185842666452210193">"<xliff:g id="APPLICATION">%1$s</xliff:g> uygulaması (<xliff:g id="PROCESS">%2$s</xliff:g> işleminde) yanıt vermiyor."</string>
<string name="anr_process" msgid="1246866008169975783">"<xliff:g id="PROCESS">%1$s</xliff:g> işlemi yanıt vermiyor."</string>
<string name="force_close" msgid="3653416315450806396">"Kapanmaya zorla"</string>
- <string name="report" msgid="4060218260984795706">"Rapor"</string>
+ <string name="report" msgid="4060218260984795706">"Bildir"</string>
<string name="wait" msgid="7147118217226317732">"Bekle"</string>
<string name="launch_warning_title" msgid="8323761616052121936">"Uygulama yönlendirildi"</string>
<string name="launch_warning_replace" msgid="6202498949970281412">"<xliff:g id="APP_NAME">%1$s</xliff:g> şimdi çalışıyor."</string>
@@ -812,7 +817,7 @@
<string name="dlg_confirm_kill_storage_users_text" msgid="3202838234780505886">"USB depolama birimini açarsanız, kullanmakta olduğunuz bazı uygulamalar durur ve USB depolama birimi kapatılıncaya kadar kullanılamayabilir."</string>
<string name="dlg_error_title" msgid="8048999973837339174">"USB işlemi başarısız oldu"</string>
<string name="dlg_ok" msgid="7376953167039865701">"Tamam"</string>
- <string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB dep br biçimlndr"</string>
+ <string name="extmedia_format_title" product="nosdcard" msgid="7980995592595097841">"USB\'yi biçimlendir"</string>
<string name="extmedia_format_title" product="default" msgid="8663247929551095854">"SD kartı biçimlendir"</string>
<string name="extmedia_format_message" product="nosdcard" msgid="8296908079722897772">"USB depolama birimi biçimlendirilsin mi? Depolama biriminde saklanan tüm dosyalar silinir. İşlem geri alınamaz!"</string>
<string name="extmedia_format_message" product="default" msgid="3621369962433523619">"SD kartı biçimlendirmek istediğinizden emin misiniz? Kartınızdaki tüm veriler yok olacak."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 6a7a12a..cf295ab 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Дозволяє програмі контролювати вібросигнал."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"контр. блим. світло"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Дозволяє програмі контролювати світловий сигнал."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"отр.дост.до прист.USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Дозволяє програмі отрим. доступ до пристр. USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"керувати налаштуваннями та дозволами для пристроїв USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Дозволяє програмі керувати налаштуваннями та дозволами для пристроїв USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"тест-ти обладн."</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Дозволяє програмі контрол. різні периферійні пристрої для тестування апаратного забезпечення."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"прямо набирати номери тел."</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Дозволяє програмі підключатися та відключатися від точок доступу Wi-Fi, а також вносити зміни до налаштованих Wi-Fi мереж."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"дозвол. отримання багатоадр. Wi-Fi"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Дозволяє програмі отрим. пакети, які не адрес. безпосер. вашому пристрою. Це може бути корисно під час виявл. пропонованих служб неподалік. Викор. більше потужності, ніж не багатоадресний реж."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"переглядати стан WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Дозволяє програмі переглядати інформацію про стан WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"змінювати стан WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Дозволяє програмі підключатися та відключатися від мережі WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"адміністрування bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Дозволяє програмі налашт. локальний телефон із Bluetooth і знаходити та створ. пару з віддаленими пристроями."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"створюв. підключення Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Використ. за умовч. для цієї дії."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Очист. налашт. за умовч. у Дом. налашт. &gt; Програми &gt; Керув. програмами."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Виберіть дію"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Виберіть програму для пристрою USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Жодна програма не може виконати цю дію."</string>
<string name="aerr_title" msgid="653922989522758100">"Помилка!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Програма <xliff:g id="APPLICATION">%1$s</xliff:g> (процес <xliff:g id="PROCESS">%2$s</xliff:g>) несподівано зупинилася. Спробуйте ще."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 28ad8b1..ed660f0 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"Cho phép ứng dụng kiểm soát bộ rung."</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"kiểm soát đèn nháy"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"Cho phép ứng dụng kiểm soát đèn nháy."</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"truy cập bộ nhớ USB"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"Cho phép ứng dụng truy cập thiết bị USB."</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"quản lý các tùy chọn và quyền dành cho thiết bị USB"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"Cho phép ứng dụng quản lý các tùy chọn và quyền dành cho thiết bị USB."</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"kiểm tra phần cứng"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"Cho phép ứng dụng kiểm soát các thiết bị ngoại vi khác nhau nhằm mục đích kiểm tra phần cứng."</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"gọi trực tiếp số điện thoại"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"Cho phép ứng dụng kết nối và ngắt kết nối khỏi điểm truy cập Wi-Fi cũng như thực hiện các thay đổi đối với mạng Wi-Fi đã được định cấu hình."</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"cho phép thu tín hiệu Wi-Fi Đa hướng"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"Cho phép ứng dụng nhận các gói không được gửi trực tiếp đến thiết bị của bạn. Quyền này có thể hữu ích khi phát hiện các dịch vụ được cung cấp gần đó. Thiết bị của bạn sử dụng nhiều năng lượng hơn chế độ không phát đa hướng."</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"xem trạng thái WiMAX"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"Cho phép ứng dụng xem thông tin về trạng thái của WiMAX."</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"thay đổi trạng thái WiMAX"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"Cho phép ứng dụng kết nối và ngắt kết nối khỏi mạng WiMAX."</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"quản trị bluetooth"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"Cho phép ứng dụng định cấu hình điện thoại Bluetooth nội hạt cũng như phát hiện và ghép nối với các thiết bị từ xa."</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"tạo kết nối Bluetooth"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"Sử dụng theo mặc định đối với tác vụ này."</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"Xoá mặc định trong Cài đặt Màn hình trang chủ &gt; Ứng dụng&gt; Quản lý ứng dụng."</string>
<string name="chooseActivity" msgid="1009246475582238425">"Chọn tác vụ"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"Chọn ứng dụng cho thiết bị USB"</string>
<string name="noApplications" msgid="1691104391758345586">"Không ứng dụng nào có thể thực hiện tác vụ này."</string>
<string name="aerr_title" msgid="653922989522758100">"Rất tiếc!"</string>
<string name="aerr_application" msgid="4683614104336409186">"Ứng dụng <xliff:g id="APPLICATION">%1$s</xliff:g> (quá trình <xliff:g id="PROCESS">%2$s</xliff:g>) đã dừng đột ngột. Vui lòng thử lại."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 6832787..432fe4b 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -335,8 +335,8 @@
<string name="permdesc_vibrate" msgid="2886677177257789187">"允许应用程序控制振动器。"</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"控制闪光灯"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"允许应用程序控制闪光灯。"</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"访问 USB 设备"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"允许应用程序访问 USB 设备。"</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"管理 USB 设备的偏好设置和权限"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"允许应用程序管理 USB 设备的偏好设置和权限。"</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"测试硬件"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"允许应用程序控制各外围设备以进行硬件测试。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"直接拨打电话号码"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"允许应用程序连接到 Wi-Fi 接入点以及与 Wi-Fi 接入点断开连接,并对配置的 Wi-Fi 网络进行更改。"</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"允许接收 Wi-Fi 多播"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"允许应用程序接收并非直接向您的设备发送的数据包。这样在查找附近提供的服务时很有用。这种操作所耗电量大于非多播模式。"</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"查看 WiMAX 状态"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"允许应用程序查看有关 WiMAX 状态的信息。"</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"更改 WiMAX 状态"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"允许应用程序连接到 WiMAX 网络以及从 WiMAX 网络断开连接。"</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"蓝牙管理"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"允许应用程序配置本地蓝牙手机,以及发现远程设备并与其配对。"</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"创建蓝牙连接"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"默认使用此方式发送。"</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"通过主屏幕上的“设置”&gt;“应用程序”&gt;“管理应用程序”清除默认设置。"</string>
<string name="chooseActivity" msgid="1009246475582238425">"选择一项操作"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"选择适用于 USB 设备的应用程序"</string>
<string name="noApplications" msgid="1691104391758345586">"没有应用程序可执行此操作。"</string>
<string name="aerr_title" msgid="653922989522758100">"很抱歉!"</string>
<string name="aerr_application" msgid="4683614104336409186">"应用程序 <xliff:g id="APPLICATION">%1$s</xliff:g>(进程:<xliff:g id="PROCESS">%2$s</xliff:g>)意外停止,请重试。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 2810fdd..35f290b 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -226,9 +226,9 @@
<string name="permlab_setAlwaysFinish" msgid="5342837862439543783">"關閉所有背景程式"</string>
<string name="permdesc_setAlwaysFinish" msgid="8773936403987091620">"允許應用程式控制哪些活動在被移到背景執行時,儘速結束。一般應用程式不需要此功能。"</string>
<string name="permlab_batteryStats" msgid="7863923071360031652">"編輯電池狀態"</string>
- <string name="permdesc_batteryStats" msgid="5847319823772230560">"允許修改電池狀態。一般應用程式不會使用此功能。"</string>
+ <string name="permdesc_batteryStats" msgid="5847319823772230560">"允修改收集到的電池用量統計資料。一般應用程式不應使用這項功能。"</string>
<string name="permlab_backup" msgid="470013022865453920">"控制系統備份與還原"</string>
- <string name="permdesc_backup" msgid="4837493065154256525">"允許應用程式控制系統備份與還原機制 (不建議一般應用程式使用)。"</string>
+ <string name="permdesc_backup" msgid="4837493065154256525">"允許應用程式控制系統的備份與還原機制。一般應用程式不應使用這項功能。"</string>
<string name="permlab_internalSystemWindow" msgid="2148563628140193231">"顯示未授權視窗"</string>
<string name="permdesc_internalSystemWindow" msgid="5895082268284998469">"允許內部系統使用介面建立視窗。一般應用程式不會使用此功能。"</string>
<string name="permlab_systemAlertWindow" msgid="3372321942941168324">"顯示系統警示"</string>
@@ -248,11 +248,11 @@
<string name="permlab_bindDeviceAdmin" msgid="8704986163711455010">"與裝置管理員互動"</string>
<string name="permdesc_bindDeviceAdmin" msgid="8714424333082216979">"允許應用程式將調用請求 (intent) 傳送至裝置管理員;一般應用程式不需使用此選項。"</string>
<string name="permlab_setOrientation" msgid="3365947717163866844">"變更螢幕顯示方向"</string>
- <string name="permdesc_setOrientation" msgid="6335814461615851863">"允許應用程式隨時變更螢幕顯示方向。一般應用程式不需要此功能。"</string>
+ <string name="permdesc_setOrientation" msgid="6335814461615851863">"允許應用程式可隨時變更螢幕旋轉方向。一般應用不應使用這項功能。"</string>
<string name="permlab_signalPersistentProcesses" msgid="4255467255488653854">"傳送 Linux 訊號到應用程式"</string>
<string name="permdesc_signalPersistentProcesses" msgid="3565530463215015289">"允許應用程式要求將支援的訊號傳送到所有持續的程序。"</string>
<string name="permlab_persistentActivity" msgid="8659652042401085862">"設定應用程式持續執行"</string>
- <string name="permdesc_persistentActivity" msgid="5037199778265006008">"允許應用程式持續執行,避免系統將它應用到其他程式。"</string>
+ <string name="permdesc_persistentActivity" msgid="5037199778265006008">"允許應用程式部分持續執行,避免系統將它用於其他應用程式。"</string>
<string name="permlab_deletePackages" msgid="3343439331576348805">"刪除應用程式"</string>
<string name="permdesc_deletePackages" msgid="3634943677518723314">"允許應用程式刪除 Android 程式。請注意:惡意程式可能利用此功能刪除重要應用程式。"</string>
<string name="permlab_clearAppUserData" msgid="2192134353540277878">"刪除其他應用程式資料"</string>
@@ -310,7 +310,7 @@
<string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"變更音訊設定"</string>
<string name="permdesc_modifyAudioSettings" msgid="5793461287365991922">"允許應用程式編輯全域音訊設定,例如音量與路由。"</string>
<string name="permlab_recordAudio" msgid="3876049771427466323">"錄製音訊"</string>
- <string name="permdesc_recordAudio" msgid="6493228261176552356">"允許應用程式存取音訊錄製路徑。"</string>
+ <string name="permdesc_recordAudio" msgid="6493228261176552356">"允許應用程式存取錄音檔路徑。"</string>
<string name="permlab_camera" msgid="3616391919559751192">"拍照和拍攝影片"</string>
<string name="permdesc_camera" msgid="6004878235852154239">"允許應用程式使用相機拍照和錄影,此功能可讓應用程式隨時透過相機收集圖片。"</string>
<string name="permlab_brick" msgid="8337817093326370537">"永久停用電話"</string>
@@ -321,34 +321,34 @@
<string name="permdesc_mount_unmount_filesystems" msgid="6253263792535859767">"允許應用程式掛載/卸載抽取式儲存設備的檔案系統。"</string>
<string name="permlab_mount_format_filesystems" msgid="5523285143576718981">"將外接式儲存裝置格式化"</string>
<string name="permdesc_mount_format_filesystems" msgid="574060044906047386">"允許應用程式將可移除式儲存裝置格式化。"</string>
- <string name="permlab_asec_access" msgid="3411338632002193846">"取得內存空間的資訊"</string>
- <string name="permdesc_asec_access" msgid="8820326551687285439">"允許應用程式取得內存空間的資訊。"</string>
- <string name="permlab_asec_create" msgid="6414757234789336327">"建立內存空間"</string>
- <string name="permdesc_asec_create" msgid="2621346764995731250">"允許應用程式建立內存空間。"</string>
- <string name="permlab_asec_destroy" msgid="526928328301618022">"銷毀內存空間"</string>
- <string name="permdesc_asec_destroy" msgid="2746706889208066256">"允許應用程式銷毀內存空間。"</string>
- <string name="permlab_asec_mount_unmount" msgid="2456287623689029744">"掛接/卸載內存空間"</string>
- <string name="permdesc_asec_mount_unmount" msgid="5934375590189368200">"允許應用程式掛接/卸載內存空間。"</string>
- <string name="permlab_asec_rename" msgid="7496633954080472417">"重新命名內存空間"</string>
- <string name="permdesc_asec_rename" msgid="2152829985238876790">"允許應用程式重新命名內存空間。"</string>
+ <string name="permlab_asec_access" msgid="3411338632002193846">"取得內部儲存空間的資訊"</string>
+ <string name="permdesc_asec_access" msgid="8820326551687285439">"允許應用程式取得內部儲存空間的資訊。"</string>
+ <string name="permlab_asec_create" msgid="6414757234789336327">"建立內部儲存空間"</string>
+ <string name="permdesc_asec_create" msgid="2621346764995731250">"允許應用程式建立內部儲存空間。"</string>
+ <string name="permlab_asec_destroy" msgid="526928328301618022">"銷毀內部儲存空間"</string>
+ <string name="permdesc_asec_destroy" msgid="2746706889208066256">"允許應用程式銷毀內部儲存空間。"</string>
+ <string name="permlab_asec_mount_unmount" msgid="2456287623689029744">"掛接/卸載內部儲存空間"</string>
+ <string name="permdesc_asec_mount_unmount" msgid="5934375590189368200">"允許應用程式掛接/卸載內部儲存空間。"</string>
+ <string name="permlab_asec_rename" msgid="7496633954080472417">"重新命名內部儲存空間"</string>
+ <string name="permdesc_asec_rename" msgid="2152829985238876790">"允許應用程式重新命名內部儲存空間。"</string>
<string name="permlab_vibrate" msgid="7768356019980849603">"控制震動"</string>
<string name="permdesc_vibrate" msgid="2886677177257789187">"允許應用程式控制震動。"</string>
<string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
<string name="permdesc_flashlight" msgid="6433045942283802309">"允許應用程式控制閃光燈。"</string>
- <string name="permlab_accessUsb" msgid="7362327818655760496">"存取 USB 裝置"</string>
- <string name="permdesc_accessUsb" msgid="2414271762914049292">"允許應用程式存取 USB 裝置。"</string>
+ <string name="permlab_manageUsb" msgid="1113453430645402723">"管理 USB 裝置的偏好設定和權限"</string>
+ <string name="permdesc_manageUsb" msgid="6148489202092166164">"允許應用程式管理 USB 裝置的偏好設定和權限。"</string>
<string name="permlab_hardware_test" msgid="4148290860400659146">"測試硬體"</string>
<string name="permdesc_hardware_test" msgid="3668894686500081699">"允許應用程式控制各種週邊設備,以供測試用。"</string>
<string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
<string name="permdesc_callPhone" msgid="3369867353692722456">"允許應用程式自行撥打電話。請注意:惡意程式可能任意撥打電話,造成預期外的支出。但此選項並不允許應用程式撥打緊急電話號碼。"</string>
<string name="permlab_callPrivileged" msgid="4198349211108497879">"直接撥打任何電話號碼"</string>
- <string name="permdesc_callPrivileged" msgid="244405067160028452">"允許應用程式自行撥打任何電話號碼,包括緊急電話號碼。請注意:惡意程式可能利用此功能濫用緊急服務,撥打不必要或違法的電話。"</string>
+ <string name="permdesc_callPrivileged" msgid="244405067160028452">"允許應用程式自行撥打任何電話號碼,包括緊急電話號碼。請注意:惡意應用程式可能會利用此權限,向緊急服務撥打騷擾甚至非法電話。"</string>
<string name="permlab_performCdmaProvisioning" msgid="5604848095315421425">"直接起始 CDMA 手機設定程序"</string>
<string name="permdesc_performCdmaProvisioning" msgid="6457447676108355905">"允許應用程式啟動 CDMA 服務 (惡意應用程式可能會在非必要的情況下啟動 CDMA 服務)。"</string>
<string name="permlab_locationUpdates" msgid="7785408253364335740">"控制位置更新通知"</string>
- <string name="permdesc_locationUpdates" msgid="2300018303720930256">"允許啟用/停用無線通訊位置更新通知。一般應用程式不會使用此功能。"</string>
+ <string name="permdesc_locationUpdates" msgid="2300018303720930256">"允許從廣播中啟用/停用位置資訊更新通知。一般應用程式不應使用這項功能。"</string>
<string name="permlab_checkinProperties" msgid="7855259461268734914">"存取登機選項"</string>
- <string name="permdesc_checkinProperties" msgid="7150307006141883832">"允許讀寫登機服務上傳的資料。一般應用程式不會使用此功能。"</string>
+ <string name="permdesc_checkinProperties" msgid="7150307006141883832">"允許讀取/寫入由登錄服務所更新的屬性存取權。一般應用程式不應使用這項功能。"</string>
<string name="permlab_bindGadget" msgid="776905339015863471">"選擇小工具"</string>
<string name="permdesc_bindGadget" msgid="2098697834497452046">"允許應用程式告知系統哪個應用程式可以使用哪些小工具。開啟此權限後,應用程式會讓其他程式使用個人資料,但一般應用程式不適合使用此功能。"</string>
<string name="permlab_modifyPhoneState" msgid="8423923777659292228">"修改手機狀態"</string>
@@ -389,8 +389,8 @@
<string name="permdesc_writeApnSettings" msgid="7443433457842966680">"允許應用程式修改 APN 設定,例如:Proxy 及 APN 的連接埠。"</string>
<string name="permlab_changeNetworkState" msgid="958884291454327309">"變更網路連線"</string>
<string name="permdesc_changeNetworkState" msgid="4199958910396387075">"允許應用程式變更網路連線狀態。"</string>
- <string name="permlab_changeTetherState" msgid="2702121155761140799">"變更數據連線"</string>
- <string name="permdesc_changeTetherState" msgid="8905815579146349568">"允許應用程式變更數據網路連線狀態。"</string>
+ <string name="permlab_changeTetherState" msgid="2702121155761140799">"變更網路共用設定"</string>
+ <string name="permdesc_changeTetherState" msgid="8905815579146349568">"允許應用程式變更已共用網路的連線狀態。"</string>
<string name="permlab_changeBackgroundDataSetting" msgid="1400666012671648741">"變更背景資料使用設定"</string>
<string name="permdesc_changeBackgroundDataSetting" msgid="1001482853266638864">"允許應用程式變更背景資料使用設定。"</string>
<string name="permlab_accessWifiState" msgid="8100926650211034400">"檢視 Wi-Fi 狀態"</string>
@@ -399,6 +399,10 @@
<string name="permdesc_changeWifiState" msgid="2950383153656873267">"允許應用程式與 Wi-Fi 存取點連線或中斷連線,並可變更 Wi-Fi 網路設定。"</string>
<string name="permlab_changeWifiMulticastState" msgid="1368253871483254784">"允許接收 Wi-Fi 多點傳播封包"</string>
<string name="permdesc_changeWifiMulticastState" msgid="8199464507656067553">"允許應用程式接收並非指定傳送給您裝置的封包,這在您發現附近有服務可使用時很有用,但消耗的電力比非多點傳播模式還要多。"</string>
+ <string name="permlab_accessWimaxState" msgid="2800410363171809280">"查看 WiMAX 狀態"</string>
+ <string name="permdesc_accessWimaxState" msgid="8298035866227524023">"允許應用程式查看 WiMAX 連線狀態相關資訊。"</string>
+ <string name="permlab_changeWimaxState" msgid="340465839241528618">"變更 WiMAX 狀態"</string>
+ <string name="permdesc_changeWimaxState" msgid="474918005058989421">"允許應用程式建立或中斷 WiMAX 網路連線。"</string>
<string name="permlab_bluetoothAdmin" msgid="1092209628459341292">"藍牙管理"</string>
<string name="permdesc_bluetoothAdmin" msgid="7256289774667054555">"允許應用程式設定本機藍牙電話,以及偵測與配對其他遠端裝置。"</string>
<string name="permlab_bluetooth" msgid="8361038707857018732">"建立藍牙連線"</string>
@@ -733,6 +737,7 @@
<string name="alwaysUse" msgid="4583018368000610438">"以此為本操作預設值。"</string>
<string name="clearDefaultHintMsg" msgid="4815455344600932173">"清除首頁設定 (應用程式) 管理應用程式的預設值。"</string>
<string name="chooseActivity" msgid="1009246475582238425">"選取一項操作"</string>
+ <string name="chooseUsbActivity" msgid="7892597146032121735">"選取要以 USB 裝置存取的應用程式"</string>
<string name="noApplications" msgid="1691104391758345586">"沒有應用程式可執行此項操作。"</string>
<string name="aerr_title" msgid="653922989522758100">"很抱歉!"</string>
<string name="aerr_application" msgid="4683614104336409186">"<xliff:g id="APPLICATION">%1$s</xliff:g> 應用程式 (程序:<xliff:g id="PROCESS">%2$s</xliff:g>) 異常終止。請再試一次。"</string>
@@ -885,7 +890,7 @@
<string name="description_star" msgid="2654319874908576133">"我的最愛"</string>
<string name="car_mode_disable_notification_title" msgid="3164768212003864316">"已啟用車用模式"</string>
<string name="car_mode_disable_notification_message" msgid="668663626721675614">"選取結束車用模式。"</string>
- <string name="tethered_notification_title" msgid="3146694234398202601">"數據連線或無線基地台已啟用"</string>
+ <string name="tethered_notification_title" msgid="3146694234398202601">"網路共用或無線基地台已啟用"</string>
<string name="tethered_notification_message" msgid="3067108323903048927">"輕觸以設定"</string>
<string name="throttle_warning_notification_title" msgid="4890894267454867276">"高行動資料用量"</string>
<string name="throttle_warning_notification_message" msgid="2609734763845705708">"輕觸即可瞭解更多有關行動資料用量的詳細資訊"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 355e681..cbb5852 100644..100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -399,4 +399,43 @@
<!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
<string-array name="config_twoDigitNumberPattern">
</string-array>
+
+ <!-- The VoiceMail default value is displayed to my own number if it is true -->
+ <bool name="config_telephony_use_own_number_for_voicemail">false</bool>
+
+ <!-- If this value is true, Sms encoded as octet is decoded by utf8 decoder.
+ If false, decoded by Latin decoder. -->
+ <bool name="config_sms_utf8_support">false</bool>
+
+ <!-- If this value is true, The mms content-disposition field is supported correctly.
+ If false, Content-disposition fragments are ignored -->
+ <bool name="config_mms_content_disposition_support">true</bool>
+
+ <!-- If this value is true, the carrier supports sms delivery reports.
+ If false, sms delivery reports are not supported and the preference
+ option to enable/disable delivery reports is removed in the Messaging app. -->
+ <bool name="config_sms_delivery_reports_support">true</bool>
+
+ <!-- If this value is true, the carrier supports mms delivery reports.
+ If false, mms delivery reports are not supported and the preference
+ option to enable/disable delivery reports is removed in the Messaging app. -->
+ <bool name="config_mms_delivery_reports_support">true</bool>
+
+ <!-- If this value is true, the carrier supports mms read reports.
+ If false, mms read reports are not supported and the preference
+ option to enable/disable read reports is removed in the Messaging app. -->
+ <bool name="config_mms_read_reports_support">true</bool>
+
+ <!-- Set and Unsets WiMAX -->
+ <bool name="config_wimaxEnabled">false</bool>
+ <!-- Location of the wimax framwork jar location -->
+ <string name="config_wimaxServiceJarLocation"></string>
+ <!-- Location of the wimax native library locaiton -->
+ <string name="config_wimaxNativeLibLocation"></string>
+ <!-- Name of the wimax manager class -->
+ <string name="config_wimaxManagerClassname"></string>
+ <!-- Name of the wimax service class -->
+ <string name="config_wimaxServiceClassname"></string>
+ <!-- Name of the wimax state tracker clas -->
+ <string name="config_wimaxStateTrackerClassname"></string>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index e331f8d..ae3cd02 100755
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -927,9 +927,9 @@
the flashlight.</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_accessUsb">access USB devices</string>
+ <string name="permlab_manageUsb">manage preferences and permissions for USB devices</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_accessUsb">Allows the application to access USB devices.</string>
+ <string name="permdesc_manageUsb">Allows the application to manage preferences and permissions for USB devices.</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_hardware_test">test hardware</string>
@@ -1139,6 +1139,18 @@
than the non-multicast mode.</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_accessWimaxState">view WiMAX state</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_accessWimaxState">Allows an application to view
+ the information about the state of WiMAX.</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_changeWimaxState">change WiMAX state</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_changeWimaxState">Allows an application to connect
+ to and disconnect from WiMAX network.</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_bluetoothAdmin">bluetooth administration</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_bluetoothAdmin">Allows an application to configure
@@ -1926,6 +1938,8 @@
<string name="clearDefaultHintMsg">Clear default in Home Settings &gt; Applications &gt; Manage applications.</string>
<!-- Default title for the activity chooser, when one is not given. Android allows multiple activities to perform an action. for example, there may be many ringtone pickers installed. A dialog is shown to the user allowing him to pick which activity should be used. This is the title. -->
<string name="chooseActivity">Select an action</string>
+ <!-- title for the USB activity chooser. -->
+ <string name="chooseUsbActivity">Select an application for the USB device</string>
<!-- Text to display when there are no activities found to display in the
activity chooser. See the "Select an action" title. -->
<string name="noApplications">No applications can perform this action.</string>
diff --git a/core/tests/ConnectivityManagerTest/Android.mk b/core/tests/ConnectivityManagerTest/Android.mk
index a1546fa..56011f7 100644
--- a/core/tests/ConnectivityManagerTest/Android.mk
+++ b/core/tests/ConnectivityManagerTest/Android.mk
@@ -25,6 +25,6 @@ LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := ConnectivityManagerTest
-#LOCAL_INSTRUMENTATION_FOR := connectivitymanagertest
+LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
diff --git a/core/tests/ConnectivityManagerTest/AndroidManifest.xml b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
index b116bea..05f8b39 100644
--- a/core/tests/ConnectivityManagerTest/AndroidManifest.xml
+++ b/core/tests/ConnectivityManagerTest/AndroidManifest.xml
@@ -16,7 +16,8 @@
<!-- package name must be unique so suffix with "tests" so package loader doesn't ignore us -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- package="com.android.connectivitymanagertest">
+ package="com.android.connectivitymanagertest"
+ android:sharedUserId="com.android.uid.test">
<!-- We add an application tag here just so that we can indicate that
this package needs to link against the android.test library,
@@ -67,5 +68,9 @@
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
+ <uses-permission android:name="android.permission.DEVICE_POWER" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+
</manifest>
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
index 47f208a..5b76e39 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerStressTestRunner.java
@@ -19,8 +19,8 @@ package com.android.connectivitymanagertest;
import android.os.Bundle;
import android.test.InstrumentationTestRunner;
import android.test.InstrumentationTestSuite;
-import android.util.Log;
import com.android.connectivitymanagertest.stress.WifiApStress;
+import com.android.connectivitymanagertest.stress.WifiStressTest;
import junit.framework.TestSuite;
@@ -34,10 +34,18 @@ import junit.framework.TestSuite;
*/
public class ConnectivityManagerStressTestRunner extends InstrumentationTestRunner {
+ public int mSoftapIterations = 100;
+ public int mScanIterations = 100;
+ public int mReconnectIterations = 100;
+ public int mSleepTime = 30 * 1000; // default sleep time is 30 seconds
+ public String mReconnectSsid = "securenetdhcp";
+ public String mReconnectPassword = "androidwifi";
+
@Override
public TestSuite getAllTests() {
TestSuite suite = new InstrumentationTestSuite(this);
suite.addTestSuite(WifiApStress.class);
+ suite.addTestSuite(WifiStressTest.class);
return suite;
}
@@ -49,14 +57,46 @@ public class ConnectivityManagerStressTestRunner extends InstrumentationTestRunn
@Override
public void onCreate(Bundle icicle) {
super.onCreate(icicle);
- String stressValue = (String) icicle.get("stressnum");
- if (stressValue != null) {
- int iteration = Integer.parseInt(stressValue);
+ String valueStr = (String) icicle.get("softap_iterations");
+ if (valueStr != null) {
+ int iteration = Integer.parseInt(valueStr);
if (iteration > 0) {
- numStress = iteration;
+ mSoftapIterations = iteration;
+ }
+ }
+
+ String scanIterationStr = (String) icicle.get("scan_iterations");
+ if (scanIterationStr != null) {
+ int scanIteration = Integer.parseInt(scanIterationStr);
+ if (scanIteration > 0) {
+ mScanIterations = scanIteration;
+ }
+ }
+
+ String ssidStr= (String) icicle.get("reconnect_ssid");
+ if (ssidStr != null) {
+ mReconnectSsid = ssidStr;
+ }
+
+ String passwordStr = (String) icicle.get("reconnect_password");
+ if (passwordStr != null) {
+ mReconnectPassword = passwordStr;
+ }
+
+ String reconnectStr = (String) icicle.get("reconnect_iterations");
+ if (reconnectStr != null) {
+ int iteration = Integer.parseInt(reconnectStr);
+ if (iteration > 0) {
+ mReconnectIterations = iteration;
}
}
- }
- public int numStress = 100;
+ String sleepTimeStr = (String) icicle.get("sleep_time");
+ if (sleepTimeStr != null) {
+ int sleepTime = Integer.parseInt(sleepTimeStr);
+ if (sleepTime > 0) {
+ mSleepTime = 1000 * sleepTime;
+ }
+ }
+ }
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
index 0807706..7aa0afd 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/ConnectivityManagerTestActivity.java
@@ -24,11 +24,17 @@ import android.content.BroadcastReceiver;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
+import android.os.IPowerManager;
+import android.os.PowerManager;
+import android.os.ServiceManager;
+import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
import android.view.KeyEvent;
+import java.io.IOException;
import java.io.InputStream;
+import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@@ -54,7 +60,7 @@ public class ConnectivityManagerTestActivity extends Activity {
public static final String LOG_TAG = "ConnectivityManagerTestActivity";
public static final int WAIT_FOR_SCAN_RESULT = 10 * 1000; //10 seconds
- public static final int WIFI_SCAN_TIMEOUT = 20 * 1000;
+ public static final int WIFI_SCAN_TIMEOUT = 50 * 1000;
public static final int SHORT_TIMEOUT = 5 * 1000;
public static final long LONG_TIMEOUT = 50 * 1000;
public static final int SUCCESS = 0; // for Wifi tethering state change
@@ -64,6 +70,7 @@ public class ConnectivityManagerTestActivity extends Activity {
public ConnectivityReceiver mConnectivityReceiver = null;
public WifiReceiver mWifiReceiver = null;
private AccessPointParserHelper mParseHelper = null;
+ public boolean scanResultAvailable = false;
/*
* Track network connectivity information
*/
@@ -79,7 +86,7 @@ public class ConnectivityManagerTestActivity extends Activity {
public int mWifiState;
public NetworkInfo mWifiNetworkInfo;
public String mBssid;
- public String mPowerSsid = "GoogleGuest"; //Default power SSID
+ public String mPowerSsid = "opennet"; //Default power SSID
private Context mContext;
/*
@@ -104,7 +111,7 @@ public class ConnectivityManagerTestActivity extends Activity {
private class ConnectivityReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
- Log.v(LOG_TAG, "ConnectivityReceiver: onReceive() is called with " + intent);
+ log("ConnectivityReceiver: onReceive() is called with " + intent);
String action = intent.getAction();
if (!action.equals(ConnectivityManager.CONNECTIVITY_ACTION)) {
Log.v("ConnectivityReceiver", "onReceive() called with " + intent);
@@ -129,9 +136,9 @@ public class ConnectivityManagerTestActivity extends Activity {
mReason = intent.getStringExtra(ConnectivityManager.EXTRA_REASON);
mIsFailOver = intent.getBooleanExtra(ConnectivityManager.EXTRA_IS_FAILOVER, false);
- Log.v(LOG_TAG, "mNetworkInfo: " + mNetworkInfo.toString());
+ log("mNetworkInfo: " + mNetworkInfo.toString());
if (mOtherNetworkInfo != null) {
- Log.v(LOG_TAG, "mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
+ log("mOtherNetworkInfo: " + mOtherNetworkInfo.toString());
}
recordNetworkState(mNetworkInfo.getType(), mNetworkInfo.getState());
if (mOtherNetworkInfo != null) {
@@ -151,7 +158,7 @@ public class ConnectivityManagerTestActivity extends Activity {
} else if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
mWifiNetworkInfo =
(NetworkInfo) intent.getParcelableExtra(WifiManager.EXTRA_NETWORK_INFO);
- Log.v(LOG_TAG, "mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
+ log("mWifiNetworkInfo: " + mWifiNetworkInfo.toString());
if (mWifiNetworkInfo.getState() == State.CONNECTED) {
mBssid = intent.getStringExtra(WifiManager.EXTRA_BSSID);
}
@@ -159,7 +166,7 @@ public class ConnectivityManagerTestActivity extends Activity {
} else if (action.equals(WifiManager.WIFI_STATE_CHANGED_ACTION)) {
mWifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE,
WifiManager.WIFI_STATE_UNKNOWN);
- Log.v(LOG_TAG, "mWifiState: " + mWifiState);
+ log("mWifiState: " + mWifiState);
notifyWifiState();
} else if (action.equals(WifiManager.WIFI_AP_STATE_CHANGED_ACTION)) {
notifyWifiAPState();
@@ -180,12 +187,13 @@ public class ConnectivityManagerTestActivity extends Activity {
public ConnectivityManagerTestActivity() {
mState = State.UNKNOWN;
+ scanResultAvailable = false;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- Log.v(LOG_TAG, "onCreate, inst=" + Integer.toHexString(hashCode()));
+ log("onCreate, inst=" + Integer.toHexString(hashCode()));
// Create a simple layout
LinearLayout contentView = new LinearLayout(this);
@@ -216,7 +224,7 @@ public class ConnectivityManagerTestActivity extends Activity {
initializeNetworkStates();
if (mWifiManager.isWifiEnabled()) {
- Log.v(LOG_TAG, "Clear Wifi before we start the test.");
+ log("Clear Wifi before we start the test.");
removeConfiguredNetworksAndDisableWifi();
}
mWifiRegexs = mCM.getTetherableWifiRegexs();
@@ -240,9 +248,9 @@ public class ConnectivityManagerTestActivity extends Activity {
private void printNetConfig(String[] configuration) {
for (int i = 0; i < configuration.length; i++) {
if (i == 0) {
- Log.v(LOG_TAG, "SSID: " + configuration[0]);
+ log("SSID: " + configuration[0]);
} else {
- Log.v(LOG_TAG, " " + configuration[i]);
+ log(" " + configuration[i]);
}
}
}
@@ -251,14 +259,14 @@ public class ConnectivityManagerTestActivity extends Activity {
public void initializeNetworkStates() {
for (int networkType = NUM_NETWORK_TYPES - 1; networkType >=0; networkType--) {
connectivityState[networkType] = new NetworkState();
- Log.v(LOG_TAG, "Initialize network state for " + networkType + ": " +
+ log("Initialize network state for " + networkType + ": " +
connectivityState[networkType].toString());
}
}
// deposit a network state
public void recordNetworkState(int networkType, State networkState) {
- Log.v(LOG_TAG, "record network state for network " + networkType +
+ log("record network state for network " + networkType +
", state is " + networkState);
connectivityState[networkType].recordState(networkState);
}
@@ -272,40 +280,41 @@ public class ConnectivityManagerTestActivity extends Activity {
// Validate the states recorded
public boolean validateNetworkStates(int networkType) {
- Log.v(LOG_TAG, "validate network state for " + networkType + ": ");
+ log("validate network state for " + networkType + ": ");
return connectivityState[networkType].validateStateTransition();
}
// return result from network state validation
public String getTransitionFailureReason(int networkType) {
- Log.v(LOG_TAG, "get network state transition failure reason for " + networkType + ": " +
+ log("get network state transition failure reason for " + networkType + ": " +
connectivityState[networkType].toString());
return connectivityState[networkType].getReason();
}
private void notifyNetworkConnectivityChange() {
synchronized(connectivityObject) {
- Log.v(LOG_TAG, "notify network connectivity changed");
+ log("notify network connectivity changed");
connectivityObject.notifyAll();
}
}
private void notifyScanResult() {
synchronized (this) {
- Log.v(LOG_TAG, "notify that scan results are available");
+ log("notify that scan results are available");
+ scanResultAvailable = true;
this.notify();
}
}
private void notifyWifiState() {
synchronized (wifiObject) {
- Log.v(LOG_TAG, "notify wifi state changed");
+ log("notify wifi state changed");
wifiObject.notify();
}
}
private void notifyWifiAPState() {
synchronized (this) {
- Log.v(LOG_TAG, "notify wifi AP state changed");
+ log("notify wifi AP state changed");
this.notify();
}
}
@@ -319,7 +328,7 @@ public class ConnectivityManagerTestActivity extends Activity {
for (Object obj: tethered) {
String str = (String)obj;
for (String tethRex: mWifiRegexs) {
- Log.v(LOG_TAG, "str: " + str +"tethRex: " + tethRex);
+ log("str: " + str +"tethRex: " + tethRex);
if (str.matches(tethRex)) {
wifiTethered = true;
}
@@ -329,7 +338,7 @@ public class ConnectivityManagerTestActivity extends Activity {
for (Object obj: errored) {
String str = (String)obj;
for (String tethRex: mWifiRegexs) {
- Log.v(LOG_TAG, "error: str: " + str +"tethRex: " + tethRex);
+ log("error: str: " + str +"tethRex: " + tethRex);
if (str.matches(tethRex)) {
wifiErrored = true;
}
@@ -341,7 +350,7 @@ public class ConnectivityManagerTestActivity extends Activity {
} else if (wifiErrored) {
mWifiTetherResult = FAILURE; // wifi tethering failed
}
- Log.v(LOG_TAG, "mWifiTetherResult: " + mWifiTetherResult);
+ log("mWifiTetherResult: " + mWifiTetherResult);
this.notify();
}
}
@@ -357,12 +366,12 @@ public class ConnectivityManagerTestActivity extends Activity {
return false;
} else {
// the broadcast has been sent out. the state has been changed.
- Log.v(LOG_TAG, "networktype: " + networkType + " state: " +
+ log("networktype: " + networkType + " state: " +
mCM.getNetworkInfo(networkType));
return true;
}
}
- Log.v(LOG_TAG, "Wait for the connectivity state for network: " + networkType +
+ log("Wait for the connectivity state for network: " + networkType +
" to be " + expectedState.toString());
synchronized (connectivityObject) {
try {
@@ -372,7 +381,7 @@ public class ConnectivityManagerTestActivity extends Activity {
}
if ((mNetworkInfo.getType() != networkType) ||
(mNetworkInfo.getState() != expectedState)) {
- Log.v(LOG_TAG, "network state for " + mNetworkInfo.getType() +
+ log("network state for " + mNetworkInfo.getType() +
"is: " + mNetworkInfo.getState());
continue;
}
@@ -393,7 +402,7 @@ public class ConnectivityManagerTestActivity extends Activity {
return true;
}
}
- Log.v(LOG_TAG, "Wait for wifi state to be: " + expectedState);
+ log("Wait for wifi state to be: " + expectedState);
synchronized (wifiObject) {
try {
wifiObject.wait(SHORT_TIMEOUT);
@@ -401,7 +410,7 @@ public class ConnectivityManagerTestActivity extends Activity {
e.printStackTrace();
}
if (mWifiState != expectedState) {
- Log.v(LOG_TAG, "Wifi state is: " + mWifiState);
+ log("Wifi state is: " + mWifiState);
continue;
}
return true;
@@ -421,7 +430,7 @@ public class ConnectivityManagerTestActivity extends Activity {
return true;
}
}
- Log.v(LOG_TAG, "Wait for wifi AP state to be: " + expectedState);
+ log("Wait for wifi AP state to be: " + expectedState);
synchronized (wifiObject) {
try {
wifiObject.wait(SHORT_TIMEOUT);
@@ -429,7 +438,7 @@ public class ConnectivityManagerTestActivity extends Activity {
e.printStackTrace();
}
if (mWifiManager.getWifiApState() != expectedState) {
- Log.v(LOG_TAG, "Wifi state is: " + mWifiManager.getWifiApState());
+ log("Wifi state is: " + mWifiManager.getWifiApState());
continue;
}
return true;
@@ -449,7 +458,7 @@ public class ConnectivityManagerTestActivity extends Activity {
if ((System.currentTimeMillis() - startTime) > timeout) {
return mWifiTetherResult;
}
- Log.v(LOG_TAG, "Wait for wifi tethering result.");
+ log("Wait for wifi tethering result.");
synchronized (this) {
try {
this.wait(SHORT_TIMEOUT);
@@ -479,6 +488,64 @@ public class ConnectivityManagerTestActivity extends Activity {
return mWifiManager.setWifiEnabled(true);
}
+ // Turn screen off
+ public void turnScreenOff() {
+ log("Turn screen off");
+ PowerManager pm =
+ (PowerManager) getSystemService(Context.POWER_SERVICE);
+ pm.goToSleep(SystemClock.uptimeMillis() + 100);
+ }
+
+ // Turn screen on
+ public void turnScreenOn() {
+ log("Turn screen on");
+ IPowerManager mPowerManagerService = IPowerManager.Stub.asInterface(
+ ServiceManager.getService("power"));;
+ try {
+ mPowerManagerService.userActivityWithForce(SystemClock.uptimeMillis(), false, true);
+ } catch (Exception e) {
+ log(e.toString());
+ }
+ }
+
+ /**
+ * @param pingServerList a list of servers that can be used for ping test, can be null
+ * @return true if the ping test is successful, false otherwise.
+ */
+ public boolean pingTest(String[] pingServerList) {
+ boolean result = false;
+ String[] hostList = {"www.google.com", "www.yahoo.com",
+ "www.bing.com", "www.facebook.com", "www.ask.com"};
+ if (pingServerList != null) {
+ hostList = pingServerList;
+ }
+ try {
+ // assume the chance that all servers are down is very small
+ for (int i = 0; i < hostList.length; i++ ) {
+ String host = hostList[i];
+ log("Start ping test, ping " + host);
+ Process p = Runtime.getRuntime().exec("ping -c 10 -w 100 " + host);
+ int status = p.waitFor();
+ if (status == 0) {
+ // if any of the ping test is successful, return true
+ result = true;
+ break;
+ } else {
+ result = false;
+ log("ping " + host + " failed.");
+ }
+ }
+ } catch (UnknownHostException e) {
+ log("Ping test Fail: Unknown Host");
+ } catch (IOException e) {
+ log("Ping test Fail: IOException");
+ } catch (InterruptedException e) {
+ log("Ping test Fail: InterruptedException");
+ }
+ log("return");
+ return result;
+ }
+
/**
* Associate the device to given SSID
* If the device is already associated with a WiFi, disconnect and forget it,
@@ -503,13 +570,13 @@ public class ConnectivityManagerTestActivity extends Activity {
//If Wifi is not enabled, enable it
if (!mWifiManager.isWifiEnabled()) {
- Log.v(LOG_TAG, "Wifi is not enabled, enable it");
+ log("Wifi is not enabled, enable it");
mWifiManager.setWifiEnabled(true);
}
List<ScanResult> netList = mWifiManager.getScanResults();
if (netList == null) {
- Log.v(LOG_TAG, "scan results are null");
+ log("scan results are null");
// if no scan results are available, start active scan
mWifiManager.startScanActive();
mScanResultIsAvailable = false;
@@ -540,7 +607,7 @@ public class ConnectivityManagerTestActivity extends Activity {
for (int i = 0; i < netList.size(); i++) {
ScanResult sr= netList.get(i);
if (sr.SSID.equals(ssid)) {
- Log.v(LOG_TAG, "found " + ssid + " in the scan result list");
+ log("found " + ssid + " in the scan result list");
int networkId = mWifiManager.addNetwork(config);
// Connect to network by disabling others.
mWifiManager.enableNetwork(networkId, true);
@@ -552,7 +619,7 @@ public class ConnectivityManagerTestActivity extends Activity {
List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
if (netConfList.size() <= 0) {
- Log.v(LOG_TAG, ssid + " is not available");
+ log(ssid + " is not available");
return false;
}
return true;
@@ -575,7 +642,7 @@ public class ConnectivityManagerTestActivity extends Activity {
// remove other saved networks
List<WifiConfiguration> netConfList = mWifiManager.getConfiguredNetworks();
if (netConfList != null) {
- Log.v(LOG_TAG, "remove configured network ids");
+ log("remove configured network ids");
for (int i = 0; i < netConfList.size(); i++) {
WifiConfiguration conf = new WifiConfiguration();
conf = netConfList.get(i);
@@ -640,7 +707,7 @@ public class ConnectivityManagerTestActivity extends Activity {
if (mWifiReceiver != null) {
unregisterReceiver(mWifiReceiver);
}
- Log.v(LOG_TAG, "onDestroy, inst=" + Integer.toHexString(hashCode()));
+ log("onDestroy, inst=" + Integer.toHexString(hashCode()));
}
@Override
@@ -682,5 +749,8 @@ public class ConnectivityManagerTestActivity extends Activity {
}
return super.onKeyDown(keyCode, event);
}
-}
+ private void log(String message) {
+ Log.v(LOG_TAG, message);
+ }
+}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
index cc53ddc..8717a12 100644
--- a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiApStress.java
@@ -19,25 +19,33 @@ package com.android.connectivitymanagertest.stress;
import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
-import com.android.connectivitymanagertest.ConnectivityManagerTestRunner;
import android.net.wifi.WifiConfiguration;
import android.net.wifi.WifiConfiguration.KeyMgmt;
import android.net.wifi.WifiConfiguration.AuthAlgorithm;
+import android.net.wifi.WifiManager;
+import android.os.Environment;
import android.test.ActivityInstrumentationTestCase2;
import android.test.suitebuilder.annotation.LargeTest;
import android.util.Log;
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+
/**
* Stress the wifi driver as access point.
*/
public class WifiApStress
extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
private final static String TAG = "WifiApStress";
- private ConnectivityManagerTestActivity mAct;
private static String NETWORK_ID = "AndroidAPTest";
private static String PASSWD = "androidwifi";
- private int max_num;
+ private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
+ private ConnectivityManagerTestActivity mAct;
+ private int iterations;
+ private BufferedWriter mOutputWriter = null;
+ private int mLastIteration = 0;
public WifiApStress() {
super(ConnectivityManagerTestActivity.class);
@@ -47,11 +55,20 @@ public class WifiApStress
public void setUp() throws Exception {
super.setUp();
mAct = getActivity();
- max_num = ((ConnectivityManagerStressTestRunner)getInstrumentation()).numStress;
+ ConnectivityManagerStressTestRunner mRunner =
+ (ConnectivityManagerStressTestRunner)getInstrumentation();
+ iterations = mRunner.mSoftapIterations;
+ mAct.turnScreenOn();
}
@Override
public void tearDown() throws Exception {
+ // write the total number of iterations into output file
+ mOutputWriter = new BufferedWriter(new FileWriter(new File(
+ Environment.getExternalStorageDirectory(), OUTPUT_FILE)));
+ mOutputWriter.write(String.format("iteration %d out of %d\n", mLastIteration, iterations));
+ mOutputWriter.flush();
+ mOutputWriter.close();
super.tearDown();
}
@@ -67,22 +84,38 @@ public class WifiApStress
if (mAct.mWifiManager.isWifiEnabled()) {
mAct.disableWifi();
}
- for (int i = 0; i < max_num; i++) {
+ int i;
+ for (i = 0; i < iterations; i++) {
Log.v(TAG, "iteration: " + i);
+ mLastIteration = i;
// enable Wifi tethering
assertTrue(mAct.mWifiManager.setWifiApEnabled(config, true));
// Wait for wifi ap state to be ENABLED
- assertTrue(mAct.waitForWifiAPState(mAct.mWifiManager.WIFI_AP_STATE_ENABLED,
- mAct.LONG_TIMEOUT));
+ assertTrue(mAct.waitForWifiAPState(WifiManager.WIFI_AP_STATE_ENABLED,
+ ConnectivityManagerTestActivity.LONG_TIMEOUT));
// Wait for wifi tethering result
- assertEquals(mAct.SUCCESS, mAct.waitForTetherStateChange(2*mAct.SHORT_TIMEOUT));
+ assertEquals(ConnectivityManagerTestActivity.SUCCESS,
+ mAct.waitForTetherStateChange(2*ConnectivityManagerTestActivity.SHORT_TIMEOUT));
// Allow the wifi tethering to be enabled for 10 seconds
try {
Thread.sleep(2 * ConnectivityManagerTestActivity.SHORT_TIMEOUT);
} catch (Exception e) {
fail("thread in sleep is interrupted");
}
+ assertTrue("no uplink data connection after Wi-Fi tethering", mAct.pingTest(null));
+ // Disable soft AP
assertTrue(mAct.mWifiManager.setWifiApEnabled(config, false));
+ // Wait for 30 seconds until Wi-Fi tethering is stopped
+ try {
+ Thread.sleep(30 * 1000);
+ Log.v(TAG, "wait for Wi-Fi tethering to be disabled.");
+ } catch (Exception e) {
+ fail("thread in sleep is interrupted");
+ }
+ assertFalse("Wi-Fi AP disable failed", mAct.mWifiManager.isWifiApEnabled());
+ }
+ if (i == iterations) {
+ mLastIteration = iterations;
}
}
diff --git a/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
new file mode 100644
index 0000000..9adccc7
--- /dev/null
+++ b/core/tests/ConnectivityManagerTest/src/com/android/connectivitymanagertest/stress/WifiStressTest.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2010, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.connectivitymanagertest.stress;
+
+import com.android.connectivitymanagertest.ConnectivityManagerStressTestRunner;
+import com.android.connectivitymanagertest.ConnectivityManagerTestActivity;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.NetworkInfo.State;
+import android.net.wifi.ScanResult;
+import android.net.wifi.WifiConfiguration;
+import android.net.wifi.WifiConfiguration.KeyMgmt;
+import android.net.wifi.WifiManager;
+import android.os.Environment;
+import android.os.PowerManager;
+import android.provider.Settings;
+import android.test.ActivityInstrumentationTestCase2;
+import android.test.suitebuilder.annotation.LargeTest;
+
+import android.util.Log;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.List;
+
+/**
+ * Stress Wi-Fi connection, scanning and reconnection after sleep.
+ *
+ * To run this stress test suite, type
+ * adb shell am instrument -e class com.android.connectivitymanagertest.stress.WifiStressTest
+ * -w com.android.connectivitymanagertest/.ConnectivityManagerStressTestRunner
+ */
+public class WifiStressTest
+ extends ActivityInstrumentationTestCase2<ConnectivityManagerTestActivity> {
+ private final static String TAG = "WifiStressTest";
+
+ /**
+ * Wi-Fi idle time for default sleep policy
+ */
+ private final static long WIFI_IDLE_MS = 60 * 1000;
+
+ /**
+ * The delay for Wi-Fi to get into idle, after screen off + WIFI_IDEL_MS + WIFI_IDLE_DELAY
+ * the Wi-Fi should be in idle mode and device should be in cellular mode.
+ */
+ private final static long WIFI_IDLE_DELAY = 3 * 1000;
+
+ private final static String OUTPUT_FILE = "WifiStressTestOutput.txt";
+ private ConnectivityManagerTestActivity mAct;
+ private int mReconnectIterations;
+ private int mWifiSleepTime;
+ private int mScanIterations;
+ private String mSsid;
+ private String mPassword;
+ private ConnectivityManagerStressTestRunner mRunner;
+ private BufferedWriter mOutputWriter = null;
+
+ public WifiStressTest() {
+ super(ConnectivityManagerTestActivity.class);
+ }
+
+ @Override
+ public void setUp() throws Exception {
+ super.setUp();
+ mAct = getActivity();
+ mRunner = (ConnectivityManagerStressTestRunner) getInstrumentation();
+ mReconnectIterations = mRunner.mReconnectIterations;
+ mSsid = mRunner.mReconnectSsid;
+ mPassword = mRunner.mReconnectPassword;
+ mScanIterations = mRunner.mScanIterations;
+ mWifiSleepTime = mRunner.mSleepTime;
+ mOutputWriter = new BufferedWriter(new FileWriter(new File(
+ Environment.getExternalStorageDirectory(), OUTPUT_FILE), true));
+ if (!mAct.mWifiManager.isWifiEnabled()) {
+ if (!mAct.enableWifi()) {
+ tearDown();
+ fail("enable wifi failed.");
+ }
+ sleep(ConnectivityManagerTestActivity.SHORT_TIMEOUT,
+ "Interruped while waiting for wifi on");
+ }
+ }
+
+ @Override
+ public void tearDown() throws Exception {
+ log("tearDown()");
+ if (mOutputWriter != null) {
+ mOutputWriter.close();
+ }
+ super.tearDown();
+ }
+
+ private void writeOutput(String s) {
+ log("write message: " + s);
+ if (mOutputWriter == null) {
+ log("no writer attached to file " + OUTPUT_FILE);
+ return;
+ }
+ try {
+ mOutputWriter.write(s + "\n");
+ mOutputWriter.flush();
+ } catch (IOException e) {
+ log("failed to write output.");
+ }
+ }
+
+ public void log(String message) {
+ Log.v(TAG, message);
+ }
+
+ private void sleep(long sometime, String errorMsg) {
+ try {
+ Thread.sleep(sometime);
+ } catch (InterruptedException e) {
+ fail(errorMsg);
+ }
+ }
+
+ /**
+ * Stress Wifi Scanning
+ * TODO: test the scanning quality for each frequency band
+ */
+ @LargeTest
+ public void testWifiScanning() {
+ int scanTimeSum = 0;
+ int i;
+ int ssidAppearInScanResultsCount = 0; // count times of given ssid appear in scan results.
+ for (i = 0; i < mScanIterations; i++) {
+ log("testWifiScanning: iteration: " + i);
+ int averageScanTime = 0;
+ if (i > 0) {
+ averageScanTime = scanTimeSum/i;
+ }
+ writeOutput(String.format("iteration %d out of %d",
+ i, mScanIterations));
+ writeOutput(String.format("average scanning time is %d", averageScanTime));
+ writeOutput(String.format("ssid appear %d out of %d scan iterations",
+ ssidAppearInScanResultsCount, i));
+ long startTime = System.currentTimeMillis();
+ mAct.scanResultAvailable = false;
+ assertTrue("start scan failed", mAct.mWifiManager.startScanActive());
+ while (true) {
+ if ((System.currentTimeMillis() - startTime) >
+ ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT) {
+ fail("Wifi scanning takes more than " +
+ ConnectivityManagerTestActivity.WIFI_SCAN_TIMEOUT + " ms");
+ }
+ synchronized(mAct) {
+ try {
+ mAct.wait(ConnectivityManagerTestActivity.WAIT_FOR_SCAN_RESULT);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ if (mAct.scanResultAvailable) {
+ long scanTime = (System.currentTimeMillis() - startTime);
+ scanTimeSum += scanTime;
+ break;
+ }
+ }
+ }
+ if ((mAct.mWifiManager.getScanResults() == null) ||
+ (mAct.mWifiManager.getScanResults().size() <= 0)) {
+ fail("Scan results are empty ");
+ }
+
+ List<ScanResult> netList = mAct.mWifiManager.getScanResults();
+ if (netList != null) {
+ log("size of scan result list: " + netList.size());
+ for (int s = 0; s < netList.size(); s++) {
+ ScanResult sr= netList.get(s);
+ log(String.format("scan result for %s is: %s", sr.SSID, sr.toString()));
+ log(String.format("signal level for %s is %d ", sr.SSID, sr.level));
+ if (sr.SSID.equals(mSsid)) {
+ ssidAppearInScanResultsCount += 1;
+ log("Number of times " + mSsid + " appear in the scan list: " +
+ ssidAppearInScanResultsCount);
+ break;
+ }
+ }
+ }
+ }
+ if (i == mScanIterations) {
+ writeOutput(String.format("iteration %d out of %d",
+ i, mScanIterations));
+ writeOutput(String.format("average scanning time is %d", scanTimeSum/mScanIterations));
+ writeOutput(String.format("ssid appear %d out of %d scan iterations",
+ ssidAppearInScanResultsCount, mScanIterations));
+ }
+ }
+
+ // Stress Wifi reconnection to secure net after sleep
+ @LargeTest
+ public void testWifiReconnectionAfterSleep() {
+ int value = Settings.System.getInt(mRunner.getContext().getContentResolver(),
+ Settings.System.WIFI_SLEEP_POLICY, -1);
+ if (value < 0) {
+ Settings.System.putInt(mRunner.getContext().getContentResolver(),
+ Settings.System.WIFI_SLEEP_POLICY, Settings.System.WIFI_SLEEP_POLICY_DEFAULT);
+ log("set wifi sleep policy to default value");
+ }
+ Settings.Secure.putLong(mRunner.getContext().getContentResolver(),
+ Settings.Secure.WIFI_IDLE_MS, WIFI_IDLE_MS);
+
+ // Connect to a Wi-Fi network
+ WifiConfiguration config = new WifiConfiguration();
+ config.SSID = mSsid;
+ config.allowedKeyManagement.set(KeyMgmt.WPA_PSK);
+ if (mPassword.matches("[0-9A-Fa-f]{64}")) {
+ config.preSharedKey = mPassword;
+ } else {
+ config.preSharedKey = '"' + mPassword + '"';
+ }
+ assertTrue("Failed to connect to Wi-Fi network: " + mSsid,
+ mAct.connectToWifiWithConfiguration(config));
+ assertTrue(mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+ ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ assertTrue(mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ // Run ping test to verify the data connection
+ assertTrue("Wi-Fi is connected, but no data connection.", mAct.pingTest(null));
+
+ int i;
+ for (i = 0; i < mReconnectIterations; i++) {
+ // 1. Put device into sleep mode
+ // 2. Wait for the device to sleep for sometime, verify wi-fi is off and mobile is on.
+ // 3. Maintain the sleep mode for some time,
+ // 4. Verify the Wi-Fi is still off, and data is on
+ // 5. Wake up the device, verify Wi-Fi is enabled and connected.
+ writeOutput(String.format("iteration %d out of %d",
+ i, mReconnectIterations));
+ log("iteration: " + i);
+ mAct.turnScreenOff();
+ PowerManager pm =
+ (PowerManager)mRunner.getContext().getSystemService(Context.POWER_SERVICE);
+ assertFalse(pm.isScreenOn());
+ sleep(WIFI_IDLE_MS, "Interruped while wait for wifi to be idle");
+ assertTrue("Wait for Wi-Fi to idle timeout",
+ mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.DISCONNECTED,
+ 6 * ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ // use long timeout as the pppd startup may take several retries.
+ assertTrue("Wait for cellular connection timeout",
+ mAct.waitForNetworkState(ConnectivityManager.TYPE_MOBILE, State.CONNECTED,
+ ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ sleep(mWifiSleepTime + WIFI_IDLE_DELAY, "Interrupted while device is in sleep mode");
+ // Verify the wi-fi is still off and data connection is on
+ assertEquals("Wi-Fi is reconnected", State.DISCONNECTED,
+ mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_WIFI).getState());
+
+ assertEquals("Cellular connection is down", State.CONNECTED,
+ mAct.mCM.getNetworkInfo(ConnectivityManager.TYPE_MOBILE).getState());
+ assertTrue("Mobile is connected, but no data connection.", mAct.pingTest(null));
+
+ // Turn screen on again
+ mAct.turnScreenOn();
+ assertTrue("Wait for Wi-Fi enable timeout after wake up",
+ mAct.waitForWifiState(WifiManager.WIFI_STATE_ENABLED,
+ ConnectivityManagerTestActivity.SHORT_TIMEOUT));
+ assertTrue("Wait for Wi-Fi connection timeout after wake up",
+ mAct.waitForNetworkState(ConnectivityManager.TYPE_WIFI, State.CONNECTED,
+ ConnectivityManagerTestActivity.LONG_TIMEOUT));
+ assertTrue("Reconnect to Wi-Fi network, but no data connection.", mAct.pingTest(null));
+ }
+ if (i == mReconnectIterations) {
+ writeOutput(String.format("iteration %d out of %d",
+ i, mReconnectIterations));
+ }
+ }
+}
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index fc4ea73..27b334e 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -96,6 +96,12 @@
<application android:theme="@style/Theme">
<uses-library android:name="android.test.runner" />
+ <activity android:name="android.view.ViewAttachTestActivity" android:label="View Attach Test">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+ </intent-filter>
+ </activity>
<activity android:name="StubTestBrowserActivity" android:label="Stubbed Test Browser">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
diff --git a/core/tests/coretests/res/layout/attach_view_test.xml b/core/tests/coretests/res/layout/attach_view_test.xml
new file mode 100644
index 0000000..42841cb
--- /dev/null
+++ b/core/tests/coretests/res/layout/attach_view_test.xml
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="utf-8"?>
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:orientation="vertical"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent">
+ <android.view.ViewAttachView
+ android:id="@+id/view_attach_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:keepScreenOn="true"/>
+</LinearLayout>
diff --git a/core/tests/coretests/src/android/text/TextUtilsTest.java b/core/tests/coretests/src/android/text/TextUtilsTest.java
index 79d57f1..63dd0cc 100644
--- a/core/tests/coretests/src/android/text/TextUtilsTest.java
+++ b/core/tests/coretests/src/android/text/TextUtilsTest.java
@@ -17,6 +17,7 @@
package android.text;
import android.graphics.Paint;
+import android.os.Parcel;
import android.test.suitebuilder.annotation.LargeTest;
import android.test.suitebuilder.annotation.SmallTest;
import android.text.Spannable;
@@ -352,6 +353,51 @@ public class TextUtilsTest extends TestCase {
assertFalse(TextUtils.delimitedStringContains("network,mock,gpsx", ',', "gps"));
}
+ @SmallTest
+ public void testCharSequenceCreator() {
+ Parcel p = Parcel.obtain();
+ TextUtils.writeToParcel(null, p, 0);
+ CharSequence text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+ assertNull("null CharSequence should generate null from parcel", text);
+ p = Parcel.obtain();
+ TextUtils.writeToParcel("test", p, 0);
+ text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+ assertEquals("conversion to/from parcel failed", "test", text);
+ }
+
+ @SmallTest
+ public void testCharSequenceCreatorNull() {
+ Parcel p;
+ CharSequence text;
+ p = Parcel.obtain();
+ TextUtils.writeToParcel(null, p, 0);
+ p.setDataPosition(0);
+ text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+ assertNull("null CharSequence should generate null from parcel", text);
+ }
+
+ @SmallTest
+ public void testCharSequenceCreatorSpannable() {
+ Parcel p;
+ CharSequence text;
+ p = Parcel.obtain();
+ TextUtils.writeToParcel(new SpannableString("test"), p, 0);
+ p.setDataPosition(0);
+ text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+ assertEquals("conversion to/from parcel failed", "test", text.toString());
+ }
+
+ @SmallTest
+ public void testCharSequenceCreatorString() {
+ Parcel p;
+ CharSequence text;
+ p = Parcel.obtain();
+ TextUtils.writeToParcel("test", p, 0);
+ p.setDataPosition(0);
+ text = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(p);
+ assertEquals("conversion to/from parcel failed", "test", text.toString());
+ }
+
/**
* CharSequence wrapper for testing the cases where text is copied into
* a char array instead of working from a String or a Spanned.
diff --git a/core/tests/coretests/src/android/view/ViewAttachTest.java b/core/tests/coretests/src/android/view/ViewAttachTest.java
new file mode 100644
index 0000000..cff66e4
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewAttachTest.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.content.pm.ActivityInfo;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+
+public class ViewAttachTest extends
+ ActivityInstrumentationTestCase2<ViewAttachTestActivity> {
+
+ public ViewAttachTest() {
+ super(ViewAttachTestActivity.class);
+ }
+
+ /**
+ * Make sure that onAttachedToWindow and onDetachedToWindow is called in the
+ * correct order The ViewAttachTestActivity contains a view that will throw
+ * an RuntimeException if onDetachedToWindow and onAttachedToWindow is
+ * called in the wrong order.
+ *
+ * 1. Initiate the activity 2. Perform a series of orientation changes to
+ * the activity (this will force the View hierarchy to be rebuild,
+ * generating onAttachedToWindow and onDetachedToWindow)
+ *
+ * Expected result: No RuntimeException is thrown from the TestView in
+ * ViewFlipperTestActivity.
+ *
+ * @throws Throwable
+ */
+ public void testAttached() throws Throwable {
+ final ViewAttachTestActivity activity = getActivity();
+ for (int i = 0; i < 20; i++) {
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
+ SystemClock.sleep(250);
+ activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
+ SystemClock.sleep(250);
+ }
+ }
+}
diff --git a/core/tests/coretests/src/android/view/ViewAttachTestActivity.java b/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
new file mode 100644
index 0000000..59e25ae
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewAttachTestActivity.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import com.android.frameworks.coretests.R;
+
+import android.app.Activity;
+import android.os.Bundle;
+
+public class ViewAttachTestActivity extends Activity {
+ public static final String TAG = "OnAttachedTest";
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.attach_view_test);
+ }
+}
diff --git a/core/tests/coretests/src/android/view/ViewAttachView.java b/core/tests/coretests/src/android/view/ViewAttachView.java
new file mode 100644
index 0000000..5af2d8f
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewAttachView.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.os.SystemClock;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.view.View;
+
+/**
+ * A View that will throw a RuntimeException if onAttachedToWindow and
+ * onDetachedFromWindow is called in the wrong order for ViewAttachTest
+ */
+public class ViewAttachView extends View {
+ public static final String TAG = "OnAttachedTest";
+ private boolean attached;
+
+ public ViewAttachView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ init(attrs, defStyle);
+ }
+
+ public ViewAttachView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ init(attrs, 0);
+ }
+
+ public ViewAttachView(Context context) {
+ super(context);
+ init(null, 0);
+ }
+
+ private void init(AttributeSet attrs, int defStyle) {
+ SystemClock.sleep(2000);
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ Log.d(TAG, "onAttachedToWindow");
+ super.onAttachedToWindow();
+ if (attached) {
+ throw new RuntimeException("OnAttachedToWindow called more than once in a row");
+ }
+ attached = true;
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ Log.d(TAG, "onDetachedFromWindow");
+ super.onDetachedFromWindow();
+ if (!attached) {
+ throw new RuntimeException(
+ "onDetachedFromWindowcalled without prior call to OnAttachedToWindow");
+ }
+ attached = false;
+ }
+
+ @Override
+ protected void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ canvas.drawColor(Color.BLUE);
+ }
+}
diff --git a/core/tests/overlaytests/Android.mk b/core/tests/overlaytests/Android.mk
new file mode 100644
index 0000000..bf69442
--- /dev/null
+++ b/core/tests/overlaytests/Android.mk
@@ -0,0 +1,4 @@
+# Dummy makefile to halt recursive directory traversal.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
diff --git a/core/tests/overlaytests/OverlayTest/Android.mk b/core/tests/overlaytests/OverlayTest/Android.mk
new file mode 100644
index 0000000..f7f67f6
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/Android.mk
@@ -0,0 +1,10 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_PACKAGE_NAME := OverlayTest
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayTest/AndroidManifest.xml b/core/tests/overlaytests/OverlayTest/AndroidManifest.xml
new file mode 100644
index 0000000..9edba12
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/AndroidManifest.xml
@@ -0,0 +1,10 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest">
+ <uses-permission android:name="android.permission.RUN_INSTRUMENTATION"/>
+ <application>
+ <uses-library android:name="android.test.runner"/>
+ </application>
+ <instrumentation android:name="android.test.InstrumentationTestRunner"
+ android:targetPackage="com.android.overlaytest"
+ android:label="Runtime resource overlay tests"/>
+</manifest>
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
new file mode 100644
index 0000000..85b49ce
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/OverlayBaseTest.java
@@ -0,0 +1,118 @@
+package com.android.overlaytest;
+
+import android.content.res.Configuration;
+import android.content.res.Resources;
+import android.test.AndroidTestCase;
+import java.io.InputStream;
+import java.util.Locale;
+
+public abstract class OverlayBaseTest extends AndroidTestCase {
+ private Resources mResources;
+ protected boolean mWithOverlay; // will be set by subclasses
+
+ protected void setUp() {
+ mResources = getContext().getResources();
+ }
+
+ private int calculateRawResourceChecksum(int resId) throws Throwable {
+ InputStream input = null;
+ try {
+ input = mResources.openRawResource(resId);
+ int ch, checksum = 0;
+ while ((ch = input.read()) != -1) {
+ checksum = (checksum + ch) % 0xffddbb00;
+ }
+ return checksum;
+ } finally {
+ input.close();
+ }
+ }
+
+ private void setLocale(String code) {
+ Locale locale = new Locale(code);
+ Locale.setDefault(locale);
+ Configuration config = new Configuration();
+ config.locale = locale;
+ mResources.updateConfiguration(config, mResources.getDisplayMetrics());
+ }
+
+ private void assertResource(int resId, boolean ewo, boolean ew) throws Throwable {
+ boolean expected = mWithOverlay ? ew : ewo;
+ boolean actual = mResources.getBoolean(resId);
+ assertEquals(expected, actual);
+ }
+
+ private void assertResource(int resId, String ewo, String ew) throws Throwable {
+ String expected = mWithOverlay ? ew : ewo;
+ String actual = mResources.getString(resId);
+ assertEquals(expected, actual);
+ }
+
+ private void assertResource(int resId, int[] ewo, int[] ew) throws Throwable {
+ int[] expected = mWithOverlay ? ew : ewo;
+ int[] actual = mResources.getIntArray(resId);
+ assertEquals("length:", expected.length, actual.length);
+ for (int i = 0; i < actual.length; ++i) {
+ assertEquals("index " + i + ":", actual[i], expected[i]);
+ }
+ }
+
+ public void testBooleanOverlay() throws Throwable {
+ // config_automatic_brightness_available has overlay (default config)
+ final int resId = com.android.internal.R.bool.config_automatic_brightness_available;
+ assertResource(resId, false, true);
+ }
+
+ public void testBoolean() throws Throwable {
+ // config_bypass_keyguard_if_slider_open has no overlay
+ final int resId = com.android.internal.R.bool.config_bypass_keyguard_if_slider_open;
+ assertResource(resId, true, true);
+ }
+
+ public void testStringOverlay() throws Throwable {
+ // phoneTypeCar has an overlay (default config), which shouldn't shadow
+ // the Swedish translation
+ final int resId = com.android.internal.R.string.phoneTypeCar;
+ setLocale("sv_SE");
+ assertResource(resId, "Bil", "Bil");
+ }
+
+ public void testStringSwedishOverlay() throws Throwable {
+ // phoneTypeWork has overlay (no default config, only for lang=sv)
+ final int resId = com.android.internal.R.string.phoneTypeWork;
+ setLocale("en_US");
+ assertResource(resId, "Work", "Work");
+ setLocale("sv_SE");
+ assertResource(resId, "Arbete", "Jobb");
+ }
+
+ public void testString() throws Throwable {
+ // phoneTypeHome has no overlay
+ final int resId = com.android.internal.R.string.phoneTypeHome;
+ setLocale("en_US");
+ assertResource(resId, "Home", "Home");
+ setLocale("sv_SE");
+ assertResource(resId, "Hem", "Hem");
+ }
+
+ public void testIntegerArrayOverlay() throws Throwable {
+ // config_scrollBarrierVibePattern has overlay (default config)
+ final int resId = com.android.internal.R.array.config_scrollBarrierVibePattern;
+ assertResource(resId, new int[]{0, 15, 10, 10}, new int[]{100, 200, 300});
+ }
+
+ public void testIntegerArray() throws Throwable {
+ // config_virtualKeyVibePattern has no overlay
+ final int resId = com.android.internal.R.array.config_virtualKeyVibePattern;
+ final int[] expected = {0, 10, 20, 30};
+ assertResource(resId, expected, expected);
+ }
+
+ public void testAsset() throws Throwable {
+ // drawable/default_background.jpg has overlay (default config)
+ final int resId = com.android.internal.R.drawable.default_wallpaper;
+ int actual = calculateRawResourceChecksum(resId);
+ int expected = mWithOverlay ? 0x000051da : 0x0014ebce;
+ assertEquals(expected, actual);
+ }
+}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
new file mode 100644
index 0000000..1292d03
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithOverlayTest.java
@@ -0,0 +1,7 @@
+package com.android.overlaytest;
+
+public class WithOverlayTest extends OverlayBaseTest {
+ public WithOverlayTest() {
+ mWithOverlay = true;
+ }
+}
diff --git a/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
new file mode 100644
index 0000000..630ff8f
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTest/src/com/android/overlaytest/WithoutOverlayTest.java
@@ -0,0 +1,7 @@
+package com.android.overlaytest;
+
+public class WithoutOverlayTest extends OverlayBaseTest {
+ public WithoutOverlayTest() {
+ mWithOverlay = false;
+ }
+}
diff --git a/core/tests/overlaytests/OverlayTestOverlay/Android.mk b/core/tests/overlaytests/OverlayTestOverlay/Android.mk
new file mode 100644
index 0000000..cf32c9f
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_SDK_VERSION := current
+
+LOCAL_PACKAGE_NAME := com.android.overlaytest.overlay
+
+LOCAL_AAPT_FLAGS := -o
+
+include $(BUILD_PACKAGE)
diff --git a/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml b/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
new file mode 100644
index 0000000..bcbb0d1
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/AndroidManifest.xml
@@ -0,0 +1,6 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.overlaytest.overlay"
+ android:versionCode="1"
+ android:versionName="1.0">
+ <overlay-package android:name="android"/>
+</manifest>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg b/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg
new file mode 100644
index 0000000..0d944d0
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/drawable/default_wallpaper.jpg
Binary files differ
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml b/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml
new file mode 100644
index 0000000..bc52367
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/values-sv/config.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <string name="phoneTypeWork">Jobb</string>
+</resources>
diff --git a/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml b/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
new file mode 100644
index 0000000..794f475
--- /dev/null
+++ b/core/tests/overlaytests/OverlayTestOverlay/res/values/config.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+ <bool name="config_automatic_brightness_available">true</bool>
+ <string name="phoneTypeCar">Automobile</string>
+ <integer-array name="config_scrollBarrierVibePattern">
+ <item>100</item>
+ <item>200</item>
+ <item>300</item>
+ </integer-array>
+ <!-- The following integer does not exist in the original package. Idmap
+ generation should therefore ignore it. -->
+ <integer name="integer_not_in_original_package">0</integer>
+</resources>
diff --git a/core/tests/overlaytests/README b/core/tests/overlaytests/README
new file mode 100644
index 0000000..4b3e6f2
--- /dev/null
+++ b/core/tests/overlaytests/README
@@ -0,0 +1,15 @@
+Unit tests for runtime resource overlay
+=======================================
+
+As of this writing, runtime resource overlay is only triggered for
+/system/framework/framework-res.apk. Because of this, installation of
+overlay packages require the Android platform be rebooted. However, the
+regular unit tests (triggered via development/testrunner/runtest.py)
+cannot handle reboots. As a workaround, this directory contains a shell
+script which will trigger the tests in a non-standard way.
+
+Once runtime resource overlay may be applied to applications, the tests
+in this directory should be moved to core/tests/coretests. Also, by
+applying runtime resource overlay to a dedicated test application, the
+test cases would not need to assume default values for non-overlaid
+resources.
diff --git a/core/tests/overlaytests/runtests.sh b/core/tests/overlaytests/runtests.sh
new file mode 100755
index 0000000..0ad9efb
--- /dev/null
+++ b/core/tests/overlaytests/runtests.sh
@@ -0,0 +1,89 @@
+#!/bin/bash
+
+adb="adb"
+if [[ $# -gt 0 ]]; then
+ adb="adb $*" # for setting -e, -d or -s <serial>
+fi
+
+function atexit()
+{
+ local retval=$?
+
+ if [[ $retval -eq 0 ]]; then
+ rm $log
+ else
+ echo "There were errors, please check log at $log"
+ fi
+}
+
+log=$(mktemp)
+trap "atexit" EXIT
+failures=0
+
+function compile_module()
+{
+ local android_mk="$1"
+
+ echo "Compiling .${android_mk:${#PWD}}"
+ ONE_SHOT_MAKEFILE="$android_mk" make -C "../../../../../" files | tee -a $log
+ if [[ ${PIPESTATUS[0]} -ne 0 ]]; then
+ exit 1
+ fi
+}
+
+function wait_for_boot_completed()
+{
+ echo "Rebooting device"
+ $adb wait-for-device logcat -c
+ $adb wait-for-device logcat | grep -m 1 -e 'PowerManagerService.*bootCompleted' >/dev/null
+}
+
+function disable_overlay()
+{
+ echo "Disabling overlay"
+ $adb shell rm /vendor/overlay/framework/framework-res.apk
+ $adb shell rm /data/resource-cache/vendor@overlay@framework@framework-res.apk@idmap
+}
+
+function enable_overlay()
+{
+ echo "Enabling overlay"
+ $adb shell ln -s /data/app/com.android.overlaytest.overlay.apk /vendor/overlay/framework/framework-res.apk
+}
+
+function instrument()
+{
+ local class="$1"
+
+ echo "Instrumenting $class"
+ $adb shell am instrument -w -e class $class com.android.overlaytest/android.test.InstrumentationTestRunner | tee -a $log
+}
+
+function sync()
+{
+ echo "Syncing to device"
+ $adb remount | tee -a $log
+ $adb sync data | tee -a $log
+}
+
+# build and sync
+compile_module "$PWD/OverlayTest/Android.mk"
+compile_module "$PWD/OverlayTestOverlay/Android.mk"
+sync
+
+# instrument test (without overlay)
+$adb shell stop
+disable_overlay
+$adb shell start
+wait_for_boot_completed
+instrument "com.android.overlaytest.WithoutOverlayTest"
+
+# instrument test (with overlay)
+$adb shell stop
+enable_overlay
+$adb shell start
+wait_for_boot_completed
+instrument "com.android.overlaytest.WithOverlayTest"
+
+# cleanup
+exit $(grep -c -e '^FAILURES' $log)
diff --git a/data/etc/android.hardware.usb.accessory.xml b/data/etc/android.hardware.usb.accessory.xml
new file mode 100644
index 0000000..80a0904
--- /dev/null
+++ b/data/etc/android.hardware.usb.accessory.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<!-- This is the standard feature indicating that the device supports USB accessories. -->
+<permissions>
+ <feature name="android.hardware.usb.accessory" />
+ <library name="com.android.future.usb.accessory"
+ file="/system/framework/com.android.future.usb.accessory.jar" />
+</permissions>
diff --git a/data/fonts/DroidSans-Bold.ttf b/data/fonts/DroidSans-Bold.ttf
index 7ac04b6..d065b64 100644
--- a/data/fonts/DroidSans-Bold.ttf
+++ b/data/fonts/DroidSans-Bold.ttf
Binary files differ
diff --git a/data/fonts/DroidSans.ttf b/data/fonts/DroidSans.ttf
index 767c63a..ad1efca 100644
--- a/data/fonts/DroidSans.ttf
+++ b/data/fonts/DroidSans.ttf
Binary files differ
diff --git a/data/fonts/DroidSansArabic.ttf b/data/fonts/DroidSansArabic.ttf
index 660e2a9..bdefaac 100644
--- a/data/fonts/DroidSansArabic.ttf
+++ b/data/fonts/DroidSansArabic.ttf
Binary files differ
diff --git a/data/fonts/DroidSansFallback.ttf b/data/fonts/DroidSansFallback.ttf
index 206621f..ba9d76f 100644
--- a/data/fonts/DroidSansFallback.ttf
+++ b/data/fonts/DroidSansFallback.ttf
Binary files differ
diff --git a/data/fonts/DroidSansMono.ttf b/data/fonts/DroidSansMono.ttf
index 6e79dad..a007071 100644
--- a/data/fonts/DroidSansMono.ttf
+++ b/data/fonts/DroidSansMono.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-Bold.ttf b/data/fonts/DroidSerif-Bold.ttf
index 85d6c6b..838d255 100644
--- a/data/fonts/DroidSerif-Bold.ttf
+++ b/data/fonts/DroidSerif-Bold.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-BoldItalic.ttf b/data/fonts/DroidSerif-BoldItalic.ttf
index 9d8e798..0b1601f 100644
--- a/data/fonts/DroidSerif-BoldItalic.ttf
+++ b/data/fonts/DroidSerif-BoldItalic.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-Italic.ttf b/data/fonts/DroidSerif-Italic.ttf
index 6acc86d..2972809 100644
--- a/data/fonts/DroidSerif-Italic.ttf
+++ b/data/fonts/DroidSerif-Italic.ttf
Binary files differ
diff --git a/data/fonts/DroidSerif-Regular.ttf b/data/fonts/DroidSerif-Regular.ttf
index 8c1c2c4..5b4fe81 100644
--- a/data/fonts/DroidSerif-Regular.ttf
+++ b/data/fonts/DroidSerif-Regular.ttf
Binary files differ
diff --git a/docs/html/guide/developing/tools/traceview.jd b/docs/html/guide/developing/tools/traceview.jd
index 95ae823..b681bba 100644
--- a/docs/html/guide/developing/tools/traceview.jd
+++ b/docs/html/guide/developing/tools/traceview.jd
@@ -120,7 +120,7 @@ the emulator host machine:</p>
the first row show the extent (entry to exit) of all the calls to the selected
method. The method in this case is LoadListener.nativeFinished() and it was
selected in the profile view. </p>
-<p><img src="/images/traceview_timeline.png" alt="Traceview timeline panel" width="893" height="284"></p>
+<p><img src="{@docRoot}images/traceview_timeline.png" alt="Traceview timeline panel" width="893" height="284"></p>
<a name="profilepanel"></a>
<h3>Profile Panel</h3>
<p>The image below shows the profile pane. The profile pane shows a
@@ -137,7 +137,7 @@ the emulator host machine:</p>
view, we can see that there were 14 calls to LoadListener.nativeFinished(); looking
at the timeline panel shows that one of those calls took an unusually
long time.</p>
-<p><img src="/images/traceview_profile.png" alt="Traceview profile panel." width="892" height="630"></p>
+<p><img src="{@docRoot}images/traceview_profile.png" alt="Traceview profile panel." width="892" height="630"></p>
<a name="format"></a>
<h2>Traceview File Format</h2>
diff --git a/docs/html/guide/market/billing/billing_integrate.jd b/docs/html/guide/market/billing/billing_integrate.jd
index 0f081a5..6e40f32 100755
--- a/docs/html/guide/market/billing/billing_integrate.jd
+++ b/docs/html/guide/market/billing/billing_integrate.jd
@@ -223,7 +223,7 @@ Billing package contains the sample application and the AIDL file. </div>
<pre>
try {
boolean bindResult = mContext.bindService(
- new Intent(IMarketBillingService.class.getName()), this, Context.BIND_AUTO_CREATE);
+ new Intent("com.android.vending.billing.MarketBillingService.BIND"), this, Context.BIND_AUTO_CREATE);
if (bindResult) {
Log.i(TAG, "Service bind successful.");
} else {
diff --git a/docs/html/guide/topics/nfc/index.jd b/docs/html/guide/topics/nfc/index.jd
index 3992099..c4917b4 100644
--- a/docs/html/guide/topics/nfc/index.jd
+++ b/docs/html/guide/topics/nfc/index.jd
@@ -31,29 +31,33 @@ page.title=Near Field Communication
</div>
</div>
- <p>Near Field Communication (NFC) is a set of short-range wireless technologies, similar to RFID.
- It typically requires a distance of 4 cm or less and operates at 13.56mhz and at rates ranging
- from 106 kbit/s to 848 kbit/s. NFC communication always involves an initiator and a target. The
- initiator actively generates an RF field that can power a passive target. This enables NFC
- targets to take very simple form factors such as tags, stickers or cards that do not require
- power. NFC peer-to-peer communication is also possible, where both devices are powered.</p>
-
- <p>Compared to other wireless technologies such as Bluetooth or WiFi, NFC provides much lower
- bandwidth and range, but provides low-cost, un-powered targets and do not require discovery or
- pairing. Users interact with NFC tags with just a tap. Targets can range in complexity. Simple
- tags just offer read and write capabilities, sometimes with one-time programmable areas to make
- the card read-only. More complex tags offer math operations, and have cryptographic hardware to
- authenticate access to a sector. The most sophisticated tags contain operating environments,
- allowing complex interactions with applets that are running on the tag.</p>
-
- <p>An Android device with NFC hardware typically acts as an initiator. This mode is also known as
- NFC reader/writer. The device actively looks for NFC tags and starts activities to handle them in
- this mode. In Android 2.3.3, devices also have some limited peer-to-peer support.</p>
+ <p>Near Field Communication (NFC) is a set of short-range wireless technologies, typically
+ requiring a distance of 4cm or less. NFC operates at 13.56mhz, and at rates ranging
+ from 106 kbit/s to 848 kbit/s. NFC communication always involves an initiator and a target.
+ The initiator actively generates an RF field that can power a passive target. This
+ enables NFC targets to take very simple form factors such as tags, stickers or cards that do
+ not require power. NFC peer-to-peer communication is also possible, where both devices
+ are powered.
+ <p>
+ Compared to other wireless technologies such as Bluetooth or WiFi, NFC provides much lower
+ bandwidth and range, but enables low-cost, un-powered targets
+ and does not require discovery or pairing. Interactions can be initiated with just a tap.
+ <p>
+ An Android device with NFC hardware will typically act as an initiator when the screen is
+ on. This mode is also known as NFC reader/writer. It will actively look for NFC tags and start
+ activities to handle them. Android 2.3.3 also has some limited P2P support.
+ <p>
+ Tags can range in complexity, simple tags just offer read/write semantics, sometimes
+ with one-time-programmable areas to make the card read-only. More complex tags offer
+ math operations, and have cryptographic hardware to authenticate access to a sector.
+ The most sophisticated tags contain operating environments, allowing
+ complex interactions with code executing on the tag.
<h2 id="api">API Overview</h2>
- <p>The {@link android.nfc} package contain the high-level classes to interact with the local
- device's NFC adapter, to represent discovered tags, and to use the NDEF data format.</p>
+ <p>The {@link android.nfc} package contains the high-level classes to interact
+ with the local device's NFC adapter, to represent discovered tags, and to use
+ the NDEF data format.
<table>
<tr>
@@ -65,44 +69,52 @@ page.title=Near Field Communication
<tr>
<td>{@link android.nfc.NfcManager}</td>
- <td>A high level manager class that enumerates the NFC adapters on this Android device. Since
- most Android devices only have one NFC adapter, you can just use the static helper {@link
- android.nfc.NfcAdapter#getDefaultAdapter()} for most situations.</td>
+
+ <td>A high level manager class that enumerates the NFC adapters on this Android device.
+ Since most Android devices only have one NFC adapter, you can just use the static helper
+ {@link android.nfc.NfcAdapter#getDefaultAdapter(Context)} for most situations.</td>
</tr>
<tr>
<td>{@link android.nfc.NfcAdapter}</td>
- <td>Represents the local NFC adapter and defines the Intents that are used in the tag
- dispatch system. It provides methods to register for foreground tag dispatching and
- foreground NDEF pushing. Foreground NDEF push is the only peer-to-peer support that is
- currently provided in Android.</td>
+ <td>Represents the local NFC adapter. Defines the intent's used to request
+ tag dispatch to your activity, and provides methods to register for foreground
+ tag dispatch and foreground NDEF push. Foreground NDEF push is the only
+ peer-to-peer support that is currently provided in Android.</td>
</tr>
<tr>
<td>{@link android.nfc.NdefMessage} and {@link android.nfc.NdefRecord}</td>
- <td>NDEF is an NFC Forum defined data structure, designed to efficiently store data on NFC
- tags, such as Text, URLs, and other MIME types. An {@link android.nfc.NdefMessage} acts as a
+ <td>NDEF is an NFC Forum defined data structure, designed to efficiently
+ store data on NFC tags, such as text, URL's, and other MIME types. A
+ {@link android.nfc.NdefMessage} acts as a
container for the data that you want to transmit or read. One {@link android.nfc.NdefMessage}
- object contains zero or more {@link android.nfc.NdefRecord}s. Each NDEF Record has a type
- such as Text, URL, Smart Poster, or any MIME type. The type of the first NDEF Record in the
- NDEF message is used to dispatch a tag to an Activity.</td>
+ object contains zero or more {@link android.nfc.NdefRecord}s. Each NDEF record
+ has a type such as text, URL, smart poster, or any MIME data. The type of the
+ first NDEF record in the NDEF message is used to dispatch a tag to an activity
+ on Android.</td>
</tr>
<tr>
<td>{@link android.nfc.Tag}</td>
- <td>Represents a passive NFC target. These can come in many form factors such as a tag, card,
- FOB, or an even more complex device doing card emulation. When a tag is discovered, a {@link
- android.nfc.Tag} object is created and wrapped inside an Intent. The dispatch system sends
- the Intent to a compatible Activity <code>startActivity()</code>. You can use the {@link
+ <td>Represents a passive NFC target. These can come in many form factors such as
+ a tag, card, key fob, or even a phone doing card emulation. When a tag is
+ discovered, a {@link android.nfc.Tag} object is created and wrapped inside an
+ Intent. The NFC dispatch system sends the intent to a compatible actvitiy
+ using <code>startActivity()</code>. You can use the {@link
android.nfc.Tag#getTechList getTechList()} method to determine the technologies supported by
this tag and create the corresponding {@link android.nfc.tech.TagTechnology} object with one
of classes provided by {@link android.nfc.tech}.</td>
</tr>
</table>
+ <p>The {@link android.nfc.tech} package contains classes to query properties
+ and perform I/O operations on a tag. The classes are divided to represent different
+ NFC technologies that can be available on a tag.
+
<p>The {@link android.nfc.tech} package contains classes to query properties and perform I/O
operations on a tag. The classes are divided to represent different NFC technologies that can be
available on a Tag:</p>
@@ -117,7 +129,7 @@ page.title=Near Field Communication
<tr>
<td>{@link android.nfc.tech.TagTechnology}</td>
- <td>The interface that all Tag Technology classes must implement.</td>
+ <td>The interface that all tag technology classes must implement.</td>
</tr>
<tr>
@@ -153,8 +165,8 @@ page.title=Near Field Communication
<tr>
<td>{@link android.nfc.tech.Ndef}</td>
- <td>Provides access to NDEF data and operations on NFC Tags that have been formatted as
- NDEF.</td>
+ <td>Provides access to NDEF data and operations on NFC tags that have been formatted as NDEF.
+ </td>
</tr>
<tr>
@@ -166,15 +178,15 @@ page.title=Near Field Communication
<tr>
<td>{@link android.nfc.tech.MifareClassic}</td>
- <td>Provides access to MIFARE Classic properties and I/O operations. Not all Android devices
- provide implementations for this class.</td>
+ <td>Provides access to MIFARE Classic properties and I/O operations, if this
+ Android device supports MIFARE.</td>
</tr>
<tr>
<td>{@link android.nfc.tech.MifareUltralight}</td>
- <td>Provides access to MIFARE Ultralight properties and I/O operations. Not all Android
- devices provide implementations for this class.</td>
+ <td>Provides access to MIFARE Ultralight properties and I/O operations, if this
+ Android device supports MIFARE.</td>
</tr>
</table>
@@ -191,12 +203,13 @@ page.title=Near Field Communication
</li>
<li>The minimum SDK version that your application can support. API level 9 only supports
- limited tag dispatching with {@link android.nfc.NfcAdapter#ACTION_TAG_DISCOVERED}, and only
- gives access to NDEF messages via the {@link android.nfc.NfcAdapter#EXTRA_NDEF_MESSAGES} extra.
- No other tag properties or I/O operations are accessible. API level 10 adds comprehensive
- reader/writer support, so you probably want to use this for more functionality.
- <pre class="pretty-print">
-&lt;uses-sdk android:minSdkVersion="9|10"/&gt;
+ limited tag dispatch via {@link android.nfc.NfcAdapter#ACTION_TAG_DISCOVERED},
+ and only gives access to NDEF messages via the {@link android.nfc.NfcAdapter#EXTRA_NDEF_MESSAGES}
+ extra. No other tag properties or I/O operations are accessible. You probably want
+ to use API level 10 which includes comprehensive reader/writer support.
+
+<pre class="pretty-print">
+&lt;uses-sdk android:minSdkVersion="10"/&gt;
</pre>
</li>
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index bfcd14e..551361f 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -3,7 +3,7 @@ sdk.redirect=0
sdk.win_installer=installer_r09-windows.exe
sdk.win_installer_bytes=32828818
-sdk.win_installer_checksum=a0185701ac0d635a4fbf8169ac949a3c5b3d31e0
+sdk.win_installer_checksum=ef92e643731f820360e036eb11658656
sdk.win_download=android-sdk_r09-windows.zip
sdk.win_bytes=32779808
diff --git a/graphics/java/android/graphics/Movie.java b/graphics/java/android/graphics/Movie.java
index 95e9946..4a33453 100644
--- a/graphics/java/android/graphics/Movie.java
+++ b/graphics/java/android/graphics/Movie.java
@@ -46,6 +46,8 @@ public class Movie {
public static native Movie decodeByteArray(byte[] data, int offset,
int length);
+ private static native void nativeDestructor(int nativeMovie);
+
public static Movie decodeFile(String pathName) {
InputStream is;
try {
@@ -57,6 +59,15 @@ public class Movie {
return decodeTempStream(is);
}
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ nativeDestructor(mNativeMovie);
+ } finally {
+ super.finalize();
+ }
+ }
+
private static Movie decodeTempStream(InputStream is) {
Movie moov = null;
try {
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index 0b8465e..501374b 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -474,10 +474,8 @@ public class BitmapDrawable extends Drawable {
mBitmapState = state;
if (res != null) {
mTargetDensity = res.getDisplayMetrics().densityDpi;
- } else if (state != null) {
- mTargetDensity = state.mTargetDensity;
} else {
- mTargetDensity = DisplayMetrics.DENSITY_DEFAULT;
+ mTargetDensity = state.mTargetDensity;
}
setBitmap(state.mBitmap);
}
diff --git a/include/utils/AssetManager.h b/include/utils/AssetManager.h
index 9e2bf37..a8c7ddb 100644
--- a/include/utils/AssetManager.h
+++ b/include/utils/AssetManager.h
@@ -222,6 +222,7 @@ private:
{
String8 path;
FileType type;
+ String8 idmap;
};
Asset* openInPathLocked(const char* fileName, AccessMode mode,
@@ -262,6 +263,16 @@ private:
void setLocaleLocked(const char* locale);
void updateResourceParamsLocked() const;
+ bool createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath);
+
+ bool isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath);
+
+ Asset* openIdmapLocked(const struct asset_path& ap) const;
+
+ bool getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename, uint32_t* pCrc);
+
class SharedZip : public RefBase {
public:
static sp<SharedZip> get(const String8& path);
diff --git a/include/utils/RefBase.h b/include/utils/RefBase.h
index 9c64ac0..c24c0db 100644
--- a/include/utils/RefBase.h
+++ b/include/utils/RefBase.h
@@ -31,13 +31,10 @@ template<typename T> class wp;
// ---------------------------------------------------------------------------
-#define COMPARE(_op_) \
+#define COMPARE_WEAK(_op_) \
inline bool operator _op_ (const sp<T>& o) const { \
return m_ptr _op_ o.m_ptr; \
} \
-inline bool operator _op_ (const wp<T>& o) const { \
- return m_ptr _op_ o.m_ptr; \
-} \
inline bool operator _op_ (const T* o) const { \
return m_ptr _op_ o; \
} \
@@ -46,12 +43,18 @@ inline bool operator _op_ (const sp<U>& o) const { \
return m_ptr _op_ o.m_ptr; \
} \
template<typename U> \
-inline bool operator _op_ (const wp<U>& o) const { \
+inline bool operator _op_ (const U* o) const { \
+ return m_ptr _op_ o; \
+}
+
+#define COMPARE(_op_) \
+COMPARE_WEAK(_op_) \
+inline bool operator _op_ (const wp<T>& o) const { \
return m_ptr _op_ o.m_ptr; \
} \
template<typename U> \
-inline bool operator _op_ (const U* o) const { \
- return m_ptr _op_ o; \
+inline bool operator _op_ (const wp<U>& o) const { \
+ return m_ptr _op_ o.m_ptr; \
}
// ---------------------------------------------------------------------------
@@ -274,13 +277,43 @@ public:
inline T* unsafe_get() const { return m_ptr; }
// Operators
-
- COMPARE(==)
- COMPARE(!=)
- COMPARE(>)
- COMPARE(<)
- COMPARE(<=)
- COMPARE(>=)
+
+ COMPARE_WEAK(==)
+ COMPARE_WEAK(!=)
+ COMPARE_WEAK(>)
+ COMPARE_WEAK(<)
+ COMPARE_WEAK(<=)
+ COMPARE_WEAK(>=)
+
+ inline bool operator == (const wp<T>& o) const {
+ return (m_ptr == o.m_ptr) && (m_refs == o.m_refs);
+ }
+ template<typename U>
+ inline bool operator == (const wp<U>& o) const {
+ return m_ptr == o.m_ptr;
+ }
+
+ inline bool operator > (const wp<T>& o) const {
+ return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
+ }
+ template<typename U>
+ inline bool operator > (const wp<U>& o) const {
+ return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr);
+ }
+
+ inline bool operator < (const wp<T>& o) const {
+ return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
+ }
+ template<typename U>
+ inline bool operator < (const wp<U>& o) const {
+ return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr);
+ }
+ inline bool operator != (const wp<T>& o) const { return m_refs != o.m_refs; }
+ template<typename U> inline bool operator != (const wp<U>& o) const { return !operator == (o); }
+ inline bool operator <= (const wp<T>& o) const { return !operator > (o); }
+ template<typename U> inline bool operator <= (const wp<U>& o) const { return !operator > (o); }
+ inline bool operator >= (const wp<T>& o) const { return !operator < (o); }
+ template<typename U> inline bool operator >= (const wp<U>& o) const { return !operator < (o); }
private:
template<typename Y> friend class sp;
@@ -294,6 +327,7 @@ template <typename T>
TextOutput& operator<<(TextOutput& to, const wp<T>& val);
#undef COMPARE
+#undef COMPARE_WEAK
// ---------------------------------------------------------------------------
// No user serviceable parts below here.
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index ab7b973..10baa11 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1735,9 +1735,9 @@ public:
~ResTable();
status_t add(const void* data, size_t size, void* cookie,
- bool copyData=false);
+ bool copyData=false, const void* idmap = NULL);
status_t add(Asset* asset, void* cookie,
- bool copyData=false);
+ bool copyData=false, const void* idmap = NULL);
status_t add(ResTable* src);
status_t getError() const;
@@ -1981,6 +1981,24 @@ public:
void getLocales(Vector<String8>* locales) const;
+ // Generate an idmap.
+ //
+ // Return value: on success: NO_ERROR; caller is responsible for free-ing
+ // outData (using free(3)). On failure, any status_t value other than
+ // NO_ERROR; the caller should not free outData.
+ status_t createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
+ void** outData, size_t* outSize) const;
+
+ enum {
+ IDMAP_HEADER_SIZE_BYTES = 3 * sizeof(uint32_t),
+ };
+ // Retrieve idmap meta-data.
+ //
+ // This function only requires the idmap header (the first
+ // IDMAP_HEADER_SIZE_BYTES) bytes of an idmap file.
+ static bool getIdmapInfo(const void* idmap, size_t size,
+ uint32_t* pOriginalCrc, uint32_t* pOverlayCrc);
+
#ifndef HAVE_ANDROID_OS
void print(bool inclValues) const;
static String8 normalizeForOutput(const char* input);
@@ -1994,7 +2012,7 @@ private:
struct bag_set;
status_t add(const void* data, size_t size, void* cookie,
- Asset* asset, bool copyData);
+ Asset* asset, bool copyData, const Asset* idmap);
ssize_t getResourcePackageIndex(uint32_t resID) const;
ssize_t getEntry(
@@ -2003,7 +2021,7 @@ private:
const ResTable_type** outType, const ResTable_entry** outEntry,
const Type** outTypeClass) const;
status_t parsePackage(
- const ResTable_package* const pkg, const Header* const header);
+ const ResTable_package* const pkg, const Header* const header, uint32_t idmap_id);
void print_value(const Package* pkg, const Res_value& value) const;
diff --git a/libs/ui/GraphicBufferAllocator.cpp b/libs/ui/GraphicBufferAllocator.cpp
index 9847a5f..fa46ab7 100644
--- a/libs/ui/GraphicBufferAllocator.cpp
+++ b/libs/ui/GraphicBufferAllocator.cpp
@@ -63,7 +63,7 @@ void GraphicBufferAllocator::dump(String8& result) const
const size_t c = list.size();
for (size_t i=0 ; i<c ; i++) {
const alloc_rec_t& rec(list.valueAt(i));
- snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %8X | 0x%08x\n",
+ snprintf(buffer, SIZE, "%10p: %7.2f KiB | %4u (%4u) x %4u | %2d | 0x%08x\n",
list.keyAt(i), rec.size/1024.0f,
rec.w, rec.s, rec.h, rec.format, rec.usage);
result.append(buffer);
diff --git a/libs/ui/InputDispatcher.cpp b/libs/ui/InputDispatcher.cpp
index 421ad663..c0872e5 100644
--- a/libs/ui/InputDispatcher.cpp
+++ b/libs/ui/InputDispatcher.cpp
@@ -37,7 +37,9 @@
// Log debug messages about the app switch latency optimization.
#define DEBUG_APP_SWITCH 0
+#include <android/input.h>
#include <cutils/log.h>
+#include <ui/Input.h>
#include <ui/InputDispatcher.h>
#include <ui/PowerManager.h>
@@ -592,10 +594,6 @@ InputDispatcher::KeyEntry* InputDispatcher::synthesizeKeyRepeatLocked(
// mKeyRepeatState.lastKeyEntry in addition to the one we return.
entry->refCount += 1;
- if (entry->repeatCount == 1) {
- entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
- }
-
mKeyRepeatState.nextRepeatTime = currentTime + keyRepeatDelay;
return entry;
}
@@ -645,6 +643,12 @@ bool InputDispatcher::dispatchKeyLocked(
resetKeyRepeatLocked();
}
+ if (entry->repeatCount == 1) {
+ entry->flags |= AKEY_EVENT_FLAG_LONG_PRESS;
+ } else {
+ entry->flags &= ~AKEY_EVENT_FLAG_LONG_PRESS;
+ }
+
entry->dispatchInProgress = true;
resetTargetsLocked();
@@ -2092,6 +2096,26 @@ void InputDispatcher::notifyKey(nsecs_t eventTime, int32_t deviceId, int32_t sou
return;
}
+ /* According to http://source.android.com/porting/keymaps_keyboard_input.html
+ * Key definitions: Key definitions follow the syntax key SCANCODE KEYCODE [FLAGS...],
+ * where SCANCODE is a number, KEYCODE is defined in your specific keylayout file
+ * (android.keylayout.xxx), and potential FLAGS are defined as follows:
+ * SHIFT: While pressed, the shift key modifier is set
+ * ALT: While pressed, the alt key modifier is set
+ * CAPS: While pressed, the caps lock key modifier is set
+ * Since KeyEvent.java doesn't check if Cap lock is ON and we don't have a
+ * modifer state for cap lock, we will not support it.
+ */
+ if (policyFlags & POLICY_FLAG_ALT) {
+ metaState |= AMETA_ALT_ON | AMETA_ALT_LEFT_ON;
+ }
+ if (policyFlags & POLICY_FLAG_ALT_GR) {
+ metaState |= AMETA_ALT_ON | AMETA_ALT_RIGHT_ON;
+ }
+ if (policyFlags & POLICY_FLAG_SHIFT) {
+ metaState |= AMETA_SHIFT_ON | AMETA_SHIFT_LEFT_ON;
+ }
+
policyFlags |= POLICY_FLAG_TRUSTED;
mPolicy->interceptKeyBeforeQueueing(eventTime, deviceId, action, /*byref*/ flags,
keyCode, scanCode, /*byref*/ policyFlags);
diff --git a/libs/ui/InputReader.cpp b/libs/ui/InputReader.cpp
index 34e44e4..336d489 100644
--- a/libs/ui/InputReader.cpp
+++ b/libs/ui/InputReader.cpp
@@ -547,9 +547,9 @@ int32_t InputReader::getState(int32_t deviceId, uint32_t sourceMask, int32_t cod
for (size_t i = 0; i < numDevices; i++) {
InputDevice* device = mDevices.valueAt(i);
if (! device->isIgnored() && sourcesMatchMask(device->getSources(), sourceMask)) {
- result = (device->*getStateFunc)(sourceMask, code);
- if (result >= AKEY_STATE_DOWN) {
- return result;
+ int32_t state = (device->*getStateFunc)(sourceMask, code);
+ if (state > result) {
+ result = state;
}
}
}
@@ -737,9 +737,9 @@ int32_t InputDevice::getState(uint32_t sourceMask, int32_t code, GetStateFunc ge
for (size_t i = 0; i < numMappers; i++) {
InputMapper* mapper = mMappers[i];
if (sourcesMatchMask(mapper->getSources(), sourceMask)) {
- result = (mapper->*getStateFunc)(sourceMask, code);
- if (result >= AKEY_STATE_DOWN) {
- return result;
+ int32_t state = (mapper->*getStateFunc)(sourceMask, code);
+ if (state > result) {
+ result = state;
}
}
}
diff --git a/libs/usb/Android.mk b/libs/usb/Android.mk
new file mode 100644
index 0000000..129828f
--- /dev/null
+++ b/libs/usb/Android.mk
@@ -0,0 +1,27 @@
+#
+# 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.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE:= com.android.future.usb.accessory
+
+include $(BUILD_JAVA_LIBRARY)
diff --git a/libs/usb/src/com/android/future/usb/UsbAccessory.java b/libs/usb/src/com/android/future/usb/UsbAccessory.java
new file mode 100644
index 0000000..0f965d7
--- /dev/null
+++ b/libs/usb/src/com/android/future/usb/UsbAccessory.java
@@ -0,0 +1,136 @@
+/*
+ * 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.future.usb;
+
+/**
+ * A class representing a USB accessory.
+ */
+public class UsbAccessory {
+
+ private final String mManufacturer;
+ private final String mModel;
+ private final String mDescription;
+ private final String mVersion;
+ private final String mUri;
+ private final String mSerial;
+
+ /* package */ UsbAccessory(android.hardware.usb.UsbAccessory accessory) {
+ mManufacturer = accessory.getManufacturer();
+ mModel = accessory.getModel();
+ mDescription = accessory.getDescription();
+ mVersion = accessory.getVersion();
+ mUri = accessory.getUri();
+ mSerial = accessory.getSerial();
+ }
+
+ /**
+ * Returns the manufacturer of the accessory.
+ *
+ * @return the accessory manufacturer
+ */
+ public String getManufacturer() {
+ return mManufacturer;
+ }
+
+ /**
+ * Returns the model name of the accessory.
+ *
+ * @return the accessory model
+ */
+ public String getModel() {
+ return mModel;
+ }
+
+ /**
+ * Returns a user visible description of the accessory.
+ *
+ * @return the accessory description
+ */
+ public String getDescription() {
+ return mDescription;
+ }
+
+ /**
+ * Returns the version of the accessory.
+ *
+ * @return the accessory version
+ */
+ public String getVersion() {
+ return mVersion;
+ }
+
+ /**
+ * Returns the URI for the accessory.
+ * This is an optional URI that might show information about the accessory
+ * or provide the option to download an application for the accessory
+ *
+ * @return the accessory URI
+ */
+ public String getUri() {
+ return mUri;
+ }
+
+ /**
+ * Returns the unique serial number for the accessory.
+ * This is an optional serial number that can be used to differentiate
+ * between individual accessories of the same model and manufacturer
+ *
+ * @return the unique serial number
+ */
+ public String getSerial() {
+ return mSerial;
+ }
+
+ private static boolean compare(String s1, String s2) {
+ if (s1 == null) return (s2 == null);
+ return s1.equals(s2);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (obj instanceof UsbAccessory) {
+ UsbAccessory accessory = (UsbAccessory)obj;
+ return (compare(mManufacturer, accessory.getManufacturer()) &&
+ compare(mModel, accessory.getModel()) &&
+ compare(mDescription, accessory.getDescription()) &&
+ compare(mVersion, accessory.getVersion()) &&
+ compare(mUri, accessory.getUri()) &&
+ compare(mSerial, accessory.getSerial()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+ (mModel == null ? 0 : mModel.hashCode()) ^
+ (mDescription == null ? 0 : mDescription.hashCode()) ^
+ (mVersion == null ? 0 : mVersion.hashCode()) ^
+ (mUri == null ? 0 : mUri.hashCode()) ^
+ (mSerial == null ? 0 : mSerial.hashCode()));
+ }
+
+ @Override
+ public String toString() {
+ return "UsbAccessory[mManufacturer=" + mManufacturer +
+ ", mModel=" + mModel +
+ ", mDescription=" + mDescription +
+ ", mVersion=" + mVersion +
+ ", mUri=" + mUri +
+ ", mSerial=" + mSerial + "]";
+ }
+}
diff --git a/libs/usb/src/com/android/future/usb/UsbManager.java b/libs/usb/src/com/android/future/usb/UsbManager.java
new file mode 100644
index 0000000..91d8e8a
--- /dev/null
+++ b/libs/usb/src/com/android/future/usb/UsbManager.java
@@ -0,0 +1,186 @@
+/*
+ * 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.future.usb;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.hardware.usb.IUsbManager;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+
+/**
+ * This is a wrapper class for the USB Manager to support USB accessories.
+ *
+ * <p>You can obtain an instance of this class by calling {@link #getInstance}
+ *
+ */
+public class UsbManager {
+ private static final String TAG = "UsbManager";
+
+ /**
+ * Broadcast Action: A broadcast for USB accessory attached event.
+ *
+ * This intent is sent when a USB accessory is attached.
+ * Call {@link #getAccessory(android.content.Intent)} to retrieve the
+ * {@link com.google.android.usb.UsbAccessory} for the attached accessory.
+ */
+ public static final String ACTION_USB_ACCESSORY_ATTACHED =
+ "android.hardware.usb.action.USB_ACCESSORY_ATTACHED";
+
+ /**
+ * Broadcast Action: A broadcast for USB accessory detached event.
+ *
+ * This intent is sent when a USB accessory is detached.
+ * Call {@link #getAccessory(android.content.Intent)} to retrieve the
+ * {@link com.google.android.usb.UsbAccessory} for the attached accessory that was detached.
+ */
+ public static final String ACTION_USB_ACCESSORY_DETACHED =
+ "android.hardware.usb.action.USB_ACCESSORY_DETACHED";
+
+ /**
+ * Name of extra added to the {@link android.app.PendingIntent}
+ * passed into {#requestPermission} or {#requestPermission}
+ * containing a boolean value indicating whether the user granted permission or not.
+ */
+ public static final String EXTRA_PERMISSION_GRANTED = "permission";
+
+ private final Context mContext;
+ private final IUsbManager mService;
+
+ private UsbManager(Context context, IUsbManager service) {
+ mContext = context;
+ mService = service;
+ }
+
+ /**
+ * Returns a new instance of this class.
+ *
+ * @param context the caller's {@link android.content.Context}
+ * @return UsbManager instance.
+ */
+ public static UsbManager getInstance(Context context) {
+ IBinder b = ServiceManager.getService(Context.USB_SERVICE);
+ return new UsbManager(context, IUsbManager.Stub.asInterface(b));
+ }
+
+ /**
+ * Returns the {@link com.google.android.usb.UsbAccessory} for
+ * a {@link #ACTION_USB_ACCESSORY_ATTACHED} or {@link #ACTION_USB_ACCESSORY_ATTACHED}
+ * broadcast Intent. This can also be used to retrieve the accessory from the result
+ * of a call to {#requestPermission}.
+ *
+ * @return UsbAccessory for the intent.
+ */
+ public static UsbAccessory getAccessory(Intent intent) {
+ android.hardware.usb.UsbAccessory accessory =
+ intent.getParcelableExtra(android.hardware.usb.UsbManager.EXTRA_ACCESSORY);
+ if (accessory == null) {
+ return null;
+ } else {
+ return new UsbAccessory(accessory);
+ }
+ }
+
+ /**
+ * Returns a list of currently attached USB accessories.
+ * (in the current implementation there can be at most one)
+ *
+ * @return list of USB accessories, or null if none are attached.
+ */
+ public UsbAccessory[] getAccessoryList() {
+ try {
+ android.hardware.usb.UsbAccessory accessory = mService.getCurrentAccessory();
+ if (accessory == null) {
+ return null;
+ } else {
+ return new UsbAccessory[] { new UsbAccessory(accessory) };
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in getAccessoryList" , e);
+ return null;
+ }
+ }
+
+ /**
+ * Opens a file descriptor for reading and writing data to the USB accessory.
+ *
+ * @param accessory the USB accessory to open
+ * @return file descriptor, or null if the accessor could not be opened.
+ */
+ public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
+ try {
+ return mService.openAccessory(new android.hardware.usb.UsbAccessory(
+ accessory.getManufacturer(),accessory.getModel(),
+ accessory.getDescription(), accessory.getVersion(),
+ accessory.getUri(), accessory.getSerial()));
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in openAccessory" , e);
+ return null;
+ }
+ }
+
+ /**
+ * Returns true if the caller has permission to access the accessory.
+ * Permission might have been granted temporarily via
+ * {@link #requestPermission} or
+ * by the user choosing the caller as the default application for the accessory.
+ *
+ * @param accessory to check permissions for
+ * @return true if caller has permission
+ */
+ public boolean hasPermission(UsbAccessory accessory) {
+ try {
+ return mService.hasAccessoryPermission(new android.hardware.usb.UsbAccessory(
+ accessory.getManufacturer(),accessory.getModel(),
+ accessory.getDescription(), accessory.getVersion(),
+ accessory.getUri(), accessory.getSerial()));
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in hasPermission", e);
+ return false;
+ }
+ }
+
+ /**
+ * Requests temporary permission for the given package to access the accessory.
+ * This may result in a system dialog being displayed to the user
+ * if permission had not already been granted.
+ * Success or failure is returned via the {@link android.app.PendingIntent} pi.
+ * The boolean extra {@link #EXTRA_PERMISSION_GRANTED} will be attached to the
+ * PendingIntent to indicate success or failure.
+ * If successful, this grants the caller permission to access the device only
+ * until the device is disconnected.
+ *
+ * @param accessory to request permissions for
+ * @param pi PendingIntent for returning result
+ */
+ public void requestPermission(UsbAccessory accessory, PendingIntent pi) {
+ try {
+ mService.requestAccessoryPermission(new android.hardware.usb.UsbAccessory(
+ accessory.getManufacturer(),accessory.getModel(),
+ accessory.getDescription(), accessory.getVersion(),
+ accessory.getUri(), accessory.getSerial()),
+ mContext.getPackageName(), pi);
+ } catch (RemoteException e) {
+ Log.e(TAG, "RemoteException in requestPermission", e);
+ }
+ }
+}
diff --git a/libs/usb/tests/AccessoryChat/Android.mk b/libs/usb/tests/AccessoryChat/Android.mk
new file mode 100644
index 0000000..77b8424
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/Android.mk
@@ -0,0 +1,31 @@
+#
+# 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.
+#
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := AccessoryChat
+
+LOCAL_JAVA_LIBRARIES := com.android.future.usb.accessory
+
+# Force an old SDK version to make sure we aren't using newer UsbManager APIs
+LOCAL_SDK_VERSION := 8
+
+include $(BUILD_PACKAGE)
diff --git a/libs/usb/tests/AccessoryChat/AndroidManifest.xml b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
new file mode 100644
index 0000000..802b715
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/AndroidManifest.xml
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.accessorychat">
+
+ <application android:label="Accessory Chat">
+ <uses-library android:name="com.android.future.usb.accessory" />
+
+ <activity android:name="AccessoryChat" android:label="Accessory Chat">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN" />
+ <category android:name="android.intent.category.DEFAULT" />
+ <category android:name="android.intent.category.LAUNCHER" />
+ </intent-filter>
+
+ <intent-filter>
+ <action android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+ </intent-filter>
+
+ <meta-data android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED"
+ android:resource="@xml/accessory_filter" />
+ </activity>
+ </application>
+ <uses-sdk android:minSdkVersion="10" />
+</manifest>
diff --git a/libs/usb/tests/AccessoryChat/README.txt b/libs/usb/tests/AccessoryChat/README.txt
new file mode 100644
index 0000000..d2ce11e
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/README.txt
@@ -0,0 +1,10 @@
+This is a test app for the USB accessory APIs. It consists of two parts:
+
+AccessoryChat - A Java app with a chat-like UI that sends and receives strings
+ via the UsbAccessory class.
+
+accessorychat - A C command-line program that communicates with AccessoryChat.
+ This program behaves as if it were a USB accessory.
+ It builds both for the host (Linux PC) and as an android
+ command line program, which will work if run as root on an
+ android device with USB host support
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/Android.mk b/libs/usb/tests/AccessoryChat/accessorychat/Android.mk
new file mode 100644
index 0000000..5a7b30e
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/accessorychat/Android.mk
@@ -0,0 +1,21 @@
+LOCAL_PATH:= $(call my-dir)
+
+# Build for Linux (desktop) host
+ifeq ($(HOST_OS),linux)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := accessorychat.c usbhost.c
+
+LOCAL_MODULE := accessorychat
+
+LOCAL_C_INCLUDES += bionic/libc/kernel/common
+LOCAL_STATIC_LIBRARIES := libcutils
+LOCAL_LDLIBS += -lpthread
+LOCAL_CFLAGS := -g -O0
+
+include $(BUILD_HOST_EXECUTABLE)
+
+endif
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
new file mode 100644
index 0000000..85b52dd
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/accessorychat/accessorychat.c
@@ -0,0 +1,196 @@
+/*
+ * 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.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <pthread.h>
+#include <time.h>
+
+#include <usbhost/usbhost.h>
+#include <linux/usb/f_accessory.h>
+
+struct usb_device *sDevice = NULL;
+
+static void* read_thread(void* arg) {
+ int endpoint = (int)arg;
+ int ret = 0;
+
+ while (sDevice && ret >= 0) {
+ char buffer[16384];
+
+ ret = usb_device_bulk_transfer(sDevice, endpoint, buffer, sizeof(buffer), 1000);
+ if (ret < 0 && errno == ETIMEDOUT)
+ ret = 0;
+ if (ret > 0) {
+ fwrite(buffer, 1, ret, stdout);
+ printf("\n");
+ fflush(stdout);
+ }
+ }
+
+ return NULL;
+}
+
+static void* write_thread(void* arg) {
+ int endpoint = (int)arg;
+ int ret = 0;
+
+ while (ret >= 0) {
+ char buffer[16384];
+ char *line = fgets(buffer, sizeof(buffer), stdin);
+ if (!line || !sDevice)
+ break;
+ ret = usb_device_bulk_transfer(sDevice, endpoint, line, strlen(line), 1000);
+ }
+
+ return NULL;
+}
+
+static void milli_sleep(int millis) {
+ struct timespec tm;
+
+ tm.tv_sec = 0;
+ tm.tv_nsec = millis * 1000000;
+ nanosleep(&tm, NULL);
+}
+
+static void send_string(struct usb_device *device, int index, const char* string) {
+ int ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
+ ACCESSORY_SEND_STRING, 0, index, (void *)string, strlen(string) + 1, 0);
+
+ // some devices can't handle back-to-back requests, so delay a bit
+ milli_sleep(10);
+}
+
+static int usb_device_added(const char *devname, void* client_data) {
+ struct usb_descriptor_header* desc;
+ struct usb_descriptor_iter iter;
+ uint16_t vendorId, productId;
+ int ret;
+ pthread_t th;
+
+ struct usb_device *device = usb_device_open(devname);
+ if (!device) {
+ fprintf(stderr, "usb_device_open failed\n");
+ return 0;
+ }
+
+ vendorId = usb_device_get_vendor_id(device);
+ productId = usb_device_get_product_id(device);
+
+ if (vendorId == 0x18D1 || vendorId == 0x22B8) {
+ if (!sDevice && (productId == 0x2D00 || productId == 0x2D01)) {
+ struct usb_descriptor_header* desc;
+ struct usb_descriptor_iter iter;
+ struct usb_interface_descriptor *intf = NULL;
+ struct usb_endpoint_descriptor *ep1 = NULL;
+ struct usb_endpoint_descriptor *ep2 = NULL;
+
+ printf("Found android device in accessory mode\n");
+ sDevice = device;
+
+ usb_descriptor_iter_init(device, &iter);
+ while ((desc = usb_descriptor_iter_next(&iter)) != NULL && (!intf || !ep1 || !ep2)) {
+ if (desc->bDescriptorType == USB_DT_INTERFACE) {
+ intf = (struct usb_interface_descriptor *)desc;
+ } else if (desc->bDescriptorType == USB_DT_ENDPOINT) {
+ if (ep1)
+ ep2 = (struct usb_endpoint_descriptor *)desc;
+ else
+ ep1 = (struct usb_endpoint_descriptor *)desc;
+ }
+ }
+
+ if (!intf) {
+ fprintf(stderr, "interface not found\n");
+ exit(1);
+ }
+ if (!ep1 || !ep2) {
+ fprintf(stderr, "endpoints not found\n");
+ exit(1);
+ }
+
+ if (usb_device_claim_interface(device, intf->bInterfaceNumber)) {
+ fprintf(stderr, "usb_device_claim_interface failed errno: %d\n", errno);
+ exit(1);
+ }
+
+ if ((ep1->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_IN) {
+ pthread_create(&th, NULL, read_thread, (void *)ep1->bEndpointAddress);
+ pthread_create(&th, NULL, write_thread, (void *)ep2->bEndpointAddress);
+ } else {
+ pthread_create(&th, NULL, read_thread, (void *)ep2->bEndpointAddress);
+ pthread_create(&th, NULL, write_thread, (void *)ep1->bEndpointAddress);
+ }
+ } else {
+ printf("Found possible android device - attempting to switch to accessory mode\n");
+
+ uint16_t protocol;
+ ret = usb_device_control_transfer(device, USB_DIR_IN | USB_TYPE_VENDOR,
+ ACCESSORY_GET_PROTOCOL, 0, 0, &protocol, sizeof(protocol), 0);
+ if (ret == 2)
+ printf("device supports protocol version %d\n", protocol);
+ else
+ fprintf(stderr, "failed to read protocol version\n");
+
+ send_string(device, ACCESSORY_STRING_MANUFACTURER, "Google, Inc.");
+ send_string(device, ACCESSORY_STRING_MODEL, "AccessoryChat");
+ send_string(device, ACCESSORY_STRING_DESCRIPTION, "Accessory Chat");
+ send_string(device, ACCESSORY_STRING_VERSION, "1.0");
+ send_string(device, ACCESSORY_STRING_URI, "http://www.android.com");
+ send_string(device, ACCESSORY_STRING_SERIAL, "1234567890");
+
+ ret = usb_device_control_transfer(device, USB_DIR_OUT | USB_TYPE_VENDOR,
+ ACCESSORY_START, 0, 0, 0, 0, 0);
+ return 0;
+ }
+ }
+
+ if (device != sDevice)
+ usb_device_close(device);
+
+ return 0;
+}
+
+static int usb_device_removed(const char *devname, void* client_data) {
+ if (sDevice && !strcmp(usb_device_get_name(sDevice), devname)) {
+ usb_device_close(sDevice);
+ sDevice = NULL;
+ // exit when we are disconnected
+ return 1;
+ }
+ return 0;
+}
+
+
+int main(int argc, char* argv[]) {
+ struct usb_host_context* context = usb_host_init();
+ if (!context) {
+ fprintf(stderr, "usb_host_init failed");
+ return 1;
+ }
+
+ // this will never return so it is safe to pass thiz directly
+ usb_host_run(context, usb_device_added, usb_device_removed, NULL, NULL);
+ return 0;
+}
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/usbhost.c b/libs/usb/tests/AccessoryChat/accessorychat/usbhost.c
new file mode 100644
index 0000000..f5a7c3f
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/accessorychat/usbhost.c
@@ -0,0 +1,574 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// #define DEBUG 1
+#if DEBUG
+
+#ifdef USE_LIBLOG
+#define LOG_TAG "usbhost"
+#include "utils/Log.h"
+#define D LOGD
+#else
+#define D printf
+#endif
+
+#else
+#define D(...)
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/inotify.h>
+#include <dirent.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <ctype.h>
+#include <pthread.h>
+
+#include <linux/usbdevice_fs.h>
+#include <asm/byteorder.h>
+
+#include "usbhost/usbhost.h"
+
+#define USB_FS_DIR "/dev/bus/usb"
+#define USB_FS_ID_SCANNER "/dev/bus/usb/%d/%d"
+#define USB_FS_ID_FORMAT "/dev/bus/usb/%03d/%03d"
+
+
+struct usb_host_context {
+ int fd;
+};
+
+struct usb_device {
+ char dev_name[64];
+ unsigned char desc[4096];
+ int desc_length;
+ int fd;
+ int writeable;
+};
+
+static inline int badname(const char *name)
+{
+ while(*name) {
+ if(!isdigit(*name++)) return 1;
+ }
+ return 0;
+}
+
+/* returns true if one of the callbacks indicates we are done */
+static int find_existing_devices(usb_device_added_cb added_cb,
+ usb_device_removed_cb removed_cb,
+ void *client_data)
+{
+ char busname[32], devname[32];
+ DIR *busdir , *devdir ;
+ struct dirent *de;
+ int done = 0;
+
+ busdir = opendir(USB_FS_DIR);
+ if(busdir == 0) return 1;
+
+ while ((de = readdir(busdir)) != 0 && !done) {
+ if(badname(de->d_name)) continue;
+
+ snprintf(busname, sizeof busname, "%s/%s", USB_FS_DIR, de->d_name);
+ devdir = opendir(busname);
+ if(devdir == 0) continue;
+
+ while ((de = readdir(devdir)) && !done) {
+ if(badname(de->d_name)) continue;
+
+ snprintf(devname, sizeof devname, "%s/%s", busname, de->d_name);
+ done = added_cb(devname, client_data);
+ } // end of devdir while
+ closedir(devdir);
+ } //end of busdir while
+ closedir(busdir);
+
+ return done;
+}
+
+struct usb_host_context *usb_host_init()
+{
+ struct usb_host_context *context = calloc(1, sizeof(struct usb_host_context));
+ if (!context) {
+ fprintf(stderr, "out of memory in usb_host_context\n");
+ return NULL;
+ }
+ context->fd = inotify_init();
+ if (context->fd < 0) {
+ fprintf(stderr, "inotify_init failed\n");
+ free(context);
+ return NULL;
+ }
+ return context;
+}
+
+void usb_host_cleanup(struct usb_host_context *context)
+{
+ close(context->fd);
+ free(context);
+}
+
+void usb_host_run(struct usb_host_context *context,
+ usb_device_added_cb added_cb,
+ usb_device_removed_cb removed_cb,
+ usb_discovery_done_cb discovery_done_cb,
+ void *client_data)
+{
+ struct inotify_event* event;
+ char event_buf[512];
+ char path[100];
+ int i, ret, done = 0;
+ int wd, wds[10];
+ int wd_count = sizeof(wds) / sizeof(wds[0]);
+
+ D("Created device discovery thread\n");
+
+ /* watch for files added and deleted within USB_FS_DIR */
+ memset(wds, 0, sizeof(wds));
+ /* watch the root for new subdirectories */
+ wds[0] = inotify_add_watch(context->fd, USB_FS_DIR, IN_CREATE | IN_DELETE);
+ if (wds[0] < 0) {
+ fprintf(stderr, "inotify_add_watch failed\n");
+ if (discovery_done_cb)
+ discovery_done_cb(client_data);
+ return;
+ }
+
+ /* watch existing subdirectories of USB_FS_DIR */
+ for (i = 1; i < wd_count; i++) {
+ snprintf(path, sizeof(path), "%s/%03d", USB_FS_DIR, i);
+ ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
+ if (ret > 0)
+ wds[i] = ret;
+ }
+
+ /* check for existing devices first, after we have inotify set up */
+ done = find_existing_devices(added_cb, removed_cb, client_data);
+ if (discovery_done_cb)
+ done |= discovery_done_cb(client_data);
+
+ while (!done) {
+ ret = read(context->fd, event_buf, sizeof(event_buf));
+ if (ret >= (int)sizeof(struct inotify_event)) {
+ event = (struct inotify_event *)event_buf;
+ wd = event->wd;
+ if (wd == wds[0]) {
+ i = atoi(event->name);
+ snprintf(path, sizeof(path), "%s/%s", USB_FS_DIR, event->name);
+ D("new subdirectory %s: index: %d\n", path, i);
+ if (i > 0 && i < wd_count) {
+ ret = inotify_add_watch(context->fd, path, IN_CREATE | IN_DELETE);
+ if (ret > 0)
+ wds[i] = ret;
+ }
+ } else {
+ for (i = 1; i < wd_count && !done; i++) {
+ if (wd == wds[i]) {
+ snprintf(path, sizeof(path), "%s/%03d/%s", USB_FS_DIR, i, event->name);
+ if (event->mask == IN_CREATE) {
+ D("new device %s\n", path);
+ done = added_cb(path, client_data);
+ } else if (event->mask == IN_DELETE) {
+ D("gone device %s\n", path);
+ done = removed_cb(path, client_data);
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+struct usb_device *usb_device_open(const char *dev_name)
+{
+ int fd, did_retry = 0, writeable = 1;
+
+ D("usb_device_open %s\n", dev_name);
+
+retry:
+ fd = open(dev_name, O_RDWR);
+ if (fd < 0) {
+ /* if we fail, see if have read-only access */
+ fd = open(dev_name, O_RDONLY);
+ D("usb_device_open open returned %d errno %d\n", fd, errno);
+ if (fd < 0 && (errno == EACCES || errno == ENOENT) && !did_retry) {
+ /* work around race condition between inotify and permissions management */
+ sleep(1);
+ did_retry = 1;
+ goto retry;
+ }
+
+ if (fd < 0)
+ return NULL;
+ writeable = 0;
+ D("[ usb open read-only %s fd = %d]\n", dev_name, fd);
+ }
+
+ struct usb_device* result = usb_device_new(dev_name, fd);
+ if (result)
+ result->writeable = writeable;
+ return result;
+}
+
+void usb_device_close(struct usb_device *device)
+{
+ close(device->fd);
+ free(device);
+}
+
+struct usb_device *usb_device_new(const char *dev_name, int fd)
+{
+ struct usb_device *device = calloc(1, sizeof(struct usb_device));
+ int length;
+
+ D("usb_device_new %s fd: %d\n", dev_name, fd);
+
+ if (lseek(fd, 0, SEEK_SET) != 0)
+ goto failed;
+ length = read(fd, device->desc, sizeof(device->desc));
+ D("usb_device_new read returned %d errno %d\n", length, errno);
+ if (length < 0)
+ goto failed;
+
+ strncpy(device->dev_name, dev_name, sizeof(device->dev_name) - 1);
+ device->fd = fd;
+ device->desc_length = length;
+ // assume we are writeable, since usb_device_get_fd will only return writeable fds
+ device->writeable = 1;
+ return device;
+
+failed:
+ close(fd);
+ free(device);
+ return NULL;
+}
+
+static int usb_device_reopen_writeable(struct usb_device *device)
+{
+ if (device->writeable)
+ return 1;
+
+ int fd = open(device->dev_name, O_RDWR);
+ if (fd >= 0) {
+ close(device->fd);
+ device->fd = fd;
+ device->writeable = 1;
+ return 1;
+ }
+ D("usb_device_reopen_writeable failed errno %d\n", errno);
+ return 0;
+}
+
+int usb_device_get_fd(struct usb_device *device)
+{
+ if (!usb_device_reopen_writeable(device))
+ return -1;
+ return device->fd;
+}
+
+const char* usb_device_get_name(struct usb_device *device)
+{
+ return device->dev_name;
+}
+
+int usb_device_get_unique_id(struct usb_device *device)
+{
+ int bus = 0, dev = 0;
+ sscanf(device->dev_name, USB_FS_ID_SCANNER, &bus, &dev);
+ return bus * 1000 + dev;
+}
+
+int usb_device_get_unique_id_from_name(const char* name)
+{
+ int bus = 0, dev = 0;
+ sscanf(name, USB_FS_ID_SCANNER, &bus, &dev);
+ return bus * 1000 + dev;
+}
+
+char* usb_device_get_name_from_unique_id(int id)
+{
+ int bus = id / 1000;
+ int dev = id % 1000;
+ char* result = (char *)calloc(1, strlen(USB_FS_ID_FORMAT));
+ snprintf(result, strlen(USB_FS_ID_FORMAT) - 1, USB_FS_ID_FORMAT, bus, dev);
+ return result;
+}
+
+uint16_t usb_device_get_vendor_id(struct usb_device *device)
+{
+ struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc;
+ return __le16_to_cpu(desc->idVendor);
+}
+
+uint16_t usb_device_get_product_id(struct usb_device *device)
+{
+ struct usb_device_descriptor* desc = (struct usb_device_descriptor*)device->desc;
+ return __le16_to_cpu(desc->idProduct);
+}
+
+const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device)
+{
+ return (struct usb_device_descriptor*)device->desc;
+}
+
+char* usb_device_get_string(struct usb_device *device, int id)
+{
+ char string[256];
+ __u16 buffer[128];
+ __u16 languages[128];
+ int i, result;
+ int languageCount = 0;
+
+ string[0] = 0;
+ memset(languages, 0, sizeof(languages));
+
+ // read list of supported languages
+ result = usb_device_control_transfer(device,
+ USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) | 0, 0, languages, sizeof(languages), 0);
+ if (result > 0)
+ languageCount = (result - 2) / 2;
+
+ for (i = 1; i <= languageCount; i++) {
+ memset(buffer, 0, sizeof(buffer));
+
+ result = usb_device_control_transfer(device,
+ USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE, USB_REQ_GET_DESCRIPTOR,
+ (USB_DT_STRING << 8) | id, languages[i], buffer, sizeof(buffer), 0);
+ if (result > 0) {
+ int i;
+ // skip first word, and copy the rest to the string, changing shorts to bytes.
+ result /= 2;
+ for (i = 1; i < result; i++)
+ string[i - 1] = buffer[i];
+ string[i - 1] = 0;
+ return strdup(string);
+ }
+ }
+
+ return NULL;
+}
+
+char* usb_device_get_manufacturer_name(struct usb_device *device)
+{
+ struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
+
+ if (desc->iManufacturer)
+ return usb_device_get_string(device, desc->iManufacturer);
+ else
+ return NULL;
+}
+
+char* usb_device_get_product_name(struct usb_device *device)
+{
+ struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
+
+ if (desc->iProduct)
+ return usb_device_get_string(device, desc->iProduct);
+ else
+ return NULL;
+}
+
+char* usb_device_get_serial(struct usb_device *device)
+{
+ struct usb_device_descriptor *desc = (struct usb_device_descriptor *)device->desc;
+
+ if (desc->iSerialNumber)
+ return usb_device_get_string(device, desc->iSerialNumber);
+ else
+ return NULL;
+}
+
+int usb_device_is_writeable(struct usb_device *device)
+{
+ return device->writeable;
+}
+
+void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter)
+{
+ iter->config = device->desc;
+ iter->config_end = device->desc + device->desc_length;
+ iter->curr_desc = device->desc;
+}
+
+struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter)
+{
+ struct usb_descriptor_header* next;
+ if (iter->curr_desc >= iter->config_end)
+ return NULL;
+ next = (struct usb_descriptor_header*)iter->curr_desc;
+ iter->curr_desc += next->bLength;
+ return next;
+}
+
+int usb_device_claim_interface(struct usb_device *device, unsigned int interface)
+{
+ return ioctl(device->fd, USBDEVFS_CLAIMINTERFACE, &interface);
+}
+
+int usb_device_release_interface(struct usb_device *device, unsigned int interface)
+{
+ return ioctl(device->fd, USBDEVFS_RELEASEINTERFACE, &interface);
+}
+
+int usb_device_connect_kernel_driver(struct usb_device *device,
+ unsigned int interface, int connect)
+{
+ struct usbdevfs_ioctl ctl;
+
+ ctl.ifno = interface;
+ ctl.ioctl_code = (connect ? USBDEVFS_CONNECT : USBDEVFS_DISCONNECT);
+ ctl.data = NULL;
+ return ioctl(device->fd, USBDEVFS_IOCTL, &ctl);
+}
+
+int usb_device_control_transfer(struct usb_device *device,
+ int requestType,
+ int request,
+ int value,
+ int index,
+ void* buffer,
+ int length,
+ unsigned int timeout)
+{
+ struct usbdevfs_ctrltransfer ctrl;
+
+ // this usually requires read/write permission
+ if (!usb_device_reopen_writeable(device))
+ return -1;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.bRequestType = requestType;
+ ctrl.bRequest = request;
+ ctrl.wValue = value;
+ ctrl.wIndex = index;
+ ctrl.wLength = length;
+ ctrl.data = buffer;
+ ctrl.timeout = timeout;
+ return ioctl(device->fd, USBDEVFS_CONTROL, &ctrl);
+}
+
+int usb_device_bulk_transfer(struct usb_device *device,
+ int endpoint,
+ void* buffer,
+ int length,
+ unsigned int timeout)
+{
+ struct usbdevfs_bulktransfer ctrl;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.ep = endpoint;
+ ctrl.len = length;
+ ctrl.data = buffer;
+ ctrl.timeout = timeout;
+ return ioctl(device->fd, USBDEVFS_BULK, &ctrl);
+}
+
+struct usb_request *usb_request_new(struct usb_device *dev,
+ const struct usb_endpoint_descriptor *ep_desc)
+{
+ struct usbdevfs_urb *urb = calloc(1, sizeof(struct usbdevfs_urb));
+ if (!urb)
+ return NULL;
+
+ if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK)
+ urb->type = USBDEVFS_URB_TYPE_BULK;
+ else if ((ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_INT)
+ urb->type = USBDEVFS_URB_TYPE_INTERRUPT;
+ else {
+ D("Unsupported endpoint type %d", ep_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK);
+ free(urb);
+ return NULL;
+ }
+ urb->endpoint = ep_desc->bEndpointAddress;
+
+ struct usb_request *req = calloc(1, sizeof(struct usb_request));
+ if (!req) {
+ free(urb);
+ return NULL;
+ }
+
+ req->dev = dev;
+ req->max_packet_size = __le16_to_cpu(ep_desc->wMaxPacketSize);
+ req->private_data = urb;
+ req->endpoint = urb->endpoint;
+ urb->usercontext = req;
+
+ return req;
+}
+
+void usb_request_free(struct usb_request *req)
+{
+ free(req->private_data);
+ free(req);
+}
+
+int usb_request_queue(struct usb_request *req)
+{
+ struct usbdevfs_urb *urb = (struct usbdevfs_urb*)req->private_data;
+ int res;
+
+ urb->status = -1;
+ urb->buffer = req->buffer;
+ urb->buffer_length = req->buffer_length;
+
+ do {
+ res = ioctl(req->dev->fd, USBDEVFS_SUBMITURB, urb);
+ } while((res < 0) && (errno == EINTR));
+
+ return res;
+}
+
+struct usb_request *usb_request_wait(struct usb_device *dev)
+{
+ struct usbdevfs_urb *urb = NULL;
+ struct usb_request *req = NULL;
+ int res;
+
+ while (1) {
+ int res = ioctl(dev->fd, USBDEVFS_REAPURB, &urb);
+ D("USBDEVFS_REAPURB returned %d\n", res);
+ if (res < 0) {
+ if(errno == EINTR) {
+ continue;
+ }
+ D("[ reap urb - error ]\n");
+ return NULL;
+ } else {
+ D("[ urb @%p status = %d, actual = %d ]\n",
+ urb, urb->status, urb->actual_length);
+ req = (struct usb_request*)urb->usercontext;
+ req->actual_length = urb->actual_length;
+ }
+ break;
+ }
+ return req;
+}
+
+int usb_request_cancel(struct usb_request *req)
+{
+ struct usbdevfs_urb *urb = ((struct usbdevfs_urb*)req->private_data);
+ return ioctl(req->dev->fd, USBDEVFS_DISCARDURB, &urb);
+}
+
diff --git a/libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h b/libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h
new file mode 100644
index 0000000..9a6b59c
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/accessorychat/usbhost/usbhost.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __USB_HOST_H
+#define __USB_HOST_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 20)
+#include <linux/usb/ch9.h>
+#else
+#include <linux/usb_ch9.h>
+#endif
+
+struct usb_host_context;
+struct usb_endpoint_descriptor;
+
+struct usb_descriptor_iter {
+ unsigned char* config;
+ unsigned char* config_end;
+ unsigned char* curr_desc;
+};
+
+struct usb_request
+{
+ struct usb_device *dev;
+ void* buffer;
+ int buffer_length;
+ int actual_length;
+ int max_packet_size;
+ void *private_data; /* struct usbdevfs_urb* */
+ int endpoint;
+ void *client_data; /* free for use by client */
+};
+
+/* Callback for notification when new USB devices are attached.
+ * Return true to exit from usb_host_run.
+ */
+typedef int (* usb_device_added_cb)(const char *dev_name, void *client_data);
+
+/* Callback for notification when USB devices are removed.
+ * Return true to exit from usb_host_run.
+ */
+typedef int (* usb_device_removed_cb)(const char *dev_name, void *client_data);
+
+/* Callback indicating that initial device discovery is done.
+ * Return true to exit from usb_host_run.
+ */
+typedef int (* usb_discovery_done_cb)(void *client_data);
+
+/* Call this to initialize the USB host library. */
+struct usb_host_context *usb_host_init(void);
+
+/* Call this to cleanup the USB host library. */
+void usb_host_cleanup(struct usb_host_context *context);
+
+/* Call this to monitor the USB bus for new and removed devices.
+ * This is intended to be called from a dedicated thread,
+ * as it will not return until one of the callbacks returns true.
+ * added_cb will be called immediately for each existing USB device,
+ * and subsequently each time a new device is added.
+ * removed_cb is called when USB devices are removed from the bus.
+ * discovery_done_cb is called after the initial discovery of already
+ * connected devices is complete.
+ */
+void usb_host_run(struct usb_host_context *context,
+ usb_device_added_cb added_cb,
+ usb_device_removed_cb removed_cb,
+ usb_discovery_done_cb discovery_done_cb,
+ void *client_data);
+
+/* Creates a usb_device object for a USB device */
+struct usb_device *usb_device_open(const char *dev_name);
+
+/* Releases all resources associated with the USB device */
+void usb_device_close(struct usb_device *device);
+
+/* Creates a usb_device object for already open USB device */
+struct usb_device *usb_device_new(const char *dev_name, int fd);
+
+/* Returns the file descriptor for the usb_device */
+int usb_device_get_fd(struct usb_device *device);
+
+/* Returns the name for the USB device, which is the same as
+ * the dev_name passed to usb_device_open()
+ */
+const char* usb_device_get_name(struct usb_device *device);
+
+/* Returns a unique ID for the device.
+ *Currently this is generated from the dev_name path.
+ */
+int usb_device_get_unique_id(struct usb_device *device);
+
+/* Returns a unique ID for the device name.
+ * Currently this is generated from the device path.
+ */
+int usb_device_get_unique_id_from_name(const char* name);
+
+/* Returns the device name for the unique ID.
+ * Call free() to deallocate the returned string */
+char* usb_device_get_name_from_unique_id(int id);
+
+/* Returns the USB vendor ID from the device descriptor for the USB device */
+uint16_t usb_device_get_vendor_id(struct usb_device *device);
+
+/* Returns the USB product ID from the device descriptor for the USB device */
+uint16_t usb_device_get_product_id(struct usb_device *device);
+
+const struct usb_device_descriptor* usb_device_get_device_descriptor(struct usb_device *device);
+
+/* Returns a USB descriptor string for the given string ID.
+ * Used to implement usb_device_get_manufacturer_name,
+ * usb_device_get_product_name and usb_device_get_serial.
+ * Call free() to free the result when you are done with it.
+ */
+char* usb_device_get_string(struct usb_device *device, int id);
+
+/* Returns the manufacturer name for the USB device.
+ * Call free() to free the result when you are done with it.
+ */
+char* usb_device_get_manufacturer_name(struct usb_device *device);
+
+/* Returns the product name for the USB device.
+ * Call free() to free the result when you are done with it.
+ */
+char* usb_device_get_product_name(struct usb_device *device);
+
+/* Returns the USB serial number for the USB device.
+ * Call free() to free the result when you are done with it.
+ */
+char* usb_device_get_serial(struct usb_device *device);
+
+/* Returns true if we have write access to the USB device,
+ * and false if we only have access to the USB device configuration.
+ */
+int usb_device_is_writeable(struct usb_device *device);
+
+/* Initializes a usb_descriptor_iter, which can be used to iterate through all
+ * the USB descriptors for a USB device.
+ */
+void usb_descriptor_iter_init(struct usb_device *device, struct usb_descriptor_iter *iter);
+
+/* Returns the next USB descriptor for a device, or NULL if we have reached the
+ * end of the list.
+ */
+struct usb_descriptor_header *usb_descriptor_iter_next(struct usb_descriptor_iter *iter);
+
+/* Claims the specified interface of a USB device */
+int usb_device_claim_interface(struct usb_device *device, unsigned int interface);
+
+/* Releases the specified interface of a USB device */
+int usb_device_release_interface(struct usb_device *device, unsigned int interface);
+
+/* Requests the kernel to connect or disconnect its driver for the specified interface.
+ * This can be used to ask the kernel to disconnect its driver for a device
+ * so usb_device_claim_interface can claim it instead.
+ */
+int usb_device_connect_kernel_driver(struct usb_device *device,
+ unsigned int interface, int connect);
+
+/* Sends a control message to the specified device on endpoint zero */
+int usb_device_control_transfer(struct usb_device *device,
+ int requestType,
+ int request,
+ int value,
+ int index,
+ void* buffer,
+ int length,
+ unsigned int timeout);
+
+/* Reads or writes on a bulk endpoint.
+ * Returns number of bytes transferred, or negative value for error.
+ */
+int usb_device_bulk_transfer(struct usb_device *device,
+ int endpoint,
+ void* buffer,
+ int length,
+ unsigned int timeout);
+
+/* Creates a new usb_request. */
+struct usb_request *usb_request_new(struct usb_device *dev,
+ const struct usb_endpoint_descriptor *ep_desc);
+
+/* Releases all resources associated with the request */
+void usb_request_free(struct usb_request *req);
+
+/* Submits a read or write request on the specified device */
+int usb_request_queue(struct usb_request *req);
+
+ /* Waits for the results of a previous usb_request_queue operation.
+ * Returns a usb_request, or NULL for error.
+ */
+struct usb_request *usb_request_wait(struct usb_device *dev);
+
+/* Cancels a pending usb_request_queue() operation. */
+int usb_request_cancel(struct usb_request *req);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* __USB_HOST_H */
diff --git a/libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml b/libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml
new file mode 100644
index 0000000..596ecbf
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/res/layout/accessory_chat.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ >
+
+ <ScrollView android:id="@+id/scroll"
+ android:layout_width="match_parent"
+ android:layout_height="0px"
+ android:layout_weight="1"
+ >
+ <TextView android:id="@+id/log"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_marginTop="25dp"
+ android:textSize="12sp"
+ android:textColor="#ffffffff"
+ />
+ </ScrollView>
+
+ <EditText android:id="@+id/message"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:capitalize="sentences"
+ android:autoText="true"
+ android:singleLine="true"
+ />
+
+</LinearLayout>
+
+
diff --git a/libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml b/libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml
new file mode 100644
index 0000000..588946f
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/res/xml/accessory_filter.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<resources>
+ <usb-accessory manufacturer="Google, Inc." model="AccessoryChat" type="Sample Program" version="1.0" />
+</resources>
diff --git a/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
new file mode 100644
index 0000000..c3f4fa3
--- /dev/null
+++ b/libs/usb/tests/AccessoryChat/src/com/android/accessorychat/AccessoryChat.java
@@ -0,0 +1,199 @@
+/*
+ * 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.accessorychat;
+
+import android.app.Activity;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.ParcelFileDescriptor;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.util.Log;
+import android.widget.EditText;
+import android.widget.TextView;
+
+import com.android.future.usb.UsbAccessory;
+import com.android.future.usb.UsbManager;
+
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class AccessoryChat extends Activity implements Runnable, TextView.OnEditorActionListener {
+
+ private static final String TAG = "AccessoryChat";
+
+ private static final String ACTION_USB_PERMISSION =
+ "com.android.accessorychat.action.USB_PERMISSION";
+
+ private TextView mLog;
+ private EditText mEditText;
+ private ParcelFileDescriptor mFileDescriptor;
+ private FileInputStream mInputStream;
+ private FileOutputStream mOutputStream;
+ private UsbManager mUsbManager;
+ private PendingIntent mPermissionIntent;
+ private boolean mPermissionRequestPending;
+
+ private static final int MESSAGE_LOG = 1;
+
+ private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() {
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if (ACTION_USB_PERMISSION.equals(intent.getAction())) {
+ synchronized (this) {
+ UsbAccessory accessory = UsbManager.getAccessory(intent);
+ if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) {
+ openAccessory(accessory);
+ } else {
+ Log.d(TAG, "permission denied for accessory " + accessory);
+ }
+ mPermissionRequestPending = false;
+ }
+ }
+ }
+ };
+
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mUsbManager = UsbManager.getInstance(this);
+ mPermissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0);
+ IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
+ registerReceiver(mUsbReceiver, filter);
+
+ setContentView(R.layout.accessory_chat);
+ mLog = (TextView)findViewById(R.id.log);
+ mEditText = (EditText)findViewById(R.id.message);
+ mEditText.setOnEditorActionListener(this);
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+
+ Intent intent = getIntent();
+ Log.d(TAG, "intent: " + intent);
+ UsbAccessory[] accessories = mUsbManager.getAccessoryList();
+ UsbAccessory accessory = (accessories == null ? null : accessories[0]);
+ if (accessory != null) {
+ if (mUsbManager.hasPermission(accessory)) {
+ openAccessory(accessory);
+ } else {
+ synchronized (mUsbReceiver) {
+ if (!mPermissionRequestPending) {
+ mUsbManager.requestPermission(accessory, mPermissionIntent);
+ mPermissionRequestPending = true;
+ }
+ }
+ }
+ } else {
+ Log.d(TAG, "mAccessory is null");
+ }
+ }
+
+ @Override
+ public void onPause() {
+ super.onPause();
+ if (mFileDescriptor != null) {
+ try {
+ mFileDescriptor.close();
+ } catch (IOException e) {
+ } finally {
+ mFileDescriptor = null;
+ }
+ }
+ }
+
+ @Override
+ public void onDestroy() {
+ unregisterReceiver(mUsbReceiver);
+ super.onDestroy();
+ }
+
+ private void openAccessory(UsbAccessory accessory) {
+ Log.d(TAG, "openAccessory: " + accessory);
+ mFileDescriptor = mUsbManager.openAccessory(accessory);
+ if (mFileDescriptor != null) {
+ FileDescriptor fd = mFileDescriptor.getFileDescriptor();
+ mInputStream = new FileInputStream(fd);
+ mOutputStream = new FileOutputStream(fd);
+ Thread thread = new Thread(null, this, "AccessoryChat");
+ thread.start();
+ Log.d(TAG, "openAccessory succeeded");
+ } else {
+ Log.d(TAG, "openAccessory fail");
+ }
+ }
+
+ public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
+ if (actionId == EditorInfo.IME_ACTION_DONE && mOutputStream != null) {
+ try {
+ mOutputStream.write(v.getText().toString().getBytes());
+ } catch (IOException e) {
+ Log.e(TAG, "write failed", e);
+ }
+ v.setText("");
+ return true;
+ }
+ Log.d(TAG, "onEditorAction " + actionId + " event: " + event);
+ return false;
+ }
+
+ public void run() {
+ int ret = 0;
+ byte[] buffer = new byte[16384];
+ while (ret >= 0) {
+ try {
+ ret = mInputStream.read(buffer);
+ } catch (IOException e) {
+ break;
+ }
+
+ if (ret > 0) {
+ Message m = Message.obtain(mHandler, MESSAGE_LOG);
+ String text = new String(buffer, 0, ret);
+ Log.d(TAG, "chat: " + text);
+ m.obj = text;
+ mHandler.sendMessage(m);
+ }
+ }
+ Log.d(TAG, "thread out");
+ }
+
+ Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MESSAGE_LOG:
+ mLog.setText(mLog.getText() + "\n" + (String)msg.obj);
+ break;
+ }
+ }
+ };
+}
+
+
diff --git a/libs/utils/AssetManager.cpp b/libs/utils/AssetManager.cpp
index e09e755..13004cd 100644
--- a/libs/utils/AssetManager.cpp
+++ b/libs/utils/AssetManager.cpp
@@ -36,6 +36,19 @@
#include <dirent.h>
#include <errno.h>
#include <assert.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifndef TEMP_FAILURE_RETRY
+/* Used to retry syscalls that can return EINTR. */
+#define TEMP_FAILURE_RETRY(exp) ({ \
+ typeof (exp) _rc; \
+ do { \
+ _rc = (exp); \
+ } while (_rc == -1 && errno == EINTR); \
+ _rc; })
+#endif
using namespace android;
@@ -48,6 +61,7 @@ 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* kIdmapCacheDir = "resource-cache";
static const char* kExcludeExtension = ".EXCLUDE";
@@ -55,6 +69,35 @@ static Asset* const kExcludedAsset = (Asset*) 0xd000000d;
static volatile int32_t gCount = 0;
+namespace {
+ // Transform string /a/b/c.apk to /data/resource-cache/a@b@c.apk@idmap
+ 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(kIdmapCacheDir);
+
+ 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;
+ }
+}
/*
* ===========================================================================
@@ -122,7 +165,7 @@ bool AssetManager::addAssetPath(const String8& path, void** cookie)
return true;
}
}
-
+
LOGV("In %p Asset %s path: %s", this,
ap.type == kFileTypeDirectory ? "dir" : "zip", ap.path.string());
@@ -133,9 +176,181 @@ bool AssetManager::addAssetPath(const String8& path, void** cookie)
*cookie = (void*)mAssetPaths.size();
}
+ // add overlay packages for /system/framework; apps are handled by the
+ // (Java) package manager
+ if (strncmp(path.string(), "/system/framework/", 18) == 0) {
+ // When there is an environment variable for /vendor, this
+ // should be changed to something similar to how ANDROID_ROOT
+ // and ANDROID_DATA are used in this file.
+ String8 overlayPath("/vendor/overlay/framework/");
+ overlayPath.append(path.getPathLeaf());
+ if (TEMP_FAILURE_RETRY(access(overlayPath.string(), R_OK)) == 0) {
+ asset_path oap;
+ oap.path = overlayPath;
+ oap.type = ::getFileType(overlayPath.string());
+ bool addOverlay = (oap.type == kFileTypeRegular); // only .apks supported as overlay
+ if (addOverlay) {
+ oap.idmap = idmapPathForPackagePath(overlayPath);
+
+ if (isIdmapStaleLocked(ap.path, oap.path, oap.idmap)) {
+ addOverlay = createIdmapFileLocked(ap.path, oap.path, oap.idmap);
+ }
+ }
+ if (addOverlay) {
+ mAssetPaths.add(oap);
+ } else {
+ LOGW("failed to add overlay package %s\n", overlayPath.string());
+ }
+ }
+ }
+
+ return true;
+}
+
+bool AssetManager::isIdmapStaleLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath)
+{
+ struct stat st;
+ if (TEMP_FAILURE_RETRY(stat(idmapPath.string(), &st)) == -1) {
+ if (errno == ENOENT) {
+ return true; // non-existing idmap is always stale
+ } else {
+ LOGW("failed to stat file %s: %s\n", idmapPath.string(), strerror(errno));
+ return false;
+ }
+ }
+ if (st.st_size < ResTable::IDMAP_HEADER_SIZE_BYTES) {
+ LOGW("file %s has unexpectedly small size=%zd\n", idmapPath.string(), (size_t)st.st_size);
+ return false;
+ }
+ int fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_RDONLY));
+ if (fd == -1) {
+ LOGW("failed to open file %s: %s\n", idmapPath.string(), strerror(errno));
+ return false;
+ }
+ char buf[ResTable::IDMAP_HEADER_SIZE_BYTES];
+ ssize_t bytesLeft = ResTable::IDMAP_HEADER_SIZE_BYTES;
+ for (;;) {
+ ssize_t r = TEMP_FAILURE_RETRY(read(fd, buf + ResTable::IDMAP_HEADER_SIZE_BYTES - bytesLeft,
+ bytesLeft));
+ if (r < 0) {
+ TEMP_FAILURE_RETRY(close(fd));
+ return false;
+ }
+ bytesLeft -= r;
+ if (bytesLeft == 0) {
+ break;
+ }
+ }
+ TEMP_FAILURE_RETRY(close(fd));
+
+ uint32_t cachedOriginalCrc, cachedOverlayCrc;
+ if (!ResTable::getIdmapInfo(buf, ResTable::IDMAP_HEADER_SIZE_BYTES,
+ &cachedOriginalCrc, &cachedOverlayCrc)) {
+ return false;
+ }
+
+ uint32_t actualOriginalCrc, actualOverlayCrc;
+ if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &actualOriginalCrc)) {
+ return false;
+ }
+ if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &actualOverlayCrc)) {
+ return false;
+ }
+ return cachedOriginalCrc != actualOriginalCrc || cachedOverlayCrc != actualOverlayCrc;
+}
+
+bool AssetManager::getZipEntryCrcLocked(const String8& zipPath, const char* entryFilename,
+ uint32_t* pCrc)
+{
+ asset_path ap;
+ ap.path = zipPath;
+ const ZipFileRO* zip = getZipFileLocked(ap);
+ if (zip == NULL) {
+ return false;
+ }
+ const ZipEntryRO entry = zip->findEntryByName(entryFilename);
+ if (entry == NULL) {
+ return false;
+ }
+ if (!zip->getEntryInfo(entry, NULL, NULL, NULL, NULL, NULL, (long*)pCrc)) {
+ return false;
+ }
return true;
}
+bool AssetManager::createIdmapFileLocked(const String8& originalPath, const String8& overlayPath,
+ const String8& idmapPath)
+{
+ LOGD("%s: originalPath=%s overlayPath=%s idmapPath=%s\n",
+ __FUNCTION__, originalPath.string(), overlayPath.string(), idmapPath.string());
+ ResTable tables[2];
+ const String8* paths[2] = { &originalPath, &overlayPath };
+ uint32_t originalCrc, overlayCrc;
+ bool retval = false;
+ ssize_t offset = 0;
+ int fd = 0;
+ uint32_t* data = NULL;
+ size_t size;
+
+ 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);
+ if (ass == NULL) {
+ LOGW("failed to find resources.arsc in %s\n", ap.path.string());
+ goto error;
+ }
+ tables[i].add(ass, (void*)1, false);
+ }
+
+ if (!getZipEntryCrcLocked(originalPath, "resources.arsc", &originalCrc)) {
+ LOGW("failed to retrieve crc for resources.arsc in %s\n", originalPath.string());
+ goto error;
+ }
+ if (!getZipEntryCrcLocked(overlayPath, "resources.arsc", &overlayCrc)) {
+ LOGW("failed to retrieve crc for resources.arsc in %s\n", overlayPath.string());
+ goto error;
+ }
+
+ if (tables[0].createIdmap(tables[1], originalCrc, overlayCrc,
+ (void**)&data, &size) != NO_ERROR) {
+ LOGW("failed to generate idmap data for file %s\n", idmapPath.string());
+ goto error;
+ }
+
+ // This should be abstracted (eg replaced by a stand-alone
+ // application like dexopt, triggered by something equivalent to
+ // installd).
+ fd = TEMP_FAILURE_RETRY(::open(idmapPath.string(), O_WRONLY | O_CREAT | O_TRUNC, 0644));
+ if (fd == -1) {
+ LOGW("failed to write idmap file %s (open: %s)\n", idmapPath.string(), strerror(errno));
+ goto error_free;
+ }
+ for (;;) {
+ ssize_t written = TEMP_FAILURE_RETRY(write(fd, data + offset, size));
+ if (written < 0) {
+ LOGW("failed to write idmap file %s (write: %s)\n", idmapPath.string(),
+ strerror(errno));
+ goto error_close;
+ }
+ size -= (size_t)written;
+ offset += written;
+ if (size == 0) {
+ break;
+ }
+ }
+
+ retval = true;
+error_close:
+ TEMP_FAILURE_RETRY(close(fd));
+error_free:
+ free(data);
+error:
+ return retval;
+}
+
bool AssetManager::addDefaultAssets()
{
const char* root = getenv("ANDROID_ROOT");
@@ -404,6 +619,7 @@ const ResTable* AssetManager::getResTable(bool required) const
ResTable* sharedRes = NULL;
bool shared = true;
const asset_path& ap = mAssetPaths.itemAt(i);
+ Asset* idmap = openIdmapLocked(ap);
LOGV("Looking for resource asset in '%s'\n", ap.path.string());
if (ap.type != kFileTypeDirectory) {
if (i == 0) {
@@ -433,7 +649,7 @@ const ResTable* AssetManager::getResTable(bool required) const
// can quickly copy it out for others.
LOGV("Creating shared resources for %s", ap.path.string());
sharedRes = new ResTable();
- sharedRes->add(ass, (void*)(i+1), false);
+ sharedRes->add(ass, (void*)(i+1), false, idmap);
sharedRes = const_cast<AssetManager*>(this)->
mZipSet.setZipResourceTable(ap.path, sharedRes);
}
@@ -457,7 +673,7 @@ const ResTable* AssetManager::getResTable(bool required) const
rt->add(sharedRes);
} else {
LOGV("Parsing resources for %s", ap.path.string());
- rt->add(ass, (void*)(i+1), !shared);
+ rt->add(ass, (void*)(i+1), !shared, idmap);
}
if (!shared) {
@@ -498,6 +714,21 @@ void AssetManager::updateResourceParamsLocked() const
res->setParameters(mConfig);
}
+Asset* AssetManager::openIdmapLocked(const struct asset_path& ap) const
+{
+ Asset* ass = NULL;
+ if (ap.idmap.size() != 0) {
+ ass = const_cast<AssetManager*>(this)->
+ openAssetFromFileLocked(ap.idmap, Asset::ACCESS_BUFFER);
+ if (ass) {
+ LOGV("loading idmap %s\n", ap.idmap.string());
+ } else {
+ LOGW("failed to load idmap %s\n", ap.idmap.string());
+ }
+ }
+ return ass;
+}
+
const ResTable& AssetManager::getResources(bool required) const
{
const ResTable* rt = getResTable(required);
diff --git a/libs/utils/README b/libs/utils/README
index 36a706d..01741e0 100644
--- a/libs/utils/README
+++ b/libs/utils/README
@@ -1,4 +1,6 @@
Android Utility Function Library
+================================
+
If you need a feature that is native to Linux but not present on other
platforms, construct a platform-dependent implementation that shares
@@ -12,3 +14,276 @@ The ultimate goal is *not* to create a super-duper platform abstraction
layer. The goal is to provide an optimized solution for Linux with
reasonable implementations for other platforms.
+
+
+Resource overlay
+================
+
+
+Introduction
+------------
+
+Overlay packages are special .apk files which provide no code but
+additional resource values (and possibly new configurations) for
+resources in other packages. When an application requests resources,
+the system will return values from either the application's original
+package or any associated overlay package. Any redirection is completely
+transparent to the calling application.
+
+Resource values have the following precedence table, listed in
+descending precedence.
+
+ * overlay package, matching config (eg res/values-en-land)
+
+ * original package, matching config
+
+ * overlay package, no config (eg res/values)
+
+ * original package, no config
+
+During compilation, overlay packages are differentiated from regular
+packages by passing the -o flag to aapt.
+
+
+Background
+----------
+
+This section provides generic background material on resources in
+Android.
+
+
+How resources are bundled in .apk files
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+Android .apk files are .zip files, usually housing .dex code,
+certificates and resources, though packages containing resources but
+no code are possible. Resources can be divided into the following
+categories; a `configuration' indicates a set of phone language, display
+density, network operator, etc.
+
+ * assets: uncompressed, raw files packaged as part of an .apk and
+ explicitly referenced by filename. These files are
+ independent of configuration.
+
+ * res/drawable: bitmap or xml graphics. Each file may have different
+ values depending on configuration.
+
+ * res/values: integers, strings, etc. Each resource may have different
+ values depending on configuration.
+
+Resource meta information and information proper is stored in a binary
+format in a named file resources.arsc, bundled as part of the .apk.
+
+Resource IDs and lookup
+~~~~~~~~~~~~~~~~~~~~~~~
+During compilation, the aapt tool gathers application resources and
+generates a resources.arsc file. Each resource name is assigned an
+integer ID 0xppttiii (translated to a symbolic name via R.java), where
+
+ * pp: corresponds to the package namespace (details below).
+
+ * tt: corresponds to the resource type (string, int, etc). Every
+ resource of the same type within the same package has the same
+ tt value, but depending on available types, the actual numerical
+ value may be different between packages.
+
+ * iiii: sequential number, assigned in the order resources are found.
+
+Resource values are specified paired with a set of configuration
+constraints (the default being the empty set), eg res/values-sv-port
+which imposes restrictions on language (Swedish) and display orientation
+(portrait). During lookup, every constraint set is matched against the
+current configuration, and the value corresponding to the best matching
+constraint set is returned (ResourceTypes.{h,cpp}).
+
+Parsing of resources.arsc is handled by ResourceTypes.cpp; this utility
+is governed by AssetManager.cpp, which tracks loaded resources per
+process.
+
+Assets are looked up by path and filename in AssetManager.cpp. The path
+to resources in res/drawable are located by ResourceTypes.cpp and then
+handled like assets by AssetManager.cpp. Other resources are handled
+solely by ResourceTypes.cpp.
+
+Package ID as namespace
+~~~~~~~~~~~~~~~~~~~~~~~
+The pp part of a resource ID defines a namespace. Android currently
+defines two namespaces:
+
+ * 0x01: system resources (pre-installed in framework-res.apk)
+
+ * 0x7f: application resources (bundled in the application .apk)
+
+ResourceTypes.cpp supports package IDs between 0x01 and 0x7f
+(inclusive); values outside this range are invalid.
+
+Each running (Dalvik) process is assigned a unique instance of
+AssetManager, which in turn keeps a forest structure of loaded
+resource.arsc files. Normally, this forest is structured as follows,
+where mPackageMap is the internal vector employed in ResourceTypes.cpp.
+
+mPackageMap[0x00] -> system package
+mPackageMap[0x01] -> NULL
+mPackageMap[0x02] -> NULL
+...
+mPackageMap[0x7f - 2] -> NULL
+mPackageMap[0x7f - 1] -> application package
+
+
+
+The resource overlay extension
+------------------------------
+
+The resource overlay mechanism aims to (partly) shadow and extend
+existing resources with new values for defined and new configurations.
+Technically, this is achieved by adding resource-only packages (called
+overlay packages) to existing resource namespaces, like so:
+
+mPackageMap[0x00] -> system package -> system overlay package
+mPackageMap[0x01] -> NULL
+mPackageMap[0x02] -> NULL
+...
+mPackageMap[0x7f - 2] -> NULL
+mPackageMap[0x7f - 1] -> application package -> overlay 1 -> overlay 2
+
+The use of overlay resources is completely transparent to
+applications; no additional resource identifiers are introduced, only
+configuration/value pairs. Any number of overlay packages may be loaded
+at a time; overlay packages are agnostic to what they target -- both
+system and application resources are fair game.
+
+The package targeted by an overlay package is called the target or
+original package.
+
+Resource overlay operates on symbolic resources names. Hence, to
+override the string/str1 resources in a package, the overlay package
+would include a resource also named string/str1. The end user does not
+have to worry about the numeric resources IDs assigned by aapt, as this
+is resolved automatically by the system.
+
+As of this writing, the use of resource overlay has not been fully
+explored. Until it has, only OEMs are trusted to use resource overlay.
+For this reason, overlay packages must reside in /system/overlay.
+
+
+Resource ID mapping
+~~~~~~~~~~~~~~~~~~~
+Resource identifiers must be coherent within the same namespace (ie
+PackageGroup in ResourceTypes.cpp). Calling applications will refer to
+resources using the IDs defined in the original package, but there is no
+guarantee aapt has assigned the same ID to the corresponding resource in
+an overlay package. To translate between the two, a resource ID mapping
+{original ID -> overlay ID} is created during package installation
+(PackageManagerService.java) and used during resource lookup. The
+mapping is stored in /data/resource-cache, with a @idmap file name
+suffix.
+
+The idmap file format is documented in a separate section, below.
+
+
+Package management
+~~~~~~~~~~~~~~~~~~
+Packages are managed by the PackageManagerService. Addition and removal
+of packages are monitored via the inotify framework, exposed via
+android.os.FileObserver.
+
+During initialization of a Dalvik process, ActivityThread.java requests
+the process' AssetManager (by proxy, via AssetManager.java and JNI)
+to load a list of packages. This list includes overlay packages, if
+present.
+
+When a target package or a corresponding overlay package is installed,
+the target package's process is stopped and a new idmap is generated.
+This is similar to how applications are stopped when their packages are
+upgraded.
+
+
+Creating overlay packages
+-------------------------
+
+Overlay packages should contain no code, define (some) resources with
+the same type and name as in the original package, and be compiled with
+the -o flag passed to aapt.
+
+The aapt -o flag instructs aapt to create an overlay package.
+Technically, this means the package will be assigned package id 0x00.
+
+There are no restrictions on overlay packages names, though the naming
+convention <original.package.name>.overlay.<name> is recommended.
+
+
+Example overlay package
+~~~~~~~~~~~~~~~~~~~~~~~
+
+To overlay the resource bool/b in package com.foo.bar, to be applied
+when the display is in landscape mode, create a new package with
+no source code and a single .xml file under res/values-land, with
+an entry for bool/b. Compile with aapt -o and place the results in
+/system/overlay by adding the following to Android.mk:
+
+LOCAL_AAPT_FLAGS := -o com.foo.bar
+LOCAL_MODULE_PATH := $(TARGET_OUT)/overlay
+
+
+The ID map (idmap) file format
+------------------------------
+
+The idmap format is designed for lookup performance. However, leading
+and trailing undefined overlay values are discarded to reduce the memory
+footprint.
+
+
+idmap grammar
+~~~~~~~~~~~~~
+All atoms (names in square brackets) are uint32_t integers. The
+idmap-magic constant spells "idmp" in ASCII. Offsets are given relative
+to the data_header, not to the beginning of the file.
+
+map := header data
+header := idmap-magic <crc32-original-pkg> <crc32-overlay-pkg>
+idmap-magic := <0x706d6469>
+data := data_header type_block+
+data_header := <m> header_block{m}
+header_block := <0> | <type_block_offset>
+type_block := <n> <id_offset> entry{n}
+entry := <resource_id_in_target_package>
+
+
+idmap example
+~~~~~~~~~~~~~
+Given a pair of target and overlay packages with CRC sums 0x216a8fe2
+and 0x6b9beaec, each defining the following resources
+
+Name Target package Overlay package
+string/str0 0x7f010000 -
+string/str1 0x7f010001 0x7f010000
+string/str2 0x7f010002 -
+string/str3 0x7f010003 0x7f010001
+string/str4 0x7f010004 -
+bool/bool0 0x7f020000 -
+integer/int0 0x7f030000 0x7f020000
+integer/int1 0x7f030001 -
+
+the corresponding resource map is
+
+0x706d6469 0x216a8fe2 0x6b9beaec 0x00000003 \
+0x00000004 0x00000000 0x00000009 0x00000003 \
+0x00000001 0x7f010000 0x00000000 0x7f010001 \
+0x00000001 0x00000000 0x7f020000
+
+or, formatted differently
+
+0x706d6469 # magic: all idmap files begin with this constant
+0x216a8fe2 # CRC32 of the resources.arsc file in the original package
+0x6b9beaec # CRC32 of the resources.arsc file in the overlay package
+0x00000003 # header; three types (string, bool, integer) in the target package
+0x00000004 # header_block for type 0 (string) is located at offset 4
+0x00000000 # no bool type exists in overlay package -> no header_block
+0x00000009 # header_block for type 2 (integer) is located at offset 9
+0x00000003 # header_block for string; overlay IDs span 3 elements
+0x00000001 # the first string in target package is entry 1 == offset
+0x7f010000 # target 0x7f01001 -> overlay 0x7f010000
+0x00000000 # str2 not defined in overlay package
+0x7f010001 # target 0x7f010003 -> overlay 0x7f010001
+0x00000001 # header_block for integer; overlay IDs span 1 element
+0x00000000 # offset == 0
+0x7f020000 # target 0x7f030000 -> overlay 0x7f020000
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index 0bd1af4..d28b751 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -480,7 +480,7 @@ void RefBase::weakref_type::printRefs() const
void RefBase::weakref_type::trackMe(bool enable, bool retain)
{
- static_cast<const weakref_impl*>(this)->trackMe(enable, retain);
+ static_cast<weakref_impl*>(this)->trackMe(enable, retain);
}
RefBase::weakref_type* RefBase::createWeak(const void* id) const
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 7fb7ae3..57aaf24 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -63,6 +63,10 @@ namespace android {
#endif
#endif
+#define IDMAP_MAGIC 0x706d6469
+// size measured in sizeof(uint32_t)
+#define IDMAP_HEADER_SIZE (ResTable::IDMAP_HEADER_SIZE_BYTES / sizeof(uint32_t))
+
static void printToLogFunc(void* cookie, const char* txt)
{
LOGV("%s", txt);
@@ -214,6 +218,81 @@ static void deserializeInternal(const void* inData, Res_png_9patch* outData) {
outData->colors = (uint32_t*) data;
}
+static bool assertIdmapHeader(const uint32_t* map, size_t sizeBytes)
+{
+ if (sizeBytes < ResTable::IDMAP_HEADER_SIZE_BYTES) {
+ LOGW("idmap assertion failed: size=%d bytes\n", sizeBytes);
+ return false;
+ }
+ if (*map != htodl(IDMAP_MAGIC)) { // htodl: map data expected to be in correct endianess
+ LOGW("idmap assertion failed: invalid magic found (is 0x%08x, expected 0x%08x)\n",
+ *map, htodl(IDMAP_MAGIC));
+ return false;
+ }
+ return true;
+}
+
+static status_t idmapLookup(const uint32_t* map, size_t sizeBytes, uint32_t key, uint32_t* outValue)
+{
+ // see README for details on the format of map
+ if (!assertIdmapHeader(map, sizeBytes)) {
+ return UNKNOWN_ERROR;
+ }
+ map = map + IDMAP_HEADER_SIZE; // skip ahead to data segment
+ // size of data block, in uint32_t
+ const size_t size = (sizeBytes - ResTable::IDMAP_HEADER_SIZE_BYTES) / sizeof(uint32_t);
+ const uint32_t type = Res_GETTYPE(key) + 1; // add one, idmap stores "public" type id
+ const uint32_t entry = Res_GETENTRY(key);
+ const uint32_t typeCount = *map;
+
+ if (type > typeCount) {
+ LOGW("Resource ID map: type=%d exceeds number of types=%d\n", type, typeCount);
+ return UNKNOWN_ERROR;
+ }
+ if (typeCount > size) {
+ LOGW("Resource ID map: number of types=%d exceeds size of map=%d\n", typeCount, size);
+ return UNKNOWN_ERROR;
+ }
+ const uint32_t typeOffset = map[type];
+ if (typeOffset == 0) {
+ *outValue = 0;
+ return NO_ERROR;
+ }
+ if (typeOffset + 1 > size) {
+ LOGW("Resource ID map: type offset=%d exceeds reasonable value, size of map=%d\n",
+ typeOffset, size);
+ return UNKNOWN_ERROR;
+ }
+ const uint32_t entryCount = map[typeOffset];
+ const uint32_t entryOffset = map[typeOffset + 1];
+ if (entryCount == 0 || entry < entryOffset || entry - entryOffset > entryCount - 1) {
+ *outValue = 0;
+ return NO_ERROR;
+ }
+ const uint32_t index = typeOffset + 2 + entry - entryOffset;
+ if (index > size) {
+ LOGW("Resource ID map: entry index=%d exceeds size of map=%d\n", index, size);
+ *outValue = 0;
+ return NO_ERROR;
+ }
+ *outValue = map[index];
+
+ return NO_ERROR;
+}
+
+static status_t getIdmapPackageId(const uint32_t* map, size_t mapSize, uint32_t *outId)
+{
+ if (!assertIdmapHeader(map, mapSize)) {
+ return UNKNOWN_ERROR;
+ }
+ const uint32_t* p = map + IDMAP_HEADER_SIZE + 1;
+ while (*p == 0) {
+ ++p;
+ }
+ *outId = (map[*p + IDMAP_HEADER_SIZE + 2] >> 24) & 0x000000ff;
+ return NO_ERROR;
+}
+
Res_png_9patch* Res_png_9patch::deserialize(const void* inData)
{
if (sizeof(void*) != sizeof(int32_t)) {
@@ -1235,7 +1314,13 @@ status_t ResXMLTree::validateNode(const ResXMLTree_node* node) const
struct ResTable::Header
{
- Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL) { }
+ Header(ResTable* _owner) : owner(_owner), ownedData(NULL), header(NULL),
+ resourceIDMap(NULL), resourceIDMapSize(0) { }
+
+ ~Header()
+ {
+ free(resourceIDMap);
+ }
ResTable* const owner;
void* ownedData;
@@ -1246,6 +1331,8 @@ struct ResTable::Header
void* cookie;
ResStringPool values;
+ uint32_t* resourceIDMap;
+ size_t resourceIDMapSize;
};
struct ResTable::Type
@@ -1661,12 +1748,13 @@ inline ssize_t ResTable::getResourcePackageIndex(uint32_t resID) const
return ((ssize_t)mPackageMap[Res_GETPACKAGE(resID)+1])-1;
}
-status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData)
+status_t ResTable::add(const void* data, size_t size, void* cookie, bool copyData,
+ const void* idmap)
{
- return add(data, size, cookie, NULL, copyData);
+ return add(data, size, cookie, NULL, copyData, reinterpret_cast<const Asset*>(idmap));
}
-status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
+status_t ResTable::add(Asset* asset, void* cookie, bool copyData, const void* idmap)
{
const void* data = asset->getBuffer(true);
if (data == NULL) {
@@ -1674,7 +1762,7 @@ status_t ResTable::add(Asset* asset, void* cookie, bool copyData)
return UNKNOWN_ERROR;
}
size_t size = (size_t)asset->getLength();
- return add(data, size, cookie, asset, copyData);
+ return add(data, size, cookie, asset, copyData, reinterpret_cast<const Asset*>(idmap));
}
status_t ResTable::add(ResTable* src)
@@ -1702,19 +1790,30 @@ status_t ResTable::add(ResTable* src)
}
status_t ResTable::add(const void* data, size_t size, void* cookie,
- Asset* asset, bool copyData)
+ Asset* asset, bool copyData, const Asset* idmap)
{
if (!data) return NO_ERROR;
Header* header = new Header(this);
header->index = mHeaders.size();
header->cookie = cookie;
+ if (idmap != NULL) {
+ const size_t idmap_size = idmap->getLength();
+ const void* idmap_data = const_cast<Asset*>(idmap)->getBuffer(true);
+ header->resourceIDMap = (uint32_t*)malloc(idmap_size);
+ if (header->resourceIDMap == NULL) {
+ delete header;
+ return (mError = NO_MEMORY);
+ }
+ memcpy((void*)header->resourceIDMap, idmap_data, idmap_size);
+ header->resourceIDMapSize = idmap_size;
+ }
mHeaders.add(header);
const bool notDeviceEndian = htods(0xf0) != 0xf0;
LOAD_TABLE_NOISY(
- LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d\n",
- data, size, cookie, asset, copyData));
+ LOGV("Adding resources to ResTable: data=%p, size=0x%x, cookie=%p, asset=%p, copy=%d "
+ "idmap=%p\n", data, size, cookie, asset, copyData, idmap));
if (copyData || notDeviceEndian) {
header->ownedData = malloc(size);
@@ -1781,7 +1880,16 @@ status_t ResTable::add(const void* data, size_t size, void* cookie,
dtohl(header->header->packageCount));
return (mError=BAD_TYPE);
}
- if (parsePackage((ResTable_package*)chunk, header) != NO_ERROR) {
+ uint32_t idmap_id = 0;
+ if (idmap != NULL) {
+ uint32_t tmp;
+ if (getIdmapPackageId(header->resourceIDMap,
+ header->resourceIDMapSize,
+ &tmp) == NO_ERROR) {
+ idmap_id = tmp;
+ }
+ }
+ if (parsePackage((ResTable_package*)chunk, header, idmap_id) != NO_ERROR) {
return mError;
}
curPackage++;
@@ -1803,6 +1911,7 @@ status_t ResTable::add(const void* data, size_t size, void* cookie,
if (mError != NO_ERROR) {
LOGW("No string values found in resource table!");
}
+
TABLE_NOISY(LOGV("Returning from add with mError=%d\n", mError));
return mError;
}
@@ -1925,17 +2034,38 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
size_t ip = grp->packages.size();
while (ip > 0) {
ip--;
+ int T = t;
+ int E = e;
const Package* const package = grp->packages[ip];
+ if (package->header->resourceIDMap) {
+ uint32_t overlayResID = 0x0;
+ status_t retval = idmapLookup(package->header->resourceIDMap,
+ package->header->resourceIDMapSize,
+ resID, &overlayResID);
+ if (retval == NO_ERROR && overlayResID != 0x0) {
+ // for this loop iteration, this is the type and entry we really want
+ LOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
+ T = Res_GETTYPE(overlayResID);
+ E = Res_GETENTRY(overlayResID);
+ } else {
+ // resource not present in overlay package, continue with the next package
+ continue;
+ }
+ }
const ResTable_type* type;
const ResTable_entry* entry;
const Type* typeClass;
- ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+ ssize_t offset = getEntry(package, T, E, &mParams, &type, &entry, &typeClass);
if (offset <= 0) {
- if (offset < 0) {
+ // No {entry, appropriate config} pair found in package. If this
+ // package is an overlay package (ip != 0), this simply means the
+ // overlay package did not specify a default.
+ // Non-overlay packages are still required to provide a default.
+ if (offset < 0 && ip == 0) {
LOGW("Failure getting entry for 0x%08x (t=%d e=%d) in package %zd (error %d)\n",
- resID, t, e, ip, (int)offset);
+ resID, T, E, ip, (int)offset);
return offset;
}
continue;
@@ -1965,13 +2095,16 @@ ssize_t ResTable::getResource(uint32_t resID, Res_value* outValue, bool mayBeBag
if (outSpecFlags != NULL) {
if (typeClass->typeSpecFlags != NULL) {
- *outSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+ *outSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
} else {
*outSpecFlags = -1;
}
}
-
- if (bestPackage != NULL && bestItem.isMoreSpecificThan(thisConfig)) {
+
+ if (bestPackage != NULL &&
+ (bestItem.isMoreSpecificThan(thisConfig) || bestItem.diff(thisConfig) == 0)) {
+ // Discard thisConfig not only if bestItem is more specific, but also if the two configs
+ // are identical (diff == 0), or overlay packages will not take effect.
continue;
}
@@ -2165,21 +2298,45 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
TABLE_NOISY(LOGI("Building bag: %p\n", (void*)resID));
+ ResTable_config bestConfig;
+ memset(&bestConfig, 0, sizeof(bestConfig));
+
// Now collect all bag attributes from all packages.
size_t ip = grp->packages.size();
while (ip > 0) {
ip--;
+ int T = t;
+ int E = e;
const Package* const package = grp->packages[ip];
+ if (package->header->resourceIDMap) {
+ uint32_t overlayResID = 0x0;
+ status_t retval = idmapLookup(package->header->resourceIDMap,
+ package->header->resourceIDMapSize,
+ resID, &overlayResID);
+ if (retval == NO_ERROR && overlayResID != 0x0) {
+ // for this loop iteration, this is the type and entry we really want
+ LOGV("resource map 0x%08x -> 0x%08x\n", resID, overlayResID);
+ T = Res_GETTYPE(overlayResID);
+ E = Res_GETENTRY(overlayResID);
+ } else {
+ // resource not present in overlay package, continue with the next package
+ continue;
+ }
+ }
const ResTable_type* type;
const ResTable_entry* entry;
const Type* typeClass;
- LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, t, e);
- ssize_t offset = getEntry(package, t, e, &mParams, &type, &entry, &typeClass);
+ LOGV("Getting entry pkg=%p, t=%d, e=%d\n", package, T, E);
+ ssize_t offset = getEntry(package, T, E, &mParams, &type, &entry, &typeClass);
LOGV("Resulting offset=%d\n", offset);
if (offset <= 0) {
- if (offset < 0) {
+ // No {entry, appropriate config} pair found in package. If this
+ // package is an overlay package (ip != 0), this simply means the
+ // overlay package did not specify a default.
+ // Non-overlay packages are still required to provide a default.
+ if (offset < 0 && ip == 0) {
if (set) free(set);
return offset;
}
@@ -2192,6 +2349,15 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
continue;
}
+ if (set != NULL && !type->config.isBetterThan(bestConfig, NULL)) {
+ continue;
+ }
+ bestConfig = type->config;
+ if (set) {
+ free(set);
+ set = NULL;
+ }
+
const uint16_t entrySize = dtohs(entry->size);
const uint32_t parent = entrySize >= sizeof(ResTable_map_entry)
? dtohl(((const ResTable_map_entry*)entry)->parent.ident) : 0;
@@ -2203,43 +2369,41 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
TABLE_NOISY(LOGI("Found map: size=%p parent=%p count=%d\n",
entrySize, parent, count));
- if (set == NULL) {
- // If this map inherits from another, we need to start
- // with its parent's values. Otherwise start out empty.
- TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
- entrySize, parent));
- if (parent) {
- const bag_entry* parentBag;
- uint32_t parentTypeSpecFlags = 0;
- const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
- const size_t NT = ((NP >= 0) ? NP : 0) + N;
- set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
- if (set == NULL) {
- return NO_MEMORY;
- }
- if (NP > 0) {
- memcpy(set+1, parentBag, NP*sizeof(bag_entry));
- set->numAttrs = NP;
- TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
- } else {
- TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
- set->numAttrs = 0;
- }
- set->availAttrs = NT;
- set->typeSpecFlags = parentTypeSpecFlags;
+ // If this map inherits from another, we need to start
+ // with its parent's values. Otherwise start out empty.
+ TABLE_NOISY(printf("Creating new bag, entrySize=0x%08x, parent=0x%08x\n",
+ entrySize, parent));
+ if (parent) {
+ const bag_entry* parentBag;
+ uint32_t parentTypeSpecFlags = 0;
+ const ssize_t NP = getBagLocked(parent, &parentBag, &parentTypeSpecFlags);
+ const size_t NT = ((NP >= 0) ? NP : 0) + N;
+ set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*NT);
+ if (set == NULL) {
+ return NO_MEMORY;
+ }
+ if (NP > 0) {
+ memcpy(set+1, parentBag, NP*sizeof(bag_entry));
+ set->numAttrs = NP;
+ TABLE_NOISY(LOGI("Initialized new bag with %d inherited attributes.\n", NP));
} else {
- set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
- if (set == NULL) {
- return NO_MEMORY;
- }
+ TABLE_NOISY(LOGI("Initialized new bag with no inherited attributes.\n"));
set->numAttrs = 0;
- set->availAttrs = N;
- set->typeSpecFlags = 0;
}
+ set->availAttrs = NT;
+ set->typeSpecFlags = parentTypeSpecFlags;
+ } else {
+ set = (bag_set*)malloc(sizeof(bag_set)+sizeof(bag_entry)*N);
+ if (set == NULL) {
+ return NO_MEMORY;
+ }
+ set->numAttrs = 0;
+ set->availAttrs = N;
+ set->typeSpecFlags = 0;
}
if (typeClass->typeSpecFlags != NULL) {
- set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[e]);
+ set->typeSpecFlags |= dtohl(typeClass->typeSpecFlags[E]);
} else {
set->typeSpecFlags = -1;
}
@@ -3759,7 +3923,7 @@ ssize_t ResTable::getEntry(
}
status_t ResTable::parsePackage(const ResTable_package* const pkg,
- const Header* const header)
+ const Header* const header, uint32_t idmap_id)
{
const uint8_t* base = (const uint8_t*)pkg;
status_t err = validate_chunk(&pkg->header, sizeof(*pkg),
@@ -3793,8 +3957,12 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
Package* package = NULL;
PackageGroup* group = NULL;
- uint32_t id = dtohl(pkg->id);
- if (id != 0 && id < 256) {
+ uint32_t id = idmap_id != 0 ? idmap_id : dtohl(pkg->id);
+ // If at this point id == 0, pkg is an overlay package without a
+ // corresponding idmap. During regular usage, overlay packages are
+ // always loaded alongside their idmaps, but during idmap creation
+ // the package is temporarily loaded by itself.
+ if (id < 256) {
package = new Package(this, header, pkg);
if (package == NULL) {
@@ -3847,7 +4015,7 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
return (mError=err);
}
} else {
- LOG_ALWAYS_FATAL("Skins not supported!");
+ LOG_ALWAYS_FATAL("Package id out of range");
return NO_ERROR;
}
@@ -3998,6 +4166,136 @@ status_t ResTable::parsePackage(const ResTable_package* const pkg,
return NO_ERROR;
}
+status_t ResTable::createIdmap(const ResTable& overlay, uint32_t originalCrc, uint32_t overlayCrc,
+ void** outData, size_t* outSize) const
+{
+ // see README for details on the format of map
+ if (mPackageGroups.size() == 0) {
+ return UNKNOWN_ERROR;
+ }
+ if (mPackageGroups[0]->packages.size() == 0) {
+ return UNKNOWN_ERROR;
+ }
+
+ Vector<Vector<uint32_t> > map;
+ const PackageGroup* pg = mPackageGroups[0];
+ const Package* pkg = pg->packages[0];
+ size_t typeCount = pkg->types.size();
+ // starting size is header + first item (number of types in map)
+ *outSize = (IDMAP_HEADER_SIZE + 1) * sizeof(uint32_t);
+ const String16 overlayPackage(overlay.mPackageGroups[0]->packages[0]->package->name);
+ const uint32_t pkg_id = pkg->package->id << 24;
+
+ for (size_t typeIndex = 0; typeIndex < typeCount; ++typeIndex) {
+ ssize_t offset = -1;
+ const Type* typeConfigs = pkg->getType(typeIndex);
+ ssize_t mapIndex = map.add();
+ if (mapIndex < 0) {
+ return NO_MEMORY;
+ }
+ Vector<uint32_t>& vector = map.editItemAt(mapIndex);
+ for (size_t entryIndex = 0; entryIndex < typeConfigs->entryCount; ++entryIndex) {
+ uint32_t resID = (0xff000000 & ((pkg->package->id)<<24))
+ | (0x00ff0000 & ((typeIndex+1)<<16))
+ | (0x0000ffff & (entryIndex));
+ resource_name resName;
+ if (!this->getResourceName(resID, &resName)) {
+ return UNKNOWN_ERROR;
+ }
+
+ 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) {
+ // overlay package has package ID == 0, use original package's ID instead
+ overlayResID |= pkg_id;
+ }
+ vector.push(overlayResID);
+ if (overlayResID != 0 && offset == -1) {
+ offset = Res_GETENTRY(resID);
+ }
+#if 0
+ if (overlayResID != 0) {
+ LOGD("%s/%s 0x%08x -> 0x%08x\n",
+ String8(String16(resName.type)).string(),
+ String8(String16(resName.name)).string(),
+ resID, overlayResID);
+ }
+#endif
+ }
+
+ if (offset != -1) {
+ // shave off leading and trailing entries which lack overlay values
+ vector.removeItemsAt(0, offset);
+ vector.insertAt((uint32_t)offset, 0, 1);
+ while (vector.top() == 0) {
+ vector.pop();
+ }
+ // reserve space for number and offset of entries, and the actual entries
+ *outSize += (2 + vector.size()) * sizeof(uint32_t);
+ } else {
+ // no entries of current type defined in overlay package
+ vector.clear();
+ // reserve space for type offset
+ *outSize += 1 * sizeof(uint32_t);
+ }
+ }
+
+ if ((*outData = malloc(*outSize)) == NULL) {
+ return NO_MEMORY;
+ }
+ uint32_t* data = (uint32_t*)*outData;
+ *data++ = htodl(IDMAP_MAGIC);
+ *data++ = htodl(originalCrc);
+ *data++ = htodl(overlayCrc);
+ const size_t mapSize = map.size();
+ *data++ = htodl(mapSize);
+ size_t offset = mapSize;
+ for (size_t i = 0; i < mapSize; ++i) {
+ const Vector<uint32_t>& vector = map.itemAt(i);
+ const size_t N = vector.size();
+ if (N == 0) {
+ *data++ = htodl(0);
+ } else {
+ offset++;
+ *data++ = htodl(offset);
+ offset += N;
+ }
+ }
+ for (size_t i = 0; i < mapSize; ++i) {
+ const Vector<uint32_t>& vector = map.itemAt(i);
+ const size_t N = vector.size();
+ if (N == 0) {
+ continue;
+ }
+ *data++ = htodl(N - 1); // do not count the offset (which is vector's first element)
+ for (size_t j = 0; j < N; ++j) {
+ const uint32_t& overlayResID = vector.itemAt(j);
+ *data++ = htodl(overlayResID);
+ }
+ }
+
+ return NO_ERROR;
+}
+
+bool ResTable::getIdmapInfo(const void* idmap, size_t sizeBytes,
+ uint32_t* pOriginalCrc, uint32_t* pOverlayCrc)
+{
+ const uint32_t* map = (const uint32_t*)idmap;
+ if (!assertIdmapHeader(map, sizeBytes)) {
+ return false;
+ }
+ *pOriginalCrc = map[1];
+ *pOverlayCrc = map[2];
+ return true;
+}
+
+
#ifndef HAVE_ANDROID_OS
#define CHAR16_TO_CSTR(c16, len) (String8(String16(c16,len)).string())
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index 74488c5..a08f388 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -293,12 +293,16 @@ public class ExifInterface {
String lngRef = mAttributes.get(ExifInterface.TAG_GPS_LONGITUDE_REF);
if (latValue != null && latRef != null && lngValue != null && lngRef != null) {
- output[0] = convertRationalLatLonToFloat(latValue, latRef);
- output[1] = convertRationalLatLonToFloat(lngValue, lngRef);
- return true;
- } else {
- return false;
+ try {
+ output[0] = convertRationalLatLonToFloat(latValue, latRef);
+ output[1] = convertRationalLatLonToFloat(lngValue, lngRef);
+ return true;
+ } catch (IllegalArgumentException e) {
+ // if values are not parseable
+ }
}
+
+ return false;
}
/**
@@ -367,12 +371,12 @@ public class ExifInterface {
String [] pair;
pair = parts[0].split("/");
- int degrees = (int) (Float.parseFloat(pair[0].trim())
- / Float.parseFloat(pair[1].trim()));
+ double degrees = Double.parseDouble(pair[0].trim())
+ / Double.parseDouble(pair[1].trim());
pair = parts[1].split("/");
- int minutes = (int) ((Float.parseFloat(pair[0].trim())
- / Float.parseFloat(pair[1].trim())));
+ double minutes = Double.parseDouble(pair[0].trim())
+ / Double.parseDouble(pair[1].trim());
pair = parts[2].split("/");
double seconds = Double.parseDouble(pair[0].trim())
@@ -383,10 +387,12 @@ public class ExifInterface {
return (float) -result;
}
return (float) result;
- } catch (RuntimeException ex) {
- // if for whatever reason we can't parse the lat long then return
- // null
- return 0f;
+ } catch (NumberFormatException e) {
+ // Some of the nubmers are not valid
+ throw new IllegalArgumentException();
+ } catch (ArrayIndexOutOfBoundsException e) {
+ // Some of the rational does not follow the correct format
+ throw new IllegalArgumentException();
}
}
diff --git a/media/libstagefright/AudioSource.cpp b/media/libstagefright/AudioSource.cpp
index 29f16d8..a84365f 100644
--- a/media/libstagefright/AudioSource.cpp
+++ b/media/libstagefright/AudioSource.cpp
@@ -287,9 +287,10 @@ status_t AudioSource::read(
}
ssize_t n = mRecord->read(buffer->data(), buffer->size());
- if (n < 0) {
+ if (n <= 0) {
+ LOGE("Read from AudioRecord returns: %ld", n);
buffer->release();
- return (status_t)n;
+ return UNKNOWN_ERROR;
}
int64_t recordDurationUs = (1000000LL * n >> 1) / sampleRate;
diff --git a/media/libstagefright/AwesomePlayer.cpp b/media/libstagefright/AwesomePlayer.cpp
index 6dc61c7..e7aec35 100644
--- a/media/libstagefright/AwesomePlayer.cpp
+++ b/media/libstagefright/AwesomePlayer.cpp
@@ -1165,7 +1165,7 @@ void AwesomePlayer::finishSeekIfNecessary(int64_t videoTimeUs) {
}
if (mAudioPlayer != NULL) {
- LOGV("seeking audio to %lld us (%.2f secs).", timeUs, timeUs / 1E6);
+ LOGV("seeking audio to %lld us (%.2f secs).", videoTimeUs, videoTimeUs / 1E6);
// If we don't have a video time, seek audio to the originally
// requested seek time instead.
diff --git a/media/libstagefright/HTTPStream.cpp b/media/libstagefright/HTTPStream.cpp
index 7194614..4ad1c12 100644
--- a/media/libstagefright/HTTPStream.cpp
+++ b/media/libstagefright/HTTPStream.cpp
@@ -133,40 +133,58 @@ status_t HTTPStream::connect(const char *server, int port) {
return ERROR_ALREADY_CONNECTED;
}
- struct hostent *ent = gethostbyname(server);
- if (ent == NULL) {
- return ERROR_UNKNOWN_HOST;
+ if (port < 0 || port > (int) USHRT_MAX) {
+ return UNKNOWN_ERROR;
}
- CHECK_EQ(mSocket, -1);
- mSocket = socket(AF_INET, SOCK_STREAM, 0);
+ char service[sizeof("65536")];
+ sprintf(service, "%d", port);
+ struct addrinfo hints, *ai;
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_flags = AI_ADDRCONFIG | AI_NUMERICSERV;
+ hints.ai_socktype = SOCK_STREAM;
- if (mSocket < 0) {
- return UNKNOWN_ERROR;
+ int ret = getaddrinfo(server, service, &hints, &ai);
+ if (ret) {
+ return ERROR_UNKNOWN_HOST;
}
- setReceiveTimeout(30); // Time out reads after 30 secs by default
+ CHECK_EQ(mSocket, -1);
mState = CONNECTING;
+ status_t res = -1;
+ struct addrinfo *tmp;
+ for (tmp = ai; tmp; tmp = tmp->ai_next) {
+ mSocket = socket(tmp->ai_family, tmp->ai_socktype, tmp->ai_protocol);
+ if (mSocket < 0) {
+ continue;
+ }
- int s = mSocket;
+ setReceiveTimeout(30); // Time out reads after 30 secs by default.
- mLock.unlock();
+ int s = mSocket;
- struct sockaddr_in addr;
- addr.sin_family = AF_INET;
- addr.sin_port = htons(port);
- addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
- memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+ mLock.unlock();
- status_t res = MyConnect(s, (const struct sockaddr *)&addr, sizeof(addr));
+ res = MyConnect(s, tmp->ai_addr, tmp->ai_addrlen);
- mLock.lock();
+ mLock.lock();
- if (mState != CONNECTING) {
- return UNKNOWN_ERROR;
+ if (mState != CONNECTING) {
+ close(s);
+ freeaddrinfo(ai);
+ return UNKNOWN_ERROR;
+ }
+
+ if (res == OK) {
+ break;
+ }
+
+ close(s);
}
+ freeaddrinfo(ai);
+
if (res != OK) {
close(mSocket);
mSocket = -1;
diff --git a/media/libstagefright/MP3Extractor.cpp b/media/libstagefright/MP3Extractor.cpp
index b15c720..ed14a4b 100644
--- a/media/libstagefright/MP3Extractor.cpp
+++ b/media/libstagefright/MP3Extractor.cpp
@@ -37,10 +37,10 @@
namespace android {
// Everything must match except for
-// protection, bitrate, padding, private bits, mode extension,
+// protection, bitrate, padding, private bits, mode, mode extension,
// copyright bit, original bit and emphasis.
// Yes ... there are things that must indeed match...
-static const uint32_t kMask = 0xfffe0cc0;
+static const uint32_t kMask = 0xfffe0c00;
static bool get_mp3_frame_size(
uint32_t header, size_t *frame_size,
@@ -344,22 +344,55 @@ static bool Resync(
off_t pos = *inout_pos;
bool valid = false;
+
+ const size_t kMaxReadBytes = 1024;
+ const off_t kMaxBytesChecked = 128 * 1024;
+ uint8_t buf[kMaxReadBytes];
+ ssize_t bytesToRead = kMaxReadBytes;
+ ssize_t totalBytesRead = 0;
+ ssize_t remainingBytes = 0;
+ bool reachEOS = false;
+ uint8_t *tmp = buf;
+
do {
- if (pos >= *inout_pos + 128 * 1024) {
+ if (pos >= *inout_pos + kMaxBytesChecked) {
// Don't scan forever.
LOGV("giving up at offset %ld", pos);
break;
}
- uint8_t tmp[4];
- if (source->readAt(pos, tmp, 4) != 4) {
- break;
+ if (remainingBytes < 4) {
+ if (reachEOS) {
+ break;
+ } else {
+ memcpy(buf, tmp, remainingBytes);
+ bytesToRead = kMaxReadBytes - remainingBytes;
+
+ /*
+ * The next read position should start from the end of
+ * the last buffer, and thus should include the remaining
+ * bytes in the buffer.
+ */
+ totalBytesRead = source->readAt(pos + remainingBytes,
+ buf + remainingBytes,
+ bytesToRead);
+ if (totalBytesRead <= 0) {
+ break;
+ }
+ reachEOS = (totalBytesRead != bytesToRead);
+ totalBytesRead += remainingBytes;
+ remainingBytes = totalBytesRead;
+ tmp = buf;
+ continue;
+ }
}
uint32_t header = U32_AT(tmp);
if (match_header != 0 && (header & kMask) != (match_header & kMask)) {
++pos;
+ ++tmp;
+ --remainingBytes;
continue;
}
@@ -368,6 +401,8 @@ static bool Resync(
if (!get_mp3_frame_size(header, &frame_size,
&sample_rate, &num_channels, &bitrate)) {
++pos;
+ ++tmp;
+ --remainingBytes;
continue;
}
@@ -417,6 +452,8 @@ static bool Resync(
}
++pos;
+ ++tmp;
+ --remainingBytes;
} while (!valid);
return valid;
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 5b0168b..3a37bf3 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -326,24 +326,31 @@ void NuCachedSource2::onRead(const sp<AMessage> &msg) {
mCondition.signal();
}
-void NuCachedSource2::restartPrefetcherIfNecessary_l() {
+void NuCachedSource2::restartPrefetcherIfNecessary_l(bool force) {
static const size_t kGrayArea = 256 * 1024;
if (mFetching || mFinalStatus != OK) {
return;
}
- if (mCacheOffset + mCache->totalSize() - mLastAccessPos
- >= kLowWaterThreshold) {
- return;
- }
+ size_t maxBytes;
- size_t maxBytes = mLastAccessPos - mCacheOffset;
- if (maxBytes < kGrayArea) {
- return;
- }
+ if (!force) {
+ if (mCacheOffset + mCache->totalSize() - mLastAccessPos
+ >= kLowWaterThreshold) {
+ return;
+ }
+
+ maxBytes = mLastAccessPos - mCacheOffset;
+ if (maxBytes < kGrayArea) {
+ return;
+ }
- maxBytes -= kGrayArea;
+ maxBytes -= kGrayArea;
+ } else {
+ // Empty it all out.
+ maxBytes = mLastAccessPos - mCacheOffset;
+ }
size_t actualBytes = mCache->releaseFromStart(maxBytes);
mCacheOffset += actualBytes;
@@ -415,10 +422,17 @@ size_t NuCachedSource2::approxDataRemaining_l(bool *eos) {
}
ssize_t NuCachedSource2::readInternal(off_t offset, void *data, size_t size) {
+ CHECK(size <= kHighWaterThreshold);
+
LOGV("readInternal offset %ld size %d", offset, size);
Mutex::Autolock autoLock(mLock);
+ if (!mFetching) {
+ mLastAccessPos = offset;
+ restartPrefetcherIfNecessary_l(true /* force */);
+ }
+
if (offset < mCacheOffset
|| offset >= (off_t)(mCacheOffset + mCache->totalSize())) {
static const off_t kPadding = 32768;
diff --git a/media/libstagefright/NuHTTPDataSource.cpp b/media/libstagefright/NuHTTPDataSource.cpp
index 04cca47..af247d5 100644
--- a/media/libstagefright/NuHTTPDataSource.cpp
+++ b/media/libstagefright/NuHTTPDataSource.cpp
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
//#define LOG_NDEBUG 0
#define LOG_TAG "NuHTTPDataSource"
#include <utils/Log.h>
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
index 8b0250a..d443b7c 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_decode_header.cpp
@@ -121,9 +121,11 @@ ERROR_CODE pvmp3_decode_header(tmp3Bits *inputStream,
uint32 temp;
/*
- * Verify that at least the header is complete
+ * Verify that at least the header is complete
+ * Note that SYNC_WORD_LNGTH is in unit of bits, but inputBufferCurrentLength
+ * is in unit of bytes.
*/
- if (inputStream->inputBufferCurrentLength < (SYNC_WORD_LNGTH + 21))
+ if (inputStream->inputBufferCurrentLength < ((SYNC_WORD_LNGTH + 21) >> 3))
{
return NO_ENOUGH_MAIN_DATA_ERROR;
}
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index 1fb2088..a836ad7 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -94,7 +94,7 @@ private:
status_t seekInternal_l(off_t offset);
size_t approxDataRemaining_l(bool *eos);
- void restartPrefetcherIfNecessary_l();
+ void restartPrefetcherIfNecessary_l(bool force = false);
DISALLOW_EVIL_CONSTRUCTORS(NuCachedSource2);
};
diff --git a/media/libstagefright/include/NuHTTPDataSource.h b/media/libstagefright/include/NuHTTPDataSource.h
index 3c88cc2..ad22807 100644
--- a/media/libstagefright/include/NuHTTPDataSource.h
+++ b/media/libstagefright/include/NuHTTPDataSource.h
@@ -1,3 +1,19 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
#ifndef NU_HTTP_DATA_SOURCE_H_
#define NU_HTTP_DATA_SOURCE_H_
diff --git a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
index 13988cd..9f6bd29 100644
--- a/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4ElementaryAssembler.cpp
@@ -104,7 +104,7 @@ AMPEG4ElementaryAssembler::AMPEG4ElementaryAssembler(
mNextExpectedSeqNoValid(false),
mNextExpectedSeqNo(0),
mAccessUnitDamaged(false) {
- mIsGeneric = desc.startsWith("mpeg4-generic/");
+ mIsGeneric = !strncasecmp(desc.c_str(),"mpeg4-generic/", 14);
if (mIsGeneric) {
AString value;
diff --git a/media/libstagefright/rtsp/APacketSource.cpp b/media/libstagefright/rtsp/APacketSource.cpp
index 10cc88b..7f09248 100644
--- a/media/libstagefright/rtsp/APacketSource.cpp
+++ b/media/libstagefright/rtsp/APacketSource.cpp
@@ -627,7 +627,7 @@ APacketSource::APacketSource(
mFormat->setInt32(kKeyWidth, width);
mFormat->setInt32(kKeyHeight, height);
- } else if (!strncmp(desc.c_str(), "mpeg4-generic/", 14)) {
+ } else if (!strncasecmp(desc.c_str(), "mpeg4-generic/", 14)) {
AString val;
if (!GetAttribute(params.c_str(), "mode", &val)
|| (strcasecmp(val.c_str(), "AAC-lbr")
diff --git a/media/libstagefright/rtsp/ARTPConnection.cpp b/media/libstagefright/rtsp/ARTPConnection.cpp
index 5a1ea5c..72943ff 100644
--- a/media/libstagefright/rtsp/ARTPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTPConnection.cpp
@@ -123,7 +123,7 @@ void ARTPConnection::MakePortPair(
struct sockaddr_in addr;
memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = INADDR_ANY;
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
addr.sin_port = htons(port);
if (bind(*rtpSocket,
@@ -346,6 +346,8 @@ void ARTPConnection::onPollStreams() {
}
status_t ARTPConnection::receive(StreamInfo *s, bool receiveRTP) {
+ LOGV("receiving %s", receiveRTP ? "RTP" : "RTCP");
+
CHECK(!s->mIsInjected);
sp<ABuffer> buffer = new ABuffer(65536);
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 5aae4e7..87b5a7e 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -67,7 +67,7 @@ ARTPSource::ARTPSource(
} else if (!strncmp(desc.c_str(), "AMR-WB/", 7)) {
mAssembler = new AAMRAssembler(notify, true /* isWide */, params);
} else if (!strncmp(desc.c_str(), "MP4V-ES/", 8)
- || !strncmp(desc.c_str(), "mpeg4-generic/", 14)) {
+ || !strncasecmp(desc.c_str(), "mpeg4-generic/", 14)) {
mAssembler = new AMPEG4ElementaryAssembler(notify, desc, params);
mIssueFIRRequests = true;
} else {
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index e936923..0740515 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -545,6 +545,10 @@ sp<ABuffer> ARTSPConnection::receiveBinaryData() {
return buffer;
}
+static bool IsRTSPVersion(const AString &s) {
+ return s == "RTSP/1.0";
+}
+
bool ARTSPConnection::receiveRTSPReponse() {
AString statusLine;
@@ -584,13 +588,27 @@ bool ARTSPConnection::receiveRTSPReponse() {
return false;
}
- AString statusCodeStr(
- response->mStatusLine, space1 + 1, space2 - space1 - 1);
+ bool isRequest = false;
- if (!ParseSingleUnsignedLong(
- statusCodeStr.c_str(), &response->mStatusCode)
- || response->mStatusCode < 100 || response->mStatusCode > 999) {
- return false;
+ if (!IsRTSPVersion(AString(response->mStatusLine, 0, space1))) {
+ CHECK(IsRTSPVersion(
+ AString(
+ response->mStatusLine,
+ space2 + 1,
+ response->mStatusLine.size() - space2 - 1)));
+
+ isRequest = true;
+
+ response->mStatusCode = 0;
+ } else {
+ AString statusCodeStr(
+ response->mStatusLine, space1 + 1, space2 - space1 - 1);
+
+ if (!ParseSingleUnsignedLong(
+ statusCodeStr.c_str(), &response->mStatusCode)
+ || response->mStatusCode < 100 || response->mStatusCode > 999) {
+ return false;
+ }
}
AString line;
@@ -680,7 +698,63 @@ bool ARTSPConnection::receiveRTSPReponse() {
}
}
- return notifyResponseListener(response);
+ return isRequest
+ ? handleServerRequest(response)
+ : notifyResponseListener(response);
+}
+
+bool ARTSPConnection::handleServerRequest(const sp<ARTSPResponse> &request) {
+ // Implementation of server->client requests is optional for all methods
+ // but we do need to respond, even if it's just to say that we don't
+ // support the method.
+
+ ssize_t space1 = request->mStatusLine.find(" ");
+ CHECK_GE(space1, 0);
+
+ AString response;
+ response.append("RTSP/1.0 501 Not Implemented\r\n");
+
+ ssize_t i = request->mHeaders.indexOfKey("cseq");
+
+ if (i >= 0) {
+ AString value = request->mHeaders.valueAt(i);
+
+ unsigned long cseq;
+ if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) {
+ return false;
+ }
+
+ response.append("CSeq: ");
+ response.append(cseq);
+ response.append("\r\n");
+ }
+
+ response.append("\r\n");
+
+ size_t numBytesSent = 0;
+ while (numBytesSent < response.size()) {
+ ssize_t n =
+ send(mSocket, response.c_str() + numBytesSent,
+ response.size() - numBytesSent, 0);
+
+ if (n == 0) {
+ // Server closed the connection.
+ LOGE("Server unexpectedly closed the connection.");
+
+ return false;
+ } else if (n < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+
+ LOGE("Error sending rtsp response.");
+ return false;
+ }
+
+ numBytesSent += (size_t)n;
+ }
+
+ return true;
}
// static
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 19be2a6..0fecf3c 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -109,6 +109,8 @@ private:
status_t findPendingRequest(
const sp<ARTSPResponse> &response, ssize_t *index) const;
+ bool handleServerRequest(const sp<ARTSPResponse> &request);
+
static bool ParseSingleUnsignedLong(
const char *from, unsigned long *x);
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 3e710dc..f03f7a2 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -71,6 +71,11 @@ bool ASessionDescription::parse(const void *data, size_t size) {
line.setTo(desc, i, eolPos - i);
}
+ if (line.empty()) {
+ i = eolPos + 1;
+ continue;
+ }
+
if (line.size() < 2 || line.c_str()[1] != '=') {
return false;
}
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 306a9c1..72a2fdb 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -38,6 +38,7 @@
#include <arpa/inet.h>
#include <sys/socket.h>
+#include <netdb.h>
// If no access units are received within 3 secs, assume that the rtp
// stream has ended and signal end of stream.
@@ -119,9 +120,10 @@ struct MyHandler : public AHandler {
// want to transmit user/pass in cleartext.
AString host, path, user, pass;
unsigned port;
- if (ARTSPConnection::ParseURL(
- mSessionURL.c_str(), &host, &port, &path, &user, &pass)
- && user.size() > 0) {
+ CHECK(ARTSPConnection::ParseURL(
+ mSessionURL.c_str(), &host, &port, &path, &user, &pass));
+
+ if (user.size() > 0) {
mSessionURL.clear();
mSessionURL.append("rtsp://");
mSessionURL.append(host);
@@ -131,6 +133,8 @@ struct MyHandler : public AHandler {
LOGI("rewritten session url: '%s'", mSessionURL.c_str());
}
+
+ mSessionHost = host;
}
void connect(const sp<AMessage> &doneMsg) {
@@ -246,34 +250,64 @@ struct MyHandler : public AHandler {
// In case we're behind NAT, fire off two UDP packets to the remote
// rtp/rtcp ports to poke a hole into the firewall for future incoming
// packets. We're going to send an RR/SDES RTCP packet to both of them.
- void pokeAHole(int rtpSocket, int rtcpSocket, const AString &transport) {
+ bool pokeAHole(int rtpSocket, int rtcpSocket, const AString &transport) {
+ struct sockaddr_in addr;
+ memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+ addr.sin_family = AF_INET;
+
AString source;
AString server_port;
if (!GetAttribute(transport.c_str(),
"source",
- &source)
- || !GetAttribute(transport.c_str(),
+ &source)) {
+ LOGW("Missing 'source' field in Transport response. Using "
+ "RTSP endpoint address.");
+
+ struct hostent *ent = gethostbyname(mSessionHost.c_str());
+ if (ent == NULL) {
+ LOGE("Failed to look up address of session host '%s'",
+ mSessionHost.c_str());
+
+ return false;
+ }
+
+ addr.sin_addr.s_addr = *(in_addr_t *)ent->h_addr;
+ } else {
+ addr.sin_addr.s_addr = inet_addr(source.c_str());
+ }
+
+ if (!GetAttribute(transport.c_str(),
"server_port",
&server_port)) {
- return;
+ LOGI("Missing 'server_port' field in Transport response.");
+ return false;
}
int rtpPort, rtcpPort;
if (sscanf(server_port.c_str(), "%d-%d", &rtpPort, &rtcpPort) != 2
|| rtpPort <= 0 || rtpPort > 65535
|| rtcpPort <=0 || rtcpPort > 65535
- || rtcpPort != rtpPort + 1
- || (rtpPort & 1) != 0) {
- return;
+ || rtcpPort != rtpPort + 1) {
+ LOGE("Server picked invalid RTP/RTCP port pair %s,"
+ " RTP port must be even, RTCP port must be one higher.",
+ server_port.c_str());
+
+ return false;
}
- struct sockaddr_in addr;
- memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
- addr.sin_family = AF_INET;
- addr.sin_addr.s_addr = inet_addr(source.c_str());
+ if (rtpPort & 1) {
+ LOGW("Server picked an odd RTP port, it should've picked an "
+ "even one, we'll let it pass for now, but this may break "
+ "in the future.");
+ }
if (addr.sin_addr.s_addr == INADDR_NONE) {
- return;
+ return true;
+ }
+
+ if (IN_LOOPBACK(ntohl(addr.sin_addr.s_addr))) {
+ // No firewalls to traverse on the loopback interface.
+ return true;
}
// Make up an RR/SDES RTCP packet.
@@ -287,16 +321,26 @@ struct MyHandler : public AHandler {
ssize_t n = sendto(
rtpSocket, buf->data(), buf->size(), 0,
(const sockaddr *)&addr, sizeof(addr));
- CHECK_EQ(n, (ssize_t)buf->size());
+
+ if (n < (ssize_t)buf->size()) {
+ LOGE("failed to poke a hole for RTP packets");
+ return false;
+ }
addr.sin_port = htons(rtcpPort);
n = sendto(
rtcpSocket, buf->data(), buf->size(), 0,
(const sockaddr *)&addr, sizeof(addr));
- CHECK_EQ(n, (ssize_t)buf->size());
+
+ if (n < (ssize_t)buf->size()) {
+ LOGE("failed to poke a hole for RTCP packets");
+ return false;
+ }
LOGV("successfully poked holes.");
+
+ return true;
}
virtual void onMessageReceived(const sp<AMessage> &msg) {
@@ -379,6 +423,7 @@ struct MyHandler : public AHandler {
response->mContent->size());
if (!mSessionDesc->isValid()) {
+ LOGE("Failed to parse session description.");
result = ERROR_MALFORMED;
} else {
ssize_t i = response->mHeaders.indexOfKey("content-base");
@@ -393,6 +438,25 @@ struct MyHandler : public AHandler {
}
}
+ if (!mBaseURL.startsWith("rtsp://")) {
+ // Some misbehaving servers specify a relative
+ // URL in one of the locations above, combine
+ // it with the absolute session URL to get
+ // something usable...
+
+ LOGW("Server specified a non-absolute base URL"
+ ", combining it with the session URL to "
+ "get something usable...");
+
+ AString tmp;
+ CHECK(MakeURL(
+ mSessionURL.c_str(),
+ mBaseURL.c_str(),
+ &tmp));
+
+ mBaseURL = tmp;
+ }
+
CHECK_GT(mSessionDesc->countTracks(), 1u);
setupTrack(1);
}
@@ -453,9 +517,12 @@ struct MyHandler : public AHandler {
if (!track->mUsingInterleavedTCP) {
AString transport = response->mHeaders.valueAt(i);
- pokeAHole(track->mRTPSocket,
- track->mRTCPSocket,
- transport);
+ // We are going to continue even if we were
+ // unable to poke a hole into the firewall...
+ pokeAHole(
+ track->mRTPSocket,
+ track->mRTCPSocket,
+ transport);
}
mRTPConn->addStream(
@@ -865,10 +932,7 @@ struct MyHandler : public AHandler {
case 'tiou':
{
if (!mReceivedFirstRTCPPacket) {
- if (mTryFakeRTCP) {
- LOGW("Never received any data, disconnecting.");
- (new AMessage('abor', id()))->post();
- } else if (mTryTCPInterleaving && mReceivedFirstRTPPacket) {
+ if (mReceivedFirstRTPPacket && !mTryFakeRTCP) {
LOGW("We received RTP packets but no RTCP packets, "
"using fake timestamps.");
@@ -876,7 +940,7 @@ struct MyHandler : public AHandler {
mReceivedFirstRTCPPacket = true;
mRTPConn->fakeTimestamps();
- } else {
+ } else if (!mReceivedFirstRTPPacket && !mTryTCPInterleaving) {
LOGW("Never received any data, switching transports.");
mTryTCPInterleaving = true;
@@ -884,6 +948,9 @@ struct MyHandler : public AHandler {
sp<AMessage> msg = new AMessage('abor', id());
msg->setInt32("reconnect", true);
msg->post();
+ } else {
+ LOGW("Never received any data, disconnecting.");
+ (new AMessage('abor', id()))->post();
}
}
break;
@@ -1010,6 +1077,7 @@ private:
sp<ASessionDescription> mSessionDesc;
AString mOriginalSessionURL; // This one still has user:pass@
AString mSessionURL;
+ AString mSessionHost;
AString mBaseURL;
AString mSessionID;
bool mSetupTracksSuccessful;
diff --git a/nfc-extras/Android.mk b/nfc-extras/Android.mk
new file mode 100644
index 0000000..131d898
--- /dev/null
+++ b/nfc-extras/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_MODULE:= com.android.nfc_extras
+
+include $(BUILD_JAVA_LIBRARY)
+
+# put the classes.jar, with full class files instead of classes.dex inside, into the dist directory
+$(call dist-for-goals, droidcore, $(full_classes_jar):com.android.nfc_extras.jar)
diff --git a/nfc-extras/com.android.nfc_extras.xml b/nfc-extras/com.android.nfc_extras.xml
new file mode 100644
index 0000000..370145d
--- /dev/null
+++ b/nfc-extras/com.android.nfc_extras.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2011 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+
+<permissions>
+ <library name="com.android.nfc_extras"
+ file="/system/framework/com.android.nfc_extras.jar" />
+</permissions>
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
new file mode 100644
index 0000000..9bd8f36
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/NfcAdapterExtras.java
@@ -0,0 +1,204 @@
+/*
+ * 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.nfc_extras;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.nfc.ApduList;
+import android.nfc.INfcAdapterExtras;
+import android.nfc.NfcAdapter;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Provides additional methods on an {@link NfcAdapter} for Card Emulation
+ * and management of {@link NfcExecutionEnvironment}'s.
+ *
+ * There is a 1-1 relationship between an {@link NfcAdapterExtras} object and
+ * a {@link NfcAdapter} object.
+ */
+public final class NfcAdapterExtras {
+ private static final String TAG = "NfcAdapterExtras";
+
+ /**
+ * Broadcast Action: an RF field ON has been detected.
+ *
+ * <p class="note">This is an unreliable signal, and will be removed.
+ * <p class="note">
+ * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
+ * to receive.
+ */
+ public static final String ACTION_RF_FIELD_ON_DETECTED =
+ "com.android.nfc_extras.action.RF_FIELD_ON_DETECTED";
+
+ /**
+ * Broadcast Action: an RF field OFF has been detected.
+ *
+ * <p class="note">This is an unreliable signal, and will be removed.
+ * <p class="note">
+ * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
+ * to receive.
+ */
+ public static final String ACTION_RF_FIELD_OFF_DETECTED =
+ "com.android.nfc_extras.action.RF_FIELD_OFF_DETECTED";
+
+ // protected by NfcAdapterExtras.class, and final after first construction
+ private static INfcAdapterExtras sService;
+ private static NfcAdapterExtras sSingleton;
+ private static NfcExecutionEnvironment sEmbeddedEe;
+ private static CardEmulationRoute sRouteOff;
+ private static CardEmulationRoute sRouteOnWhenScreenOn;
+
+ /**
+ * Get the {@link NfcAdapterExtras} for the given {@link NfcAdapter}.
+ *
+ * <p class="note">
+ * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+ *
+ * @param adapter a {@link NfcAdapter}, must not be null
+ * @return the {@link NfcAdapterExtras} object for the given {@link NfcAdapter}
+ */
+ public static NfcAdapterExtras get(NfcAdapter adapter) {
+ synchronized(NfcAdapterExtras.class) {
+ if (sSingleton == null) {
+ try {
+ sService = adapter.getNfcAdapterExtrasInterface();
+ sEmbeddedEe = new NfcExecutionEnvironment(sService);
+ sRouteOff = new CardEmulationRoute(CardEmulationRoute.ROUTE_OFF, null);
+ sRouteOnWhenScreenOn = new CardEmulationRoute(
+ CardEmulationRoute.ROUTE_ON_WHEN_SCREEN_ON, sEmbeddedEe);
+ sSingleton = new NfcAdapterExtras();
+ } finally {
+ if (sSingleton == null) {
+ sService = null;
+ sEmbeddedEe = null;
+ sRouteOff = null;
+ sRouteOnWhenScreenOn = null;
+ }
+ }
+ }
+ return sSingleton;
+ }
+ }
+
+ private NfcAdapterExtras() {}
+
+ /**
+ * Immutable data class that describes a card emulation route.
+ */
+ public final static class CardEmulationRoute {
+ /**
+ * Card Emulation is turned off on this NfcAdapter.
+ * <p>This is the default routing state after boot.
+ */
+ public static final int ROUTE_OFF = 1;
+
+ /**
+ * Card Emulation is routed to {@link #nfcEe} only when the screen is on,
+ * otherwise it is turned off.
+ */
+ public static final int ROUTE_ON_WHEN_SCREEN_ON = 2;
+
+ /**
+ * A route such as {@link #ROUTE_OFF} or {@link #ROUTE_ON_WHEN_SCREEN_ON}.
+ */
+ public final int route;
+
+ /**
+ * The {@link NFcExecutionEnvironment} that is Card Emulation is routed to.
+ * <p>null if {@link #route} is {@link #ROUTE_OFF}, otherwise not null.
+ */
+ public final NfcExecutionEnvironment nfcEe;
+
+ public CardEmulationRoute(int route, NfcExecutionEnvironment nfcEe) {
+ if (route == ROUTE_OFF && nfcEe != null) {
+ throw new IllegalArgumentException("must not specifiy a NFC-EE with ROUTE_OFF");
+ } else if (route != ROUTE_OFF && nfcEe == null) {
+ throw new IllegalArgumentException("must specifiy a NFC-EE for this route");
+ }
+ this.route = route;
+ this.nfcEe = nfcEe;
+ }
+ }
+
+ /**
+ * Get the routing state of this NFC EE.
+ *
+ * <p class="note">
+ * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+ *
+ * @return
+ */
+ public CardEmulationRoute getCardEmulationRoute() {
+ try {
+ int route = sService.getCardEmulationRoute();
+ return route == CardEmulationRoute.ROUTE_OFF ?
+ sRouteOff :
+ sRouteOnWhenScreenOn;
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ return sRouteOff;
+ }
+ }
+
+ /**
+ * Set the routing state of this NFC EE.
+ *
+ * <p>This routing state is not persisted across reboot.
+ *
+ * <p class="note">
+ * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+ *
+ * @param route a {@link #CardEmulationRoute}
+ */
+ public void setCardEmulationRoute(CardEmulationRoute route) {
+ try {
+ sService.setCardEmulationRoute(route.route);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ /**
+ * Get the {@link NfcExecutionEnvironment} that is embedded with the
+ * {@link NFcAdapter}.
+ *
+ * <p class="note">
+ * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+ *
+ * @return a {@link NfcExecutionEnvironment}, or null if there is no embedded NFC-EE
+ */
+ public NfcExecutionEnvironment getEmbeddedExecutionEnvironment() {
+ return sEmbeddedEe;
+ }
+
+ public void registerTearDownApdus(String packageName, ApduList apdus) {
+ try {
+ sService.registerTearDownApdus(packageName, apdus);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+
+ public void unregisterTearDownApdus(String packageName) {
+ try {
+ sService.unregisterTearDownApdus(packageName);
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ }
+ }
+}
diff --git a/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
new file mode 100644
index 0000000..3efe492
--- /dev/null
+++ b/nfc-extras/java/com/android/nfc_extras/NfcExecutionEnvironment.java
@@ -0,0 +1,125 @@
+/*
+ * 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.nfc_extras;
+
+import java.io.IOException;
+
+import android.annotation.SdkConstant;
+import android.annotation.SdkConstant.SdkConstantType;
+import android.content.Context;
+import android.nfc.INfcAdapterExtras;
+import android.nfc.NfcAdapter;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+
+public class NfcExecutionEnvironment {
+ private final INfcAdapterExtras mService;
+
+ /**
+ * Broadcast Action: An ISO-DEP AID was selected.
+ *
+ * <p>This happens as the result of a 'SELECT AID' command from an
+ * external NFC reader/writer.
+ *
+ * <p>Always contains the extra field {@link #EXTRA_AID}
+ *
+ * <p class="note">
+ * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission
+ * to receive.
+ */
+ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+ public static final String ACTION_AID_SELECTED =
+ "com.android.nfc_extras.action.AID_SELECTED";
+
+ /**
+ * Mandatory byte array extra field in {@link #ACTION_AID_SELECTED}.
+ *
+ * <p>Contains the AID selected.
+ * @hide
+ */
+ public static final String EXTRA_AID = "com.android.nfc_extras.extra.AID";
+
+ NfcExecutionEnvironment(INfcAdapterExtras service) {
+ mService = service;
+ }
+
+ /**
+ * Open the NFC Execution Environment on its contact interface.
+ *
+ * <p>Only one process may open the secure element at a time. If it is
+ * already open, an {@link IOException} is thrown.
+ *
+ * <p>All other NFC functionality is disabled while the NFC-EE is open
+ * on its contact interface, so make sure to call {@link #close} once complete.
+ *
+ * <p class="note">
+ * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+ *
+ * @throws IOException if the NFC-EE is already open, or some other error occurs
+ */
+ public void open() throws IOException {
+ try {
+ Bundle b = mService.open(new Binder());
+ throwBundle(b);
+ } catch (RemoteException e) {
+ return;
+ }
+ }
+
+ /**
+ * Close the NFC Execution Environment on its contact interface.
+ *
+ * <p class="note">
+ * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+ *
+ * @throws IOException if the NFC-EE is already open, or some other error occurs
+ */
+ public void close() throws IOException {
+ try {
+ throwBundle(mService.close());
+ } catch (RemoteException e) {
+ return;
+ }
+ }
+
+ /**
+ * Send raw commands to the NFC-EE and receive the response.
+ *
+ * <p class="note">
+ * Requires the {@link android.Manifest.permission#WRITE_SECURE_SETTINGS} permission.
+ *
+ * @throws IOException if the NFC-EE is not open, or some other error occurs
+ */
+ public byte[] transceive(byte[] in) throws IOException {
+ Bundle b;
+ try {
+ b = mService.transceive(in);
+ } catch (RemoteException e) {
+ throw new IOException(e.getMessage());
+ }
+ throwBundle(b);
+ return b.getByteArray("out");
+ }
+
+ private static void throwBundle(Bundle b) throws IOException {
+ if (b.getInt("e") == -1) {
+ throw new IOException(b.getString("m"));
+ }
+ }
+}
diff --git a/obex/javax/obex/ClientSession.java b/obex/javax/obex/ClientSession.java
index 0935383..27d8976 100644
--- a/obex/javax/obex/ClientSession.java
+++ b/obex/javax/obex/ClientSession.java
@@ -449,8 +449,8 @@ public final class ClientSession extends ObexSession {
maxPacketSize = (mInput.read() << 8) + mInput.read();
//check with local max size
- if (maxPacketSize > ObexHelper.MAX_PACKET_SIZE_INT) {
- maxPacketSize = ObexHelper.MAX_PACKET_SIZE_INT;
+ if (maxPacketSize > ObexHelper.MAX_CLIENT_PACKET_SIZE) {
+ maxPacketSize = ObexHelper.MAX_CLIENT_PACKET_SIZE;
}
if (length > 7) {
diff --git a/obex/javax/obex/ObexHelper.java b/obex/javax/obex/ObexHelper.java
index 1b66662..7852fe9 100644
--- a/obex/javax/obex/ObexHelper.java
+++ b/obex/javax/obex/ObexHelper.java
@@ -70,6 +70,12 @@ public final class ObexHelper {
*/
public static final int MAX_PACKET_SIZE_INT = 0xFFFE;
+ /**
+ * Temporary workaround to be able to push files to Windows 7.
+ * TODO: Should be removed as soon as Microsoft updates their driver.
+ */
+ public static final int MAX_CLIENT_PACKET_SIZE = 0xFC00;
+
public static final int OBEX_OPCODE_CONNECT = 0x80;
public static final int OBEX_OPCODE_DISCONNECT = 0x81;
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 7995869..a979d65 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -5,6 +5,7 @@
>
<uses-permission android:name="android.permission.STATUS_BAR_SERVICE" />
+ <uses-permission android:name="android.permission.MANAGE_USB" />
<application
android:persistent="true"
@@ -25,5 +26,40 @@
android:excludeFromRecents="true">
</activity>
+ <!-- started from UsbDeviceSettingsManager -->
+ <activity android:name=".usb.UsbConfirmActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_USB"
+ android:theme="@*android:style/Theme.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
+
+ <!-- started from UsbDeviceSettingsManager -->
+ <activity android:name=".usb.UsbPermissionActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_USB"
+ android:theme="@*android:style/Theme.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
+
+ <!-- started from UsbDeviceSettingsManager -->
+ <activity android:name=".usb.UsbResolverActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_USB"
+ android:theme="@*android:style/Theme.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
+
+ <!-- started from UsbDeviceSettingsManager -->
+ <activity android:name=".usb.UsbAccessoryUriActivity"
+ android:exported="true"
+ android:permission="android.permission.MANAGE_USB"
+ android:theme="@*android:style/Theme.Dialog.Alert"
+ android:finishOnCloseSystemDialogs="true"
+ android:excludeFromRecents="true">
+ </activity>
</application>
</manifest>
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png
new file mode 100644
index 0000000..1aea612
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png
new file mode 100644
index 0000000..425535e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png
new file mode 100644
index 0000000..fcad363
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png
new file mode 100644
index 0000000..4ff7db3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png
new file mode 100644
index 0000000..2c4a07f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.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_inadnout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.png
new file mode 100644
index 0000000..61a7503
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.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_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_wimax_signal_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.png
new file mode 100644
index 0000000..f24d801
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png
new file mode 100644
index 0000000..66eb5db
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_0_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png
new file mode 100644
index 0000000..edff74a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png
new file mode 100644
index 0000000..1cdd4eb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_1_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png
new file mode 100644
index 0000000..95fdaf9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png
new file mode 100644
index 0000000..8678e39
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_2_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png
new file mode 100644
index 0000000..1d2d290
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
new file mode 100644
index 0000000..c2e4b78
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_3_fully.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
new file mode 100644
index 0000000..51b839f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_disconnected.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png
new file mode 100644
index 0000000..b20c5c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_wimax_signal_idle.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
index adde938..c8ddfce 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
index adde938..6b6a6df 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_roaming_cdma_flash_anim1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
index 78ece9e..c77e61e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
index 31fc1b0..b9f721a 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png
new file mode 100644
index 0000000..cff969e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
index 19adb4b..d2d7ab3 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
index fd419ea..83ce6d0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
index 94e77ae..abe511f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
index 91328c0..d685af8 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
index 2fee692..8c697a1 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png
new file mode 100644
index 0000000..9a4b807
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
index d0968aa..eb11d04 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
index 991228b..6e54de0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
index ae03e38..5bfb33b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png
index 97b011e..119067b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png
index a826866..a70cc2e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png
new file mode 100644
index 0000000..ea3dba7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png
index f6a6891..53221b9 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png
index 19b9816..11d44d0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png
index f8c0961..9defd79 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png
index 22deb70..136576d 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png
index c7c1b49..26ca31f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png
new file mode 100644
index 0000000..de8c5ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png
index d9a0702..64dbf3c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png
index 6beed8a..34923fb 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png
index e4179c1..506b5c6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png
index 4b2f86d..163976f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png
index 6779604..a6af649 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png
new file mode 100644
index 0000000..0c08e52
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png
index 1309a97..1d02edb 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png
index 2fc1e8e..edc9536 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png
index 0eef2c1..8376817 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
index f8904e2..ecef547 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
index 3ef306e..a7c48b6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png
new file mode 100644
index 0000000..f4bcd9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
index 2ff6d90..b46bb3a 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
index 8ff49b0..e8b70f2 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
index f416203..4e23c4e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png
new file mode 100644
index 0000000..ced9175
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
index 24b7daa..92d4a19 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
index 5ea9142..a208736 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png
new file mode 100644
index 0000000..f407bc9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
index 002bf46..b8a65c2 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
index 924b84f..a978b68 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
index bd0d1ca..710dd52 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
index f583eec..a7b35e4 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png
new file mode 100644
index 0000000..bb05449
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
index 66940ea..a144222 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
index 0381f52..b0eafb6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
index 0b84fe8..f6b83d0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
index c61cce7..827d84a 100755
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
index c61cce7..edc6023 100755
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_roaming_cdma_flash_anim1.png
Binary files differ
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 68b0b0a..dc6beb5 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"البطارية منخفضة:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"يتبقى <xliff:g id="NUMBER">%d%%</xliff:g> أو أقل."</string>
<string name="battery_low_why" msgid="7279169609518386372">"استخدام البطارية"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"لا يعمل أي تطبيق مثبت مع ملحق UEB هذا. تعرف على المزيد عن هذا الملحق على <xliff:g id="URL">%1$s</xliff:g>."</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"ملحق USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"عرض"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"الاستخدام بشكل افتراضي لملحق USB هذا"</string>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 12a3f23..d9ee86a 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Батерията се изтощава:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Остава <xliff:g id="NUMBER">%d%%</xliff:g> или по-малко."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Използване на батерията"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Инсталираните приложения не работят с този аксесоар за USB. Научете повече на адрес <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Аксесоар за USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Преглед"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Използване по подразб. за този аксесоар за USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 655cd63..debf301 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Comença a quedar poca bateria:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"En queda un <xliff:g id="NUMBER">%d%%</xliff:g> o menys."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Ús de la bateria"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Cap de les aplicacions instal·lades no funciona amb aquest accessori USB. Més informació a <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Accessori USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Mostra"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Utilitza de manera predet. per a l\'accessori USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 3e7136a..7095c34 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Baterie je vybitá:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Zbývá <xliff:g id="NUMBER">%d%%</xliff:g> nebo méně."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Využití baterie"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"S tímto periferním zařízením USB nefunguje žádná nainstalovaná aplikace. Další informace naleznete na stránkách <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Periferní zařízení USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Zobrazit"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Pro toto periferní zařízení USB použít jako výchozí"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index bf549fd..86185e1 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet er ved at være fladt:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> eller mindre tilbage."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Batteriforbrug"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Ingen inst. programmer virker med USB-ekstraudstyret. Få oplysninger om ekstraudstyret på <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB-ekstraudstyr"</string>
+ <string name="label_view" msgid="6304565553218192990">"Vis"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Brug som standard til dette USB-tilbehør"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index e534116..a88244b 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Akku ist fast leer."</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> oder weniger verbleiben."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Akkuverbrauch"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Keine installierten Anwendungen für dieses USB-Zubehör. Weitere Informationen unter <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB-Zubehör"</string>
+ <string name="label_view" msgid="6304565553218192990">"Anzeigen"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Standardmäßig für dieses USB-Zubehör verwenden"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index c96e403..8200a30 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Η στάθμη της μπαταρίας είναι χαμηλή:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Απομένει <xliff:g id="NUMBER">%d%%</xliff:g> ή λιγότερο."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Χρήση μπαταρίας"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Καμία εγκατ. εφαρμ. δεν συνεργ. με το αξ. USB. Μάθετε περισ. για το αξ. στο <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Αξεσουάρ USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Προβολή"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Χρήση από προεπιλογή για αυτό το εξάρτημα USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index 74343da..cb21a03 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"The battery is getting low:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> or less remaining."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Battery use"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"No installed applications work with this USB accessory. Learn more about this accessory at <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB accessory"</string>
+ <string name="label_view" msgid="6304565553218192990">"View"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Use by default for this USB accessory"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 29a1f20..ce31628 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Hay poca batería:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> o menos disponible."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Las aplicaciones instaladas no funcionan con este accesorio USB. Obtener más información acerca de este accesorio en <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Accesorio USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Ver"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Se usa de forma predeterminada para este accesorio USB."</string>
</resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 3c2b060..1f0fd16 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Se está agotando la batería:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> o menos disponible"</string>
<string name="battery_low_why" msgid="7279169609518386372">"Uso de la batería"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Ninguna aplicación instalada funciona con este accesorio USB. Más información: <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Accesorio USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Ver"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Usar de forma predeterminada para este accesorio USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index ff72480..fe85637 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"باتری در حال کم شدن است:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> یا کمتر باقیمانده است."</string>
<string name="battery_low_why" msgid="7279169609518386372">"استفاده از باتری"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"برنامه های نصب شده با این وسیله جانبی USB کار می کنند. در <xliff:g id="URL">%1$s</xliff:g>راجع به این لوازم جانبی بیشتر بیاموزید"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"لوازم جانبی USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"مشاهده"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"استفاده به صورت پیش فرض برای این دستگاه USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 4e69881..ab43e71 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Akun virta on vähissä:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"jäljellä <xliff:g id="NUMBER">%d%%</xliff:g> tai vähemmän."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Akun käyttö"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Asennetut sov. eivät toimi tämän USB-lisälaitteen kanssa. Lisätietoja lisälaitteesta os. <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB-lisälaite"</string>
+ <string name="label_view" msgid="6304565553218192990">"Näytä"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Käytä oletuksena tällä USB-lisälaitteella"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index b3aa6d9..8865e0f 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Le niveau de la batterie est bas :"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Maximum <xliff:g id="NUMBER">%d%%</xliff:g> restants."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Utilisation de la batterie"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Aucune application installée n\'est compatible avec cet accessoire USB. En savoir plus sur <xliff:g id="URL">%1$s</xliff:g>."</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Accessoire USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Afficher"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Utiliser par défaut pour cet accessoire USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 9a6b95d..ab133f1 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Baterija će uskoro biti potrošena:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Preostaje <xliff:g id="NUMBER">%d%%</xliff:g> ili manje."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Iskorištenost baterije"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Nijedna instalirana aplikacija ne radi s ovim USB dodatkom. Saznajte više o ovom dodatku na <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB pribor"</string>
+ <string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Koristi se prema zadanim postavkama za ovaj USB pribor"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 2bddb7e..ff2f4bf 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Akkufeszültség alacsony:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> vagy kevesebb maradt."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Akkumulátorhasználat"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"A telepített alkalmazások nem működnek ezzel az USB-kiegészítővel. Bővebben: <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB-kellék"</string>
+ <string name="label_view" msgid="6304565553218192990">"Megtekintés"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Alapértelmezett használat ehhez az USB-kiegészítőhöz"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index c49accf..d51a51d 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Baterai kekurangan daya:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> atau kurang yang tersisa."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Penggunaan baterai"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Tidak ada aplikasi terpasang yang bekerja dengan aksesori USB ini. Pelajari aksesori ini lebih lanjut di <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Aksesori USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Lihat"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Gunakan secara bawaan untuk aksesori USB ini"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index f0003fc..7e75478 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Batteria quasi scarica:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> rimanente o meno."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Utilizzo batteria"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Applicazioni installate non funzionano con accessorio USB. Altre informazioni su accessorio su <xliff:g id="URL">%1$s</xliff:g>."</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Accessorio USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Visualizza"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Usa per impostazione predef. per accessorio USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 6b6e628..3fe91b26 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"הסוללה נחלשת:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"נותרו עוד <xliff:g id="NUMBER">%d%%</xliff:g> או פחות."</string>
<string name="battery_low_why" msgid="7279169609518386372">"צריכת סוללה"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"אין יישומים מותקנים הפועלים עם אביזר ה-USB. למידע נוסף אודות אביזר זה בכתובת <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"עזרי USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"הצג"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"השתמש כברירת מחדל עבור אביזר USB זה"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 7ac8227..ee75d38 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"電池が残り少なくなっています:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"残り<xliff:g id="NUMBER">%d%%</xliff:g>未満です。"</string>
<string name="battery_low_why" msgid="7279169609518386372">"電池使用量"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"このUSBアクセサリを扱うアプリはインストールされていません。詳細は <xliff:g id="URL">%1$s</xliff:g> をご覧ください。"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USBアクセサリ"</string>
+ <string name="label_view" msgid="6304565553218192990">"表示"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"このUSBアクセサリにデフォルトで使用する"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index fe76942..56fc57d 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -25,7 +25,17 @@
<string name="status_bar_ongoing_events_title" msgid="1682504513316879202">"진행 중"</string>
<string name="status_bar_latest_events_title" msgid="6594767438577593172">"알림"</string>
<string name="battery_low_title" msgid="7923774589611311406">"충전기를 연결하세요."</string>
- <string name="battery_low_subtitle" msgid="7388781709819722764">"배터리 전원이 부족합니다."</string>
+ <string name="battery_low_subtitle" msgid="7388781709819722764">"배터리가 얼마 남지 않았습니다."</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"잔여 배터리가 <xliff:g id="NUMBER">%d%%</xliff:g> 이하입니다."</string>
<string name="battery_low_why" msgid="7279169609518386372">"배터리 사용량"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"이 USB와 호환되는 설치 애플리케이션이 없습니다. <xliff:g id="URL">%1$s</xliff:g>에서 세부정보를 참조하세요."</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB 액세서리"</string>
+ <string name="label_view" msgid="6304565553218192990">"보기"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"이 USB 액세서리에 기본값으로 사용"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index c016922..47102c6 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Akumuliatorius senka:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Liko <xliff:g id="NUMBER">%d%%</xliff:g> ar mažiau."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Akumuliatoriaus naudojimas"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Su šiuo USB pr. nev. jokios įdieg. pr. Suž. daugiau apie šį pr. šiuo adr.: <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB reikmuo"</string>
+ <string name="label_view" msgid="6304565553218192990">"Žiūrėti"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Šiam USB priedui naudoti pagal numat. nustatymus"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index f462282..60f05fe 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Akumulatora uzlādes līmenis kļūst zems:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Atlicis <xliff:g id="NUMBER">%d%%</xliff:g> vai mazāk."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Akumulatora lietojums"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Neinst. lietojumpr. darbojas ar šo USB pied. Uzz. vairāk par šo piederumu: <xliff:g id="URL">%1$s</xliff:g>."</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB piederums"</string>
+ <string name="label_view" msgid="6304565553218192990">"Skatīt"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Pēc noklusējuma izmantot šim USB piederumam"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 94d7e6a..9d6bddc 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet er nesten tomt:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"mindre enn <xliff:g id="NUMBER">%d%%</xliff:g> igjen."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Batteribruk"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Ingen installerte applikasjoner støtter dette USB-tilbehøret. Les mer om tilbehøret på <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB-enhet"</string>
+ <string name="label_view" msgid="6304565553218192990">"Vis"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Bruk som standard for dette USB-tilbehøret"</string>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index de4f5be..4671361 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"De accu raakt op:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> of minder resterend."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Accugebruik"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Er zijn geen geïnstalleerde applicaties die werken met dit USB-accessoire. Meer informatie over dit accessoire vindt u op <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB-accessoire"</string>
+ <string name="label_view" msgid="6304565553218192990">"Weergeven"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Standaard gebruiken voor dit USB-accessoire"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index b1770d6..af00198 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Bateria się rozładowuje:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Pozostało: <xliff:g id="NUMBER">%d%%</xliff:g> lub mniej."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Użycie baterii"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Zainstalowane aplikacje nie działają z tym akcesorium USB. Więcej informacji: <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Akcesorium USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Wyświetl"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Używaj domyślnie dla tego akcesorium USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index f80031c..383fc09 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"A bateria está a ficar fraca:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Restam <xliff:g id="NUMBER">%d%%</xliff:g> ou menos."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Utilização da bateria"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Nenhuma das aplicações instaladas funciona com este acessório USB. Saiba mais sobre este acessório em <xliff:g id="URL">%1$s</xliff:g>."</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Acessório USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Ver"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Utilizar por predefinição para este acessório USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 3abf8e1..7c800c3 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"A bateria está ficando baixa:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> ou menos restante(s)."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Uso da bateria"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Nenhum apl. instalado funciona com o acess. USB. Saiba mais sobre o acessório em <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Acessório USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Visualizar"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Usar por padrão para este acessório USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-rm/strings.xml b/packages/SystemUI/res/values-rm/strings.xml
index 0db8430..d6ceed5 100644
--- a/packages/SystemUI/res/values-rm/strings.xml
+++ b/packages/SystemUI/res/values-rm/strings.xml
@@ -29,4 +29,18 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"L\'accu è prest vid."</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> u pli pauc restant."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Consum dad accu"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <!-- no translation found for usb_accessory_uri_prompt (6332150684964235705) -->
+ <skip />
+ <!-- no translation found for title_usb_accessory (4966265263465181372) -->
+ <skip />
+ <!-- no translation found for label_view (6304565553218192990) -->
+ <skip />
+ <!-- no translation found for always_use_accessory (1210954576979621596) -->
+ <skip />
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index 3587a03..0fac35d 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Bateria se termină:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"A rămas <xliff:g id="NUMBER">%d%%</xliff:g> sau mai puţin."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Utilizarea bateriei"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Aplic. instal. nu funcţ. cu acest acces. USB. Aflaţi despre acest acces. la <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Accesoriu USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Afişaţi"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Utiliz. în mod prestabilit pt. acest accesoriu USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index e465767..24d3c04 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Батарея разряжена:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Осталось <xliff:g id="NUMBER">%d%%</xliff:g> или меньше."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Расход заряда батареи"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Установленные приложения не поддерживают этот USB-аксессуар. Подробнее о нем читайте здесь: <xliff:g id="URL">%1$s</xliff:g>."</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB-устройство"</string>
+ <string name="label_view" msgid="6304565553218192990">"Просмотр"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Использовать по умолчанию для этого USB-аксессуара"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 929f774..cd25c8d 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Batéria je skoro vybitá:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Zostáva <xliff:g id="NUMBER">%d%%</xliff:g> alebo menej."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Využitie batérie"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"S týmto periférnym zariad. USB nefunguje žiadna nainštalovaná aplikácia. Viac informácií nájdete na stránkach <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Periférne zariadenie USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Zobraziť"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Pre toto periférne zar. USB použiť ako predvolené"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 5ae3ab3..2737460 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Baterija je skoraj prazna:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Preostalo <xliff:g id="NUMBER">%d%%</xliff:g> ali manj."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Uporaba baterije"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Noben nameščen program ne deluje s tem dodatkom USB. Več o tem dodatku: <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Dodatek USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Prikaži"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Privzeto uporabi za ta dodatek USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e6d8bde..cfccd5d 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Ниво напуњености батерије је низак:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Преостало је <xliff:g id="NUMBER">%d%%</xliff:g> или мање."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Коришћење батерије"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Ниједна инстал. апликација не функционише са овим USB додатком. Сазнајте више о додатку на <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB помоћни уређај"</string>
+ <string name="label_view" msgid="6304565553218192990">"Прикажи"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Користи подразумевано за овај USB додатак"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 29147bd..df69140 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Batteriet håller på att ta slut:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> eller mindre kvar."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Batteriförbrukning"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Inga program fungerar med det här USB-tillbehöret. Läs mer om det på <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB-tillbehör"</string>
+ <string name="label_view" msgid="6304565553218192990">"Visa"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Använd som standard för det här USB-tillbehöret"</string>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index e6922c2..2d9d23a 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"แบตเตอรี่เหลือน้อย"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"เหลือ <xliff:g id="NUMBER">%d%%</xliff:g> หรือน้อยกว่า"</string>
<string name="battery_low_why" msgid="7279169609518386372">"การใช้แบตเตอรี่"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"แอปพลิเคชันที่ติดตั้งใช้กับอุปกรณ์ USB นี้ไม่ได้ เรียนรู้เพิ่มเติมที่ <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"อุปกรณ์เสริม USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"ดู"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"ใช้ค่าเริ่มต้นสำหรับอุปกรณ์เสริม USB นี้"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index e54753b..3d9039c 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Humihina ang baterya:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> o mas kaunti ang natitira."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Paggamit ng baterya"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Walang gumaganang mga naka-install na application sa USB accessory na ito <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB accessory"</string>
+ <string name="label_view" msgid="6304565553218192990">"Tingnan"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Gamitin bilang default sa USB accessory na ito"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 43808bc..eb0392d 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Pil tükeniyor:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"<xliff:g id="NUMBER">%d%%</xliff:g> veya daha az kaldı."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Pil kullanımı"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Hiçbir yüklü uyg bu USB aksesuarıyla çalışmıyor. Bu aksesuar hakknd daha fazla bilgi için: <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB aksesuarı"</string>
+ <string name="label_view" msgid="6304565553218192990">"Görüntüle"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Bu USB aksesuar için varsayılan olarak kullan"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 66bc927..449313c 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Батарея виснажується:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"Залиш-ся <xliff:g id="NUMBER">%d%%</xliff:g> або менше."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Викор. батареї"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Установлені прогр. не працюють із цим аксесуаром USB. Більше про цей аксесуар: <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Пристрій USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Переглянути"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Використовувати за умовчанням для аксесуара USB"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f0e6f9d..877c6e2 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"Pin đang yếu:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"còn <xliff:g id="NUMBER">%d%%</xliff:g> hoặc ít hơn."</string>
<string name="battery_low_why" msgid="7279169609518386372">"Sử dụng pin"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"Không có ứng dụng được cài đặt nào hoạt động với phụ kiện USB này. Tìm hiểu thêm về phụ kiện này tại <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"Phụ kiện USB"</string>
+ <string name="label_view" msgid="6304565553218192990">"Xem"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"Sử dụng theo mặc định cho phụ kiện USB này"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 5ac5f97..96d0b03 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"电量所剩不多:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"电量剩余 <xliff:g id="NUMBER">%d%%</xliff:g> 或更少。"</string>
<string name="battery_low_why" msgid="7279169609518386372">"电量使用情况"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"未安装此 USB 配件适用的应用程序。要了解关于此配件的详情,请访问:<xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB 配件"</string>
+ <string name="label_view" msgid="6304565553218192990">"查看"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"默认情况下用于该 USB 配件"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index ed6e02e..3cba543 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -28,4 +28,14 @@
<string name="battery_low_subtitle" msgid="7388781709819722764">"電池電量即將不足:"</string>
<string name="battery_low_percent_format" msgid="696154104579022959">"還剩 <xliff:g id="NUMBER">%d%%</xliff:g> 以下。"</string>
<string name="battery_low_why" msgid="7279169609518386372">"電池使用狀況"</string>
+ <!-- no translation found for usb_accessory_permission_prompt (3969745913539898765) -->
+ <skip />
+ <!-- no translation found for usb_device_confirm_prompt (2727793581411868504) -->
+ <skip />
+ <!-- no translation found for usb_accessory_confirm_prompt (3947430407252730383) -->
+ <skip />
+ <string name="usb_accessory_uri_prompt" msgid="6332150684964235705">"已安裝的應用程式均無法存取這類 USB 配件,如要進一步瞭解這個配件,請造訪 <xliff:g id="URL">%1$s</xliff:g>"</string>
+ <string name="title_usb_accessory" msgid="4966265263465181372">"USB 配件"</string>
+ <string name="label_view" msgid="6304565553218192990">"查看"</string>
+ <string name="always_use_accessory" msgid="1210954576979621596">"預設用於這個 USB 配件"</string>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ba3a3d1..6334b2a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -51,4 +51,25 @@
power usage activity to find out what drained the battery. -->
<string name="battery_low_why">Battery use</string>
+ <!-- Prompt for the USB accessory permission dialog [CHAR LIMIT=80] -->
+ <string name="usb_accessory_permission_prompt">Allow the application %1$s to access the USB accessory?</string>
+
+ <!-- Prompt for the USB device confirm dialog [CHAR LIMIT=80] -->
+ <string name="usb_device_confirm_prompt">Open %1$s when this USB device is connected?</string>
+
+ <!-- Prompt for the USB accessory confirm dialog [CHAR LIMIT=80] -->
+ <string name="usb_accessory_confirm_prompt">Open %1$s when this USB accessory is connected?</string>
+
+ <!-- Prompt for the USB accessory URI dialog [CHAR LIMIT=80] -->
+ <string name="usb_accessory_uri_prompt">No installed applications work with this USB accessory. Learn more about this accessory at <xliff:g id="url">%1$s</xliff:g></string>
+
+ <!-- Title for USB accessory dialog. Used when the name of the accessory cannot be determined. [CHAR LIMIT=50] -->
+ <string name="title_usb_accessory">USB accessory</string>
+
+ <!-- View button label for USB dialogs. [CHAR LIMIT=15] -->
+ <string name="label_view">View</string>
+
+ <!-- Checkbox label for USB accessory dialogs. [CHAR LIMIT=50] -->
+ <string name="always_use_accessory">Use by default for this USB accessory</string>
+
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
index 9ef6e6f..8c0fecf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarPolicy.java
@@ -74,6 +74,7 @@ import com.android.internal.telephony.cdma.TtyIntent;
import com.android.server.am.BatteryStatsService;
import com.android.systemui.R;
+import android.net.wimax.WimaxManagerConstants;
/**
* This class contains all of the policy about which icons are installed in the status
@@ -239,9 +240,165 @@ public class StatusBarPolicy {
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
R.drawable.stat_sys_roaming_cdma_0,
- R.drawable.stat_sys_roaming_cdma_0 //83
+ R.drawable.stat_sys_roaming_cdma_0, //83
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0,
+ R.drawable.stat_sys_roaming_cdma_0 //239
- // 128-255 Reserved
+ // 240-255 Reserved
};
//***** Data connection icons
@@ -341,6 +498,25 @@ public class StatusBarPolicy {
private int mLastWifiSignalLevel = -1;
private boolean mIsWifiConnected = false;
+ //4G
+ private static final int[][] sWimaxSignalImages = {
+ { R.drawable.stat_sys_data_wimax_signal_0,
+ R.drawable.stat_sys_data_wimax_signal_1,
+ R.drawable.stat_sys_data_wimax_signal_2,
+ R.drawable.stat_sys_data_wimax_signal_3 },
+ { R.drawable.stat_sys_data_wimax_signal_0_fully,
+ R.drawable.stat_sys_data_wimax_signal_1_fully,
+ R.drawable.stat_sys_data_wimax_signal_2_fully,
+ R.drawable.stat_sys_data_wimax_signal_3_fully }
+ };
+ private static final int sWimaxDisconnectedImg =
+ R.drawable.stat_sys_data_wimax_signal_disconnected;
+ private static final int sWimaxIdleImg = R.drawable.stat_sys_data_wimax_signal_idle;
+ private boolean mIsWimaxConnected = false;
+ private boolean mIsWimaxEnabled = false;
+ private int mWimaxSignal = 0;
+ private int mWimaxState = 0;
+
// state of inet connection - 0 not connected, 100 connected
private int mInetCondition = 0;
@@ -398,6 +574,11 @@ public class StatusBarPolicy {
// TODO - stop using other means to get wifi/mobile info
updateConnectivity(intent);
}
+ else if (action.equals(WimaxManagerConstants.WIMAX_ENABLED_STATUS_CHANGED) ||
+ action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION) ||
+ action.equals(WimaxManagerConstants.WIMAX_STATE_CHANGED_ACTION)) {
+ updateWiMAX(intent);
+ }
}
};
@@ -438,6 +619,15 @@ public class StatusBarPolicy {
mService.setIconVisibility("wifi", false);
// wifi will get updated by the sticky intents
+ // wimax
+ //enable/disable wimax depending on the value in config.xml
+ boolean isWimaxEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_wimaxEnabled);
+ if (isWimaxEnabled) {
+ mService.setIcon("wimax", sWimaxDisconnectedImg, 0);
+ mService.setIconVisibility("wimax", false);
+ }
+
// TTY status
mService.setIcon("tty", R.drawable.stat_sys_tty_mode, 0);
mService.setIconVisibility("tty", false);
@@ -503,6 +693,10 @@ public class StatusBarPolicy {
filter.addAction(TtyIntent.TTY_ENABLED_CHANGE_ACTION);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
+ filter.addAction(WimaxManagerConstants.WIMAX_STATE_CHANGED_ACTION);
+ filter.addAction(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION);
+ filter.addAction(WimaxManagerConstants.WIMAX_ENABLED_STATUS_CHANGED);
+
mContext.registerReceiver(mIntentReceiver, filter, null, mHandler);
// load config to determine if to distinguish Hspa data icon
@@ -744,6 +938,16 @@ public class StatusBarPolicy {
}
updateSignalStrength(); // apply any change in mInetCondition
break;
+ case ConnectivityManager.TYPE_WIMAX:
+ mInetCondition = inetCondition;
+ if (info.isConnected()) {
+ mIsWimaxConnected = true;
+ mService.setIconVisibility("wimax", true);
+ } else {
+ mIsWimaxConnected = false;
+ }
+ updateWiMAX(intent);
+ break;
}
}
@@ -1124,6 +1328,48 @@ public class StatusBarPolicy {
}
}
+ private final void updateWiMAX(Intent intent) {
+ final String action = intent.getAction();
+ int iconId = sWimaxDisconnectedImg;
+
+ if (action.equals(WimaxManagerConstants. WIMAX_ENABLED_STATUS_CHANGED)) {
+ int mWimaxStatus = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATUS,
+ WimaxManagerConstants.WIMAX_STATUS_DISABLED);
+ switch(mWimaxStatus) {
+ case WimaxManagerConstants.WIMAX_STATUS_ENABLED:
+ mIsWimaxEnabled = true;
+ break;
+ case WimaxManagerConstants.WIMAX_STATUS_DISABLED:
+ mIsWimaxEnabled = false;
+ break;
+ }
+ } else if (action.equals(WimaxManagerConstants.SIGNAL_LEVEL_CHANGED_ACTION)) {
+ mWimaxSignal = intent.getIntExtra(WimaxManagerConstants.EXTRA_NEW_SIGNAL_LEVEL, 0);
+ } else if (action.equals(WimaxManagerConstants.WIMAX_STATE_CHANGED_ACTION)) {
+ mWimaxState = intent.getIntExtra(WimaxManagerConstants.EXTRA_WIMAX_STATE,
+ WimaxManagerConstants.WIMAX_STATE_UNKNOWN);
+ int mExtraWimaxState = intent.getIntExtra(
+ WimaxManagerConstants.EXTRA_WIMAX_STATE_DETAIL,
+ WimaxManagerConstants.WIMAX_DEREGISTRATION);
+
+ switch(mWimaxState) {
+ case WimaxManagerConstants.WIMAX_STATE_DISCONNECTED:
+ iconId = sWimaxDisconnectedImg;
+ break;
+ case WimaxManagerConstants.WIMAX_STATE_CONNECTED:
+ if(mExtraWimaxState == WimaxManagerConstants.WIMAX_IDLE) {
+ iconId = sWimaxIdleImg;
+ }
+ else {
+ iconId = sWimaxSignalImages[mInetCondition][mWimaxSignal];
+ }
+ break;
+ }
+ mService.setIcon("wimax", iconId, 0);
+ }
+ mService.setIconVisibility("wimax", mIsWimaxEnabled);
+ }
+
private final void updateGps(Intent intent) {
final String action = intent.getAction();
final boolean enabled = intent.getBooleanExtra(LocationManager.EXTRA_GPS_ENABLED, false);
@@ -1193,6 +1439,10 @@ public class StatusBarPolicy {
switch (iconMode) {
case EriInfo.ROAMING_ICON_MODE_NORMAL:
+ if (iconIndex >= iconList.length) {
+ Slog.e(TAG, "unknown iconIndex " + iconIndex + ", skipping ERI icon update");
+ return;
+ }
mService.setIcon("cdma_eri", iconList[iconIndex], 0);
mService.setIconVisibility("cdma_eri", true);
break;
@@ -1205,7 +1455,6 @@ public class StatusBarPolicy {
mService.setIcon("phone_signal", mPhoneSignalIconId, 0);
}
-
private class StatusBarHandler extends Handler {
@Override
public void handleMessage(Message msg) {
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
new file mode 100644
index 0000000..5007cf4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbAccessoryUriActivity.java
@@ -0,0 +1,100 @@
+/*
+ * 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.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ActivityNotFoundException;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.net.Uri;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.util.Log;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+/**
+ * If the attached USB accessory has a URL associated with it, and that URL is valid,
+ * show this dialog to the user to allow them to optionally visit that URL for more
+ * information or software downloads.
+ * Otherwise (no valid URL) this activity does nothing at all, finishing immediately.
+ */
+public class UsbAccessoryUriActivity extends AlertActivity
+ implements DialogInterface.OnClickListener {
+
+ private static final String TAG = "UsbAccessoryUriActivity";
+
+ private UsbAccessory mAccessory;
+ private Uri mUri;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Intent intent = getIntent();
+ mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ String uriString = intent.getStringExtra("uri");
+ mUri = (uriString == null ? null : Uri.parse(uriString));
+
+ // sanity check before displaying dialog
+ if (mUri == null) {
+ Log.e(TAG, "could not parse Uri " + uriString);
+ finish();
+ return;
+ }
+ String scheme = mUri.getScheme();
+ if (!"http".equals(scheme) && !"https".equals(scheme)) {
+ Log.e(TAG, "Uri not http or https: " + mUri);
+ finish();
+ return;
+ }
+
+ final AlertController.AlertParams ap = mAlertParams;
+ ap.mTitle = mAccessory.getDescription();
+ if (ap.mTitle == null || ap.mTitle.length() == 0) {
+ ap.mTitle = getString(R.string.title_usb_accessory);
+ }
+ ap.mMessage = getString(R.string.usb_accessory_uri_prompt, mUri);
+ ap.mPositiveButtonText = getString(R.string.label_view);
+ ap.mNegativeButtonText = getString(android.R.string.cancel);
+ ap.mPositiveButtonListener = this;
+ ap.mNegativeButtonListener = this;
+
+ setupAlert();
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ // launch the browser
+ Intent intent = new Intent(Intent.ACTION_VIEW, mUri);
+ intent.addCategory(Intent.CATEGORY_BROWSABLE);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "startActivity failed for " + mUri);
+ }
+ }
+ finish();
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
new file mode 100644
index 0000000..148bcb4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbConfirmActivity.java
@@ -0,0 +1,143 @@
+/*
+ * 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.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class UsbConfirmActivity extends AlertActivity
+ implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
+
+ private static final String TAG = "UsbConfirmActivity";
+
+ private CheckBox mAlwaysUse;
+ private TextView mClearDefaultHint;
+ private UsbAccessory mAccessory;
+ private ResolveInfo mResolveInfo;
+ private boolean mPermissionGranted;
+ private UsbDisconnectedReceiver mDisconnectedReceiver;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Intent intent = getIntent();
+ mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+ mResolveInfo = (ResolveInfo)intent.getParcelableExtra("rinfo");
+
+ PackageManager packageManager = getPackageManager();
+ String appName = mResolveInfo.loadLabel(packageManager).toString();
+
+ final AlertController.AlertParams ap = mAlertParams;
+ ap.mIcon = mResolveInfo.loadIcon(packageManager);
+ ap.mTitle = appName;
+ ap.mMessage = getString(R.string.usb_accessory_confirm_prompt, appName);
+ ap.mPositiveButtonText = getString(android.R.string.ok);
+ ap.mNegativeButtonText = getString(android.R.string.cancel);
+ ap.mPositiveButtonListener = this;
+ ap.mNegativeButtonListener = this;
+
+ // add "always use" checkbox
+ LayoutInflater inflater = (LayoutInflater)getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+ mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+ mAlwaysUse.setText(R.string.always_use_accessory);
+ mAlwaysUse.setOnCheckedChangeListener(this);
+ mClearDefaultHint = (TextView)ap.mView.findViewById(
+ com.android.internal.R.id.clearDefaultHint);
+ mClearDefaultHint.setVisibility(View.GONE);
+
+ setupAlert();
+
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mDisconnectedReceiver != null) {
+ unregisterReceiver(mDisconnectedReceiver);
+ }
+ super.onDestroy();
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ try {
+ IBinder b = ServiceManager.getService(USB_SERVICE);
+ IUsbManager service = IUsbManager.Stub.asInterface(b);
+ int uid = mResolveInfo.activityInfo.applicationInfo.uid;
+ boolean alwaysUse = mAlwaysUse.isChecked();
+ Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.setComponent(
+ new ComponentName(mResolveInfo.activityInfo.packageName,
+ mResolveInfo.activityInfo.name));
+
+ // grant permission for the accessory
+ service.grantAccessoryPermission(mAccessory, uid);
+ // set or clear default setting
+ if (alwaysUse) {
+ service.setAccessoryPackage(mAccessory,
+ mResolveInfo.activityInfo.packageName);
+ } else {
+ service.setAccessoryPackage(mAccessory, null);
+ }
+ startActivity(intent);
+ } catch (Exception e) {
+ Log.e(TAG, "Unable to start activity", e);
+ }
+ }
+ finish();
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mClearDefaultHint == null) return;
+
+ if(isChecked) {
+ mClearDefaultHint.setVisibility(View.VISIBLE);
+ } else {
+ mClearDefaultHint.setVisibility(View.GONE);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java b/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java
new file mode 100644
index 0000000..4fa3ad0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbDisconnectedReceiver.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import android.app.Activity;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+
+// This class is used to close UsbPermissionsActivity and UsbResolverActivity
+// if their accessory is disconnected while the dialog is still open
+class UsbDisconnectedReceiver extends BroadcastReceiver {
+ private final Activity mActivity;
+ private UsbAccessory mAccessory;
+
+ public UsbDisconnectedReceiver(Activity activity, UsbAccessory accessory) {
+ mActivity = activity;
+ mAccessory = accessory;
+
+ IntentFilter filter = new IntentFilter(UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+ activity.registerReceiver(this, filter);
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ String action = intent.getAction();
+ if (UsbManager.ACTION_USB_ACCESSORY_DETACHED.equals(action)) {
+ UsbAccessory accessory =
+ (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ if (accessory != null && accessory.equals(mAccessory)) {
+ mActivity.finish();
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
new file mode 100644
index 0000000..ec7c13a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbPermissionActivity.java
@@ -0,0 +1,153 @@
+/*
+ * 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.systemui.usb;
+
+import android.app.Activity;
+import android.app.AlertDialog;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.CompoundButton;
+import android.widget.TextView;
+
+import com.android.internal.app.AlertActivity;
+import com.android.internal.app.AlertController;
+
+import com.android.systemui.R;
+
+public class UsbPermissionActivity extends AlertActivity
+ implements DialogInterface.OnClickListener, CheckBox.OnCheckedChangeListener {
+
+ private static final String TAG = "UsbPermissionActivity";
+
+ private CheckBox mAlwaysUse;
+ private TextView mClearDefaultHint;
+ private UsbAccessory mAccessory;
+ private PendingIntent mPendingIntent;
+ private String mPackageName;
+ private int mUid;
+ private boolean mPermissionGranted;
+ private UsbDisconnectedReceiver mDisconnectedReceiver;
+
+ @Override
+ public void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+
+ Intent intent = getIntent();
+ mAccessory = (UsbAccessory)intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+ mPendingIntent = (PendingIntent)intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ mUid = intent.getIntExtra("uid", 0);
+ mPackageName = intent.getStringExtra("package");
+
+ PackageManager packageManager = getPackageManager();
+ ApplicationInfo aInfo;
+ try {
+ aInfo = packageManager.getApplicationInfo(mPackageName, 0);
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "unable to look up package name", e);
+ finish();
+ return;
+ }
+ String appName = aInfo.loadLabel(packageManager).toString();
+
+ final AlertController.AlertParams ap = mAlertParams;
+ ap.mIcon = aInfo.loadIcon(packageManager);
+ ap.mTitle = appName;
+ ap.mMessage = getString(R.string.usb_accessory_permission_prompt, appName);
+ ap.mPositiveButtonText = getString(android.R.string.ok);
+ ap.mNegativeButtonText = getString(android.R.string.cancel);
+ ap.mPositiveButtonListener = this;
+ ap.mNegativeButtonListener = this;
+
+ // add "always use" checkbox
+ LayoutInflater inflater = (LayoutInflater)getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+ ap.mView = inflater.inflate(com.android.internal.R.layout.always_use_checkbox, null);
+ mAlwaysUse = (CheckBox)ap.mView.findViewById(com.android.internal.R.id.alwaysUse);
+ mAlwaysUse.setText(R.string.always_use_accessory);
+ mAlwaysUse.setOnCheckedChangeListener(this);
+ mClearDefaultHint = (TextView)ap.mView.findViewById(
+ com.android.internal.R.id.clearDefaultHint);
+ mClearDefaultHint.setVisibility(View.GONE);
+
+ setupAlert();
+
+ }
+
+ @Override
+ public void onDestroy() {
+ IBinder b = ServiceManager.getService(USB_SERVICE);
+ IUsbManager service = IUsbManager.Stub.asInterface(b);
+
+ // send response via pending intent
+ Intent intent = new Intent();
+ try {
+ if (mAccessory != null) {
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, mAccessory);
+ if (mPermissionGranted) {
+ service.grantAccessoryPermission(mAccessory, mUid);
+ if (mAlwaysUse.isChecked()) {
+ service.setAccessoryPackage(mAccessory, mPackageName);
+ }
+ }
+ }
+ intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, mPermissionGranted);
+ mPendingIntent.send(this, 0, intent);
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "PendingIntent was cancelled");
+ } catch (RemoteException e) {
+ Log.e(TAG, "IUsbService connection failed", e);
+ }
+
+ if (mDisconnectedReceiver != null) {
+ unregisterReceiver(mDisconnectedReceiver);
+ }
+ super.onDestroy();
+ }
+
+ public void onClick(DialogInterface dialog, int which) {
+ if (which == AlertDialog.BUTTON_POSITIVE) {
+ mPermissionGranted = true;
+ }
+ finish();
+ }
+
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if (mClearDefaultHint == null) return;
+
+ if(isChecked) {
+ mClearDefaultHint.setVisibility(View.VISIBLE);
+ } else {
+ mClearDefaultHint.setVisibility(View.GONE);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
new file mode 100644
index 0000000..082c839
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbResolverActivity.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.usb;
+
+import com.android.internal.app.ResolverActivity;
+
+import android.content.ActivityNotFoundException;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.os.ServiceManager;
+import android.util.Log;
+import android.widget.CheckBox;
+
+import com.android.systemui.R;
+
+import java.util.ArrayList;
+
+/* Activity for choosing an application for a USB device or accessory */
+public class UsbResolverActivity extends ResolverActivity {
+ public static final String TAG = "UsbResolverActivity";
+ public static final String EXTRA_RESOLVE_INFOS = "rlist";
+
+ private UsbAccessory mAccessory;
+ private UsbDisconnectedReceiver mDisconnectedReceiver;
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ Intent intent = getIntent();
+ Parcelable targetParcelable = intent.getParcelableExtra(Intent.EXTRA_INTENT);
+ if (!(targetParcelable instanceof Intent)) {
+ Log.w("UsbResolverActivity", "Target is not an intent: " + targetParcelable);
+ finish();
+ return;
+ }
+ Intent target = (Intent)targetParcelable;
+ ArrayList<ResolveInfo> rList = intent.getParcelableArrayListExtra(EXTRA_RESOLVE_INFOS);
+ CharSequence title = getResources().getText(com.android.internal.R.string.chooseUsbActivity);
+ super.onCreate(savedInstanceState, target, title, null, rList,
+ true /* Set alwaysUseOption to true to enable "always use this app" checkbox. */ );
+
+ CheckBox alwaysUse = (CheckBox)findViewById(com.android.internal.R.id.alwaysUse);
+ if (alwaysUse != null) {
+ alwaysUse.setText(R.string.always_use_accessory);
+ }
+
+ mAccessory = (UsbAccessory)target.getParcelableExtra(UsbManager.EXTRA_ACCESSORY);
+ if (mAccessory == null) {
+ Log.e(TAG, "accessory is null");
+ finish();
+ return;
+ }
+ mDisconnectedReceiver = new UsbDisconnectedReceiver(this, mAccessory);
+ }
+
+ @Override
+ protected void onDestroy() {
+ if (mDisconnectedReceiver != null) {
+ unregisterReceiver(mDisconnectedReceiver);
+ }
+ super.onDestroy();
+ }
+
+ protected void onIntentSelected(ResolveInfo ri, Intent intent, boolean alwaysCheck) {
+ try {
+ IBinder b = ServiceManager.getService(USB_SERVICE);
+ IUsbManager service = IUsbManager.Stub.asInterface(b);
+ int uid = ri.activityInfo.applicationInfo.uid;
+
+ // grant permission for the accessory
+ service.grantAccessoryPermission(mAccessory, uid);
+ // set or clear default setting
+ if (alwaysCheck) {
+ service.setAccessoryPackage(mAccessory, ri.activityInfo.packageName);
+ } else {
+ service.setAccessoryPackage(mAccessory, null);
+ }
+
+ try {
+ startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "startActivity failed", e);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "onIntentSelected failed", e);
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
index 5c52783..43dfb96 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
@@ -30,7 +30,7 @@ import android.content.DialogInterface.OnCancelListener;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
-import android.hardware.Usb;
+import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
@@ -83,7 +83,7 @@ public class UsbStorageActivity extends Activity
private BroadcastReceiver mUsbStateReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if (intent.getAction().equals(Usb.ACTION_USB_STATE)) {
+ if (intent.getAction().equals(UsbManager.ACTION_USB_STATE)) {
handleUsbStateChanged(intent);
}
}
@@ -175,7 +175,7 @@ public class UsbStorageActivity extends Activity
super.onResume();
mStorageManager.registerListener(mStorageListener);
- registerReceiver(mUsbStateReceiver, new IntentFilter(Usb.ACTION_USB_STATE));
+ registerReceiver(mUsbStateReceiver, new IntentFilter(UsbManager.ACTION_USB_STATE));
try {
mAsyncStorageHandler.post(new Runnable() {
@Override
@@ -199,7 +199,7 @@ public class UsbStorageActivity extends Activity
}
private void handleUsbStateChanged(Intent intent) {
- boolean connected = intent.getExtras().getBoolean(Usb.USB_CONNECTED);
+ boolean connected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
if (!connected) {
// It was disconnected from the plug, so finish
finish();
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 5e33f05..dee275c 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -316,9 +316,10 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
filteredPos++;
}
- throw new IllegalArgumentException("position " + position + " out of "
- + "range of showable actions, filtered count = "
- + "= " + getCount() + ", keyguardshowing=" + mKeyguardShowing
+ throw new IllegalArgumentException("position " + position
+ + " out of range of showable actions"
+ + ", filtered count=" + getCount()
+ + ", keyguardshowing=" + mKeyguardShowing
+ ", provisioned=" + mDeviceProvisioned);
}
diff --git a/services/audioflinger/AudioResampler.cpp b/services/audioflinger/AudioResampler.cpp
index 5dabacb..245bfdf 100644
--- a/services/audioflinger/AudioResampler.cpp
+++ b/services/audioflinger/AudioResampler.cpp
@@ -26,11 +26,15 @@
#include "AudioResamplerSinc.h"
#include "AudioResamplerCubic.h"
+#ifdef __arm__
+#include <machine/cpu-features.h>
+#endif
+
namespace android {
-#ifdef __ARM_ARCH_5E__ // optimized asm option
+#ifdef __ARM_HAVE_HALFWORD_MULTIPLY // optimized asm option
#define ASM_ARM_RESAMP1 // enable asm optimisation for ResamplerOrder1
-#endif // __ARM_ARCH_5E__
+#endif // __ARM_HAVE_HALFWORD_MULTIPLY
// ----------------------------------------------------------------------------
class AudioResamplerOrder1 : public AudioResampler {
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index 8560d16..555975f 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -18,10 +18,13 @@ package com.android.server;
import android.app.Notification;
import android.app.NotificationManager;
-import android.content.ContentResolver;
import android.content.Context;
+import android.content.ContentResolver;
+import android.content.ContextWrapper;
import android.content.Intent;
import android.content.pm.PackageManager;
+import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
import android.net.ConnectivityManager;
import android.net.IConnectivityManager;
import android.net.MobileDataStateTracker;
@@ -29,6 +32,7 @@ import android.net.NetworkInfo;
import android.net.NetworkStateTracker;
import android.net.NetworkUtils;
import android.net.wifi.WifiStateTracker;
+import android.net.wimax.WimaxManagerConstants;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
@@ -41,19 +45,23 @@ import android.provider.Settings;
import android.text.TextUtils;
import android.util.EventLog;
import android.util.Slog;
-
import com.android.internal.telephony.Phone;
-
import com.android.server.connectivity.Tethering;
-
+import dalvik.system.DexClassLoader;
import java.io.FileDescriptor;
import java.io.PrintWriter;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.GregorianCalendar;
import java.util.List;
import java.net.InetAddress;
import java.net.UnknownHostException;
+
+
/**
* @hide
*/
@@ -103,7 +111,6 @@ public class ConnectivityService extends IConnectivityManager.Stub {
private boolean mTestMode;
private static ConnectivityService sServiceInstance;
-
private static final int ENABLED = 1;
private static final int DISABLED = 0;
@@ -381,6 +388,17 @@ public class ConnectivityService extends IConnectivityManager.Stub {
mNetTrackers[netType].teardown();
}
break;
+ case ConnectivityManager.TYPE_WIMAX:
+ NetworkStateTracker nst = makeWimaxStateTracker();
+ if (nst != null) {
+ nst.startMonitoring();
+ }
+ mNetTrackers[netType] = nst;
+ if (noMobileData) {
+ if (DBG) Slog.d(TAG, "tearing down WiMAX networks due to setting");
+ mNetTrackers[netType].teardown();
+ }
+ break;
default:
Slog.e(TAG, "Trying to create a DataStateTracker for an unknown radio type " +
mNetAttributes[netType].mRadio);
@@ -400,6 +418,94 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
}
+ private NetworkStateTracker makeWimaxStateTracker() {
+ //Initialize Wimax
+ DexClassLoader wimaxClassLoader;
+ Class wimaxStateTrackerClass = null;
+ Class wimaxServiceClass = null;
+ Class wimaxManagerClass;
+ String wimaxJarLocation;
+ String wimaxLibLocation;
+ String wimaxManagerClassName;
+ String wimaxServiceClassName;
+ String wimaxStateTrackerClassName;
+
+ NetworkStateTracker wimaxStateTracker = null;
+
+ boolean isWimaxEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_wimaxEnabled);
+
+ if (isWimaxEnabled) {
+ try {
+ wimaxJarLocation = mContext.getResources().getString(
+ com.android.internal.R.string.config_wimaxServiceJarLocation);
+ wimaxLibLocation = mContext.getResources().getString(
+ com.android.internal.R.string.config_wimaxNativeLibLocation);
+ wimaxManagerClassName = mContext.getResources().getString(
+ com.android.internal.R.string.config_wimaxManagerClassname);
+ wimaxServiceClassName = mContext.getResources().getString(
+ com.android.internal.R.string.config_wimaxServiceClassname);
+ wimaxStateTrackerClassName = mContext.getResources().getString(
+ com.android.internal.R.string.config_wimaxStateTrackerClassname);
+
+ wimaxClassLoader = new DexClassLoader(wimaxJarLocation,
+ new ContextWrapper(mContext).getCacheDir().getAbsolutePath(),
+ wimaxLibLocation,ClassLoader.getSystemClassLoader());
+
+ try {
+ wimaxManagerClass = wimaxClassLoader.loadClass(wimaxManagerClassName);
+ wimaxStateTrackerClass = wimaxClassLoader.loadClass(wimaxStateTrackerClassName);
+ wimaxServiceClass = wimaxClassLoader.loadClass(wimaxServiceClassName);
+ } catch (ClassNotFoundException ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ } catch(Resources.NotFoundException ex) {
+ Slog.e(TAG, "Wimax Resources does not exist!!! ");
+ return null;
+ }
+
+ try {
+ Slog.v(TAG, "Starting Wimax Service... ");
+
+ Constructor wmxStTrkrConst = wimaxStateTrackerClass.getConstructor
+ (new Class[] {Context.class,Handler.class});
+ wimaxStateTracker = (NetworkStateTracker)wmxStTrkrConst.newInstance(mContext,mHandler);
+
+ Constructor wmxSrvConst = wimaxServiceClass.getDeclaredConstructor
+ (new Class[] {Context.class,wimaxStateTrackerClass});
+ wmxSrvConst.setAccessible(true);
+ IBinder svcInvoker = (IBinder) wmxSrvConst.newInstance(mContext,wimaxStateTracker);
+ wmxSrvConst.setAccessible(false);
+
+ ServiceManager.addService(WimaxManagerConstants.WIMAX_SERVICE, svcInvoker);
+
+ } catch(ClassCastException ex) {
+ ex.printStackTrace();
+ return null;
+ } catch (NoSuchMethodException ex) {
+ ex.printStackTrace();
+ return null;
+ } catch (InstantiationException ex) {
+ ex.printStackTrace();
+ return null;
+ } catch(IllegalAccessException ex) {
+ ex.printStackTrace();
+ return null;
+ } catch(InvocationTargetException ex) {
+ ex.printStackTrace();
+ return null;
+ } catch(Exception ex) {
+ ex.printStackTrace();
+ return null;
+ }
+ } else {
+ Slog.e(TAG, "Wimax is not enabled or not added to the network attributes!!! ");
+ return null;
+ }
+
+ return wimaxStateTracker;
+ }
/**
* Sets the preferred network.
@@ -492,18 +598,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
*/
public NetworkInfo getActiveNetworkInfo() {
enforceAccessPermission();
- for (int type=0; type <= ConnectivityManager.MAX_NETWORK_TYPE; type++) {
- if (mNetAttributes[type] == null || !mNetAttributes[type].isDefault()) {
- continue;
- }
- NetworkStateTracker t = mNetTrackers[type];
- NetworkInfo info = t.getNetworkInfo();
- if (info.isConnected()) {
- if (DBG && type != mActiveDefaultNetwork) Slog.e(TAG,
- "connected default network is not " +
- "mActiveDefaultNetwork!");
- return info;
- }
+ if (mActiveDefaultNetwork != -1) {
+ return mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
}
return null;
}
@@ -926,6 +1022,12 @@ public class ConnectivityService extends IConnectivityManager.Stub {
}
mNetTrackers[ConnectivityManager.TYPE_MOBILE].reconnect();
}
+ if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {
+ if (DBG) {
+ Slog.d(TAG, "starting up " + mNetTrackers[ConnectivityManager.TYPE_WIMAX]);
+ }
+ mNetTrackers[ConnectivityManager.TYPE_WIMAX].reconnect();
+ }
} else {
for (NetworkStateTracker nt : mNetTrackers) {
if (nt == null) continue;
@@ -935,6 +1037,9 @@ public class ConnectivityService extends IConnectivityManager.Stub {
nt.teardown();
}
}
+ if (mNetTrackers[ConnectivityManager.TYPE_WIMAX] != null) {
+ mNetTrackers[ConnectivityManager.TYPE_WIMAX].teardown();
+ }
}
}
@@ -1018,18 +1123,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
info.getExtraInfo());
}
- NetworkStateTracker newNet = null;
if (mNetAttributes[prevNetType].isDefault()) {
- newNet = tryFailover(prevNetType);
- if (newNet != null) {
- NetworkInfo switchTo = newNet.getNetworkInfo();
- if (!switchTo.isConnected()) {
- // if the other net is connected they've already reset this and perhaps even gotten
- // a positive report we don't want to overwrite, but if not we need to clear this now
- // to turn our cellular sig strength white
- mDefaultInetConditionPublished = 0;
- intent.putExtra(ConnectivityManager.EXTRA_NO_CONNECTIVITY, true);
- }
+ tryFailover(prevNetType);
+ if (mActiveDefaultNetwork != -1) {
+ NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
} else {
mDefaultInetConditionPublished = 0; // we're not connected anymore
@@ -1045,86 +1142,47 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* If the failover network is already connected, then immediately send
* out a followup broadcast indicating successful failover
*/
- if (newNet != null && newNet.getNetworkInfo().isConnected()) {
- sendConnectedBroadcast(newNet.getNetworkInfo());
+ if (mActiveDefaultNetwork != -1) {
+ sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
}
}
- // returns null if no failover available
- private NetworkStateTracker tryFailover(int prevNetType) {
+ private void tryFailover(int prevNetType) {
/*
* If this is a default network, check if other defaults are available
* or active
*/
- NetworkStateTracker newNet = null;
if (mNetAttributes[prevNetType].isDefault()) {
if (mActiveDefaultNetwork == prevNetType) {
mActiveDefaultNetwork = -1;
}
- int newType = -1;
- int newPriority = -1;
boolean noMobileData = !getMobileDataEnabled();
for (int checkType=0; checkType <= ConnectivityManager.MAX_NETWORK_TYPE; checkType++) {
if (checkType == prevNetType) continue;
if (mNetAttributes[checkType] == null) continue;
+ if (mNetAttributes[checkType].isDefault() == false) continue;
if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_MOBILE &&
noMobileData) {
Slog.e(TAG, "not failing over to mobile type " + checkType +
" because Mobile Data Disabled");
continue;
}
- if (mNetAttributes[checkType].isDefault()) {
- /* TODO - if we have multiple nets we could use
- * we may want to put more thought into which we choose
- */
- if (checkType == mNetworkPreference) {
- newType = checkType;
- break;
- }
- if (mNetAttributes[checkType].mPriority > newPriority) {
- newType = checkType;
- newPriority = mNetAttributes[newType].mPriority;
- }
+ if (mNetAttributes[checkType].mRadio == ConnectivityManager.TYPE_WIMAX &&
+ noMobileData) {
+ Slog.e(TAG, "not failing over to mobile type " + checkType +
+ " because Mobile Data Disabled");
+ continue;
}
- }
-
- if (newType != -1) {
- newNet = mNetTrackers[newType];
- /**
- * See if the other network is available to fail over to.
- * If is not available, we enable it anyway, so that it
- * will be able to connect when it does become available,
- * but we report a total loss of connectivity rather than
- * report that we are attempting to fail over.
- */
- if (newNet.isAvailable()) {
- NetworkInfo switchTo = newNet.getNetworkInfo();
- switchTo.setFailover(true);
- if (!switchTo.isConnectedOrConnecting() ||
- newNet.isTeardownRequested()) {
- newNet.reconnect();
- }
- if (DBG) {
- if (switchTo.isConnected()) {
- Slog.v(TAG, "Switching to already connected " +
- switchTo.getTypeName());
- } else {
- Slog.v(TAG, "Attempting to switch to " +
- switchTo.getTypeName());
- }
- }
- } else {
- newNet.reconnect();
- newNet = null; // not officially avail.. try anyway, but
- // report no failover
+ NetworkStateTracker checkTracker = mNetTrackers[checkType];
+ NetworkInfo checkInfo = checkTracker.getNetworkInfo();
+ if (!checkInfo.isConnectedOrConnecting() || checkTracker.isTeardownRequested()) {
+ checkInfo.setFailover(true);
+ checkTracker.reconnect();
}
- } else {
- Slog.e(TAG, "Network failover failing.");
+ if (DBG) Slog.d(TAG, "Attempting to switch to " + checkInfo.getTypeName());
}
}
-
- return newNet;
}
private void sendConnectedBroadcast(NetworkInfo info) {
@@ -1187,17 +1245,10 @@ public class ConnectivityService extends IConnectivityManager.Stub {
info.setFailover(false);
}
- NetworkStateTracker newNet = null;
if (mNetAttributes[info.getType()].isDefault()) {
- newNet = tryFailover(info.getType());
- if (newNet != null) {
- NetworkInfo switchTo = newNet.getNetworkInfo();
- if (!switchTo.isConnected()) {
- // if the other net is connected they've already reset this and perhaps
- // even gotten a positive report we don't want to overwrite, but if not
- // we need to clear this now to turn our cellular sig strength white
- mDefaultInetConditionPublished = 0;
- }
+ tryFailover(info.getType());
+ if (mActiveDefaultNetwork != -1) {
+ NetworkInfo switchTo = mNetTrackers[mActiveDefaultNetwork].getNetworkInfo();
intent.putExtra(ConnectivityManager.EXTRA_OTHER_NETWORK_INFO, switchTo);
} else {
mDefaultInetConditionPublished = 0;
@@ -1211,8 +1262,8 @@ public class ConnectivityService extends IConnectivityManager.Stub {
* If the failover network is already connected, then immediately send
* out a followup broadcast indicating successful failover
*/
- if (newNet != null && newNet.getNetworkInfo().isConnected()) {
- sendConnectedBroadcast(newNet.getNetworkInfo());
+ if (mActiveDefaultNetwork != -1) {
+ sendConnectedBroadcast(mNetTrackers[mActiveDefaultNetwork].getNetworkInfo());
}
}
@@ -1265,6 +1316,7 @@ public class ConnectivityService extends IConnectivityManager.Stub {
" teardown");
if (!teardown(otherNet)) {
Slog.e(TAG, "Network declined teardown request");
+ teardown(thisNet);
return;
}
if (isFailover) {
@@ -1327,6 +1379,15 @@ public class ConnectivityService extends IConnectivityManager.Stub {
if (mNetAttributes[netType].isDefault()) {
mNetTrackers[netType].addDefaultRoute();
} else {
+ // many radios add a default route even when we don't want one.
+ // remove the default interface unless we need it for our active network
+ if (mActiveDefaultNetwork != -1) {
+ String defaultIface = mNetTrackers[mActiveDefaultNetwork].getInterfaceName();
+ if (defaultIface != null &&
+ !defaultIface.equals(mNetTrackers[netType].getInterfaceName())) {
+ mNetTrackers[netType].removeDefaultRoute();
+ }
+ }
mNetTrackers[netType].addPrivateDnsRoutes();
}
} else {
diff --git a/services/java/com/android/server/NotificationManagerService.java b/services/java/com/android/server/NotificationManagerService.java
index 4da5eb2..540389e 100755
--- a/services/java/com/android/server/NotificationManagerService.java
+++ b/services/java/com/android/server/NotificationManagerService.java
@@ -38,7 +38,7 @@ import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.hardware.Usb;
+import android.hardware.usb.UsbManager;
import android.media.AudioManager;
import android.net.Uri;
import android.os.BatteryManager;
@@ -352,14 +352,12 @@ public class NotificationManagerService extends INotificationManager.Stub
mBatteryFull = batteryFull;
updateLights();
}
- } else if (action.equals(Usb.ACTION_USB_STATE)) {
+ } else if (action.equals(UsbManager.ACTION_USB_STATE)) {
Bundle extras = intent.getExtras();
- boolean usbConnected = extras.getBoolean(Usb.USB_CONNECTED);
- boolean adbEnabled = (Usb.USB_FUNCTION_ENABLED.equals(
- extras.getString(Usb.USB_FUNCTION_ADB)));
+ boolean usbConnected = extras.getBoolean(UsbManager.USB_CONNECTED);
+ boolean adbEnabled = (UsbManager.USB_FUNCTION_ENABLED.equals(
+ extras.getString(UsbManager.USB_FUNCTION_ADB)));
updateAdbNotification(usbConnected && adbEnabled);
- } else if (action.equals(Usb.ACTION_USB_DISCONNECTED)) {
- updateAdbNotification(false);
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)
|| action.equals(Intent.ACTION_PACKAGE_RESTARTED)
|| (queryRestart=action.equals(Intent.ACTION_QUERY_PACKAGE_RESTART))
@@ -475,7 +473,7 @@ public class NotificationManagerService extends INotificationManager.Stub
// register for battery changed notifications
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_BATTERY_CHANGED);
- filter.addAction(Usb.ACTION_USB_STATE);
+ filter.addAction(UsbManager.ACTION_USB_STATE);
filter.addAction(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
filter.addAction(TelephonyManager.ACTION_PHONE_STATE_CHANGED);
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index df69b76..0f03f75 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -17,6 +17,7 @@
package com.android.server;
import com.android.server.am.ActivityManagerService;
+import com.android.server.usb.UsbService;
import com.android.internal.app.ShutdownThread;
import com.android.internal.os.BinderInternal;
import com.android.internal.os.SamplingProfilerIntegration;
@@ -122,7 +123,7 @@ class ServerThread extends Thread {
BluetoothA2dpService bluetoothA2dp = null;
HeadsetObserver headset = null;
DockObserver dock = null;
- UsbObserver usb = null;
+ UsbService usb = null;
UiModeManagerService uiMode = null;
RecognitionManagerService recognition = null;
ThrottleService throttle = null;
@@ -397,11 +398,12 @@ class ServerThread extends Thread {
}
try {
- Slog.i(TAG, "USB Observer");
+ Slog.i(TAG, "USB Service");
// Listen for USB changes
- usb = new UsbObserver(context);
+ usb = new UsbService(context);
+ ServiceManager.addService(Context.USB_SERVICE, usb);
} catch (Throwable e) {
- Slog.e(TAG, "Failure starting UsbObserver", e);
+ Slog.e(TAG, "Failure starting UsbService", e);
}
try {
@@ -493,7 +495,7 @@ class ServerThread extends Thread {
final BatteryService batteryF = battery;
final ConnectivityService connectivityF = connectivity;
final DockObserver dockF = dock;
- final UsbObserver usbF = usb;
+ final UsbService usbF = usb;
final ThrottleService throttleF = throttle;
final UiModeManagerService uiModeF = uiMode;
final AppWidgetService appWidgetF = appWidget;
diff --git a/services/java/com/android/server/UsbObserver.java b/services/java/com/android/server/UsbObserver.java
deleted file mode 100644
index d08fe9b..0000000
--- a/services/java/com/android/server/UsbObserver.java
+++ /dev/null
@@ -1,207 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.ContentResolver;
-import android.content.Context;
-import android.content.Intent;
-import android.hardware.Usb;
-import android.net.Uri;
-import android.os.Handler;
-import android.os.Message;
-import android.os.UEventObserver;
-import android.provider.Settings;
-import android.util.Log;
-import android.util.Slog;
-
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileReader;
-import java.util.ArrayList;
-
-/**
- * <p>UsbObserver monitors for changes to USB state.
- */
-class UsbObserver extends UEventObserver {
- private static final String TAG = UsbObserver.class.getSimpleName();
- private static final boolean LOG = false;
-
- private static final String USB_CONFIGURATION_MATCH = "DEVPATH=/devices/virtual/switch/usb_configuration";
- private static final String USB_FUNCTIONS_MATCH = "DEVPATH=/devices/virtual/usb_composite/";
- private static final String USB_CONFIGURATION_PATH = "/sys/class/switch/usb_configuration/state";
- private static final String USB_COMPOSITE_CLASS_PATH = "/sys/class/usb_composite";
-
- private static final int MSG_UPDATE = 0;
-
- private int mUsbConfig = 0;
- private int mPreviousUsbConfig = 0;
-
- // lists of enabled and disabled USB functions
- private final ArrayList<String> mEnabledFunctions = new ArrayList<String>();
- private final ArrayList<String> mDisabledFunctions = new ArrayList<String>();
-
- private boolean mSystemReady;
-
- private final Context mContext;
-
- private PowerManagerService mPowerManager;
-
- public UsbObserver(Context context) {
- mContext = context;
- init(); // set initial status
-
- startObserving(USB_CONFIGURATION_MATCH);
- startObserving(USB_FUNCTIONS_MATCH);
- }
-
- @Override
- public void onUEvent(UEventObserver.UEvent event) {
- if (Log.isLoggable(TAG, Log.VERBOSE)) {
- Slog.v(TAG, "USB UEVENT: " + event.toString());
- }
-
- synchronized (this) {
- String switchState = event.get("SWITCH_STATE");
- if (switchState != null) {
- try {
- int newConfig = Integer.parseInt(switchState);
- if (newConfig != mUsbConfig) {
- mPreviousUsbConfig = mUsbConfig;
- mUsbConfig = newConfig;
- // trigger an Intent broadcast
- if (mSystemReady) {
- update();
- }
- }
- } catch (NumberFormatException e) {
- Slog.e(TAG, "Could not parse switch state from event " + event);
- }
- } else {
- String function = event.get("FUNCTION");
- String enabledStr = event.get("ENABLED");
- if (function != null && enabledStr != null) {
- // Note: we do not broadcast a change when a function is enabled or disabled.
- // We just record the state change for the next broadcast.
- boolean enabled = "1".equals(enabledStr);
- if (enabled) {
- if (!mEnabledFunctions.contains(function)) {
- mEnabledFunctions.add(function);
- }
- mDisabledFunctions.remove(function);
- } else {
- if (!mDisabledFunctions.contains(function)) {
- mDisabledFunctions.add(function);
- }
- mEnabledFunctions.remove(function);
- }
- }
- }
- }
- }
- private final void init() {
- char[] buffer = new char[1024];
-
- try {
- FileReader file = new FileReader(USB_CONFIGURATION_PATH);
- int len = file.read(buffer, 0, 1024);
- mPreviousUsbConfig = mUsbConfig = Integer.valueOf((new String(buffer, 0, len)).trim());
-
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "This kernel does not have USB configuration switch support");
- } catch (Exception e) {
- Slog.e(TAG, "" , e);
- }
-
- try {
- File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles();
- for (int i = 0; i < files.length; i++) {
- File file = new File(files[i], "enable");
- FileReader reader = new FileReader(file);
- int len = reader.read(buffer, 0, 1024);
- int value = Integer.valueOf((new String(buffer, 0, len)).trim());
- String functionName = files[i].getName();
- if (value == 1) {
- mEnabledFunctions.add(functionName);
- } else {
- mDisabledFunctions.add(functionName);
- }
- }
- } catch (FileNotFoundException e) {
- Slog.w(TAG, "This kernel does not have USB composite class support");
- } catch (Exception e) {
- Slog.e(TAG, "" , e);
- }
- }
-
- void systemReady() {
- synchronized (this) {
- update();
- mSystemReady = true;
- }
- }
-
- private final void update() {
- mHandler.sendEmptyMessage(MSG_UPDATE);
- }
-
- private final Handler mHandler = new Handler() {
- private void addEnabledFunctions(Intent intent) {
- // include state of all USB functions in our extras
- for (int i = 0; i < mEnabledFunctions.size(); i++) {
- intent.putExtra(mEnabledFunctions.get(i), Usb.USB_FUNCTION_ENABLED);
- }
- for (int i = 0; i < mDisabledFunctions.size(); i++) {
- intent.putExtra(mDisabledFunctions.get(i), Usb.USB_FUNCTION_DISABLED);
- }
- }
-
- @Override
- public void handleMessage(Message msg) {
- switch (msg.what) {
- case MSG_UPDATE:
- synchronized (this) {
- final ContentResolver cr = mContext.getContentResolver();
-
- if (Settings.Secure.getInt(cr,
- Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
- Slog.i(TAG, "Device not provisioned, skipping USB broadcast");
- return;
- }
- // Send an Intent containing connected/disconnected state
- // and the enabled/disabled state of all USB functions
- Intent intent;
- boolean usbConnected = (mUsbConfig != 0);
- if (usbConnected) {
- intent = new Intent(Usb.ACTION_USB_CONNECTED);
- addEnabledFunctions(intent);
- } else {
- intent = new Intent(Usb.ACTION_USB_DISCONNECTED);
- }
- mContext.sendBroadcast(intent);
-
- // send a sticky broadcast for clients interested in both connect and disconnect
- intent = new Intent(Usb.ACTION_USB_STATE);
- intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
- intent.putExtra(Usb.USB_CONNECTED, usbConnected);
- addEnabledFunctions(intent);
- mContext.sendStickyBroadcast(intent);
- }
- break;
- }
- }
- };
-}
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 667b544..26cf55f 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -929,6 +929,10 @@ public class WindowManagerService extends IWindowManager.Stub
&& w.mAttrs.type == WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
&& i > 0) {
WindowState wb = localmWindows.get(i-1);
+ while (i > 1 && wb.mAppToken == w.mAppToken && !canBeImeTarget(wb)) {
+ i--;
+ wb = localmWindows.get(i-1);
+ }
if (wb.mAppToken == w.mAppToken && canBeImeTarget(wb)) {
i--;
w = wb;
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 0e38e10..d24ce7e 100755..100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -6694,8 +6694,9 @@ public final class ActivityManagerService extends ActivityManagerNative
addErrorToDropBox("wtf", r, null, null, tag, null, null, crashInfo);
- if (Settings.Secure.getInt(mContext.getContentResolver(),
- Settings.Secure.WTF_IS_FATAL, 0) != 0) {
+ if (r != null && r.pid != Process.myPid() &&
+ Settings.Secure.getInt(mContext.getContentResolver(),
+ Settings.Secure.WTF_IS_FATAL, 0) != 0) {
crashApplication(r, crashInfo);
return true;
} else {
@@ -6733,18 +6734,25 @@ public final class ActivityManagerService extends ActivityManagerNative
* to append various headers to the dropbox log text.
*/
private void appendDropBoxProcessHeaders(ProcessRecord process, StringBuilder sb) {
+ // Watchdog thread ends up invoking this function (with
+ // a null ProcessRecord) to add the stack file to dropbox.
+ // Do not acquire a lock on this (am) in such cases, as it
+ // could cause a potential deadlock, if and when watchdog
+ // is invoked due to unavailability of lock on am and it
+ // would prevent watchdog from killing system_server.
+ if (process == null) {
+ sb.append("Process: system_server\n");
+ return;
+ }
// Note: ProcessRecord 'process' is guarded by the service
// instance. (notably process.pkgList, which could otherwise change
// concurrently during execution of this method)
synchronized (this) {
- if (process == null || process.pid == MY_PID) {
+ if (process.pid == MY_PID) {
sb.append("Process: system_server\n");
} else {
sb.append("Process: ").append(process.processName).append("\n");
}
- if (process == null) {
- return;
- }
int flags = process.info.flags;
IPackageManager pm = AppGlobals.getPackageManager();
sb.append("Flags: 0x").append(Integer.toString(flags, 16)).append("\n");
diff --git a/services/java/com/android/server/connectivity/Tethering.java b/services/java/com/android/server/connectivity/Tethering.java
index a73a4ce..1ec9b51 100644
--- a/services/java/com/android/server/connectivity/Tethering.java
+++ b/services/java/com/android/server/connectivity/Tethering.java
@@ -26,7 +26,7 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.res.Resources;
-import android.hardware.Usb;
+import android.hardware.usb.UsbManager;
import android.net.ConnectivityManager;
import android.net.InterfaceConfiguration;
import android.net.IConnectivityManager;
@@ -111,14 +111,6 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
private boolean mUsbMassStorageOff; // track the status of USB Mass Storage
private boolean mUsbConnected; // track the status of USB connection
- // mUsbHandler message
- static final int USB_STATE_CHANGE = 1;
- static final int USB_DISCONNECTED = 0;
- static final int USB_CONNECTED = 1;
-
- // Time to delay before processing USB disconnect events
- static final long USB_DISCONNECT_DELAY = 1000;
-
public Tethering(Context context, Looper looper) {
mContext = context;
mLooper = looper;
@@ -143,7 +135,7 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
mStateReceiver = new StateReceiver();
IntentFilter filter = new IntentFilter();
- filter.addAction(Usb.ACTION_USB_STATE);
+ filter.addAction(UsbManager.ACTION_USB_STATE);
filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
filter.addAction(Intent.ACTION_BOOT_COMPLETED);
mContext.registerReceiver(mStateReceiver, filter);
@@ -429,25 +421,12 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
}
}
- private Handler mUsbHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- mUsbConnected = (msg.arg1 == USB_CONNECTED);
- updateUsbStatus();
- }
- };
-
private class StateReceiver extends BroadcastReceiver {
public void onReceive(Context content, Intent intent) {
String action = intent.getAction();
- if (action.equals(Usb.ACTION_USB_STATE)) {
- // process connect events immediately, but delay handling disconnects
- // to debounce USB configuration changes
- boolean connected = intent.getExtras().getBoolean(Usb.USB_CONNECTED);
- Message msg = Message.obtain(mUsbHandler, USB_STATE_CHANGE,
- (connected ? USB_CONNECTED : USB_DISCONNECTED), 0);
- mUsbHandler.removeMessages(USB_STATE_CHANGE);
- mUsbHandler.sendMessageDelayed(msg, connected ? 0 : USB_DISCONNECT_DELAY);
+ if (action.equals(UsbManager.ACTION_USB_STATE)) {
+ mUsbConnected = intent.getExtras().getBoolean(UsbManager.USB_CONNECTED);
+ updateUsbStatus();
} else if (action.equals(Intent.ACTION_MEDIA_SHARED)) {
mUsbMassStorageOff = false;
updateUsbStatus();
@@ -1194,18 +1173,18 @@ public class Tethering extends INetworkManagementEventObserver.Stub {
for (String iface : ifaces) {
for (String regex : mUpstreamIfaceRegexs) {
if (iface.matches(regex)) {
- // verify it is up!
+ // verify it is active
InterfaceConfiguration ifcg = null;
try {
ifcg = service.getInterfaceConfig(iface);
+ if (ifcg.isActive()) {
+ return iface;
+ }
} catch (Exception e) {
Log.e(TAG, "Error getting iface config :" + e);
// ignore - try next
continue;
}
- if (ifcg.interfaceFlags.contains("up")) {
- return iface;
- }
}
}
}
diff --git a/services/java/com/android/server/location/GpsLocationProvider.java b/services/java/com/android/server/location/GpsLocationProvider.java
index 3561862..63ce0bd 100755
--- a/services/java/com/android/server/location/GpsLocationProvider.java
+++ b/services/java/com/android/server/location/GpsLocationProvider.java
@@ -203,7 +203,7 @@ public class GpsLocationProvider implements LocationProviderInterface {
// flags to trigger NTP or XTRA data download when network becomes available
// initialized to true so we do NTP and XTRA when the network comes up after booting
private boolean mInjectNtpTimePending = true;
- private boolean mDownloadXtraDataPending = false;
+ private boolean mDownloadXtraDataPending = true;
// true if GPS is navigating
private boolean mNavigating;
diff --git a/services/java/com/android/server/usb/UsbDeviceSettingsManager.java b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
new file mode 100644
index 0000000..616bdca
--- /dev/null
+++ b/services/java/com/android/server/usb/UsbDeviceSettingsManager.java
@@ -0,0 +1,671 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.usb;
+
+import android.app.PendingIntent;
+import android.content.ActivityNotFoundException;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+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.res.XmlResourceParser;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.os.Binder;
+import android.os.FileUtils;
+import android.os.Process;
+import android.util.Log;
+import android.util.SparseBooleanArray;
+import android.util.Xml;
+
+import com.android.internal.content.PackageMonitor;
+import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+class UsbDeviceSettingsManager {
+
+ private static final String TAG = "UsbDeviceSettingsManager";
+ private static final File sSettingsFile = new File("/data/system/usb_device_manager.xml");
+
+ private final Context mContext;
+ private final PackageManager mPackageManager;
+
+ // Temporary mapping UsbAccessory to list of UIDs with permissions for the accessory
+ private final HashMap<UsbAccessory, SparseBooleanArray> mAccessoryPermissionMap =
+ new HashMap<UsbAccessory, SparseBooleanArray>();
+ // Maps AccessoryFilter to user preferred application package
+ private final HashMap<AccessoryFilter, String> mAccessoryPreferenceMap =
+ new HashMap<AccessoryFilter, String>();
+
+ private final Object mLock = new Object();
+
+ // This class is used to describe a USB accessory.
+ // When used in HashMaps all values must be specified,
+ // but wildcards can be used for any of the fields in
+ // the package meta-data.
+ private static class AccessoryFilter {
+ // USB accessory manufacturer (or null for unspecified)
+ public final String mManufacturer;
+ // USB accessory model (or null for unspecified)
+ public final String mModel;
+ // USB accessory version (or null for unspecified)
+ public final String mVersion;
+
+ public AccessoryFilter(String manufacturer, String model, String version) {
+ mManufacturer = manufacturer;
+ mModel = model;
+ mVersion = version;
+ }
+
+ public AccessoryFilter(UsbAccessory accessory) {
+ mManufacturer = accessory.getManufacturer();
+ mModel = accessory.getModel();
+ mVersion = accessory.getVersion();
+ }
+
+ public static AccessoryFilter read(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String manufacturer = null;
+ String model = null;
+ String version = null;
+
+ int count = parser.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ String name = parser.getAttributeName(i);
+ String value = parser.getAttributeValue(i);
+
+ if ("manufacturer".equals(name)) {
+ manufacturer = value;
+ } else if ("model".equals(name)) {
+ model = value;
+ } else if ("version".equals(name)) {
+ version = value;
+ }
+ }
+ return new AccessoryFilter(manufacturer, model, version);
+ }
+
+ public void write(XmlSerializer serializer)throws IOException {
+ serializer.startTag(null, "usb-accessory");
+ if (mManufacturer != null) {
+ serializer.attribute(null, "manufacturer", mManufacturer);
+ }
+ if (mModel != null) {
+ serializer.attribute(null, "model", mModel);
+ }
+ if (mVersion != null) {
+ serializer.attribute(null, "version", mVersion);
+ }
+ serializer.endTag(null, "usb-accessory");
+ }
+
+ public boolean matches(UsbAccessory acc) {
+ if (mManufacturer != null && !acc.getManufacturer().equals(mManufacturer)) return false;
+ if (mModel != null && !acc.getModel().equals(mModel)) return false;
+ if (mVersion != null && !acc.getVersion().equals(mVersion)) return false;
+ return true;
+ }
+
+ public boolean matches(AccessoryFilter f) {
+ if (mManufacturer != null && !f.mManufacturer.equals(mManufacturer)) return false;
+ if (mModel != null && !f.mModel.equals(mModel)) return false;
+ if (mVersion != null && !f.mVersion.equals(mVersion)) return false;
+ return true;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ // can't compare if we have wildcard strings
+ if (mManufacturer == null || mModel == null || mVersion == null) {
+ return false;
+ }
+ if (obj instanceof AccessoryFilter) {
+ AccessoryFilter filter = (AccessoryFilter)obj;
+ return (mManufacturer.equals(filter.mManufacturer) &&
+ mModel.equals(filter.mModel) &&
+ mVersion.equals(filter.mVersion));
+ }
+ if (obj instanceof UsbAccessory) {
+ UsbAccessory accessory = (UsbAccessory)obj;
+ return (mManufacturer.equals(accessory.getManufacturer()) &&
+ mModel.equals(accessory.getModel()) &&
+ mVersion.equals(accessory.getVersion()));
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return ((mManufacturer == null ? 0 : mManufacturer.hashCode()) ^
+ (mModel == null ? 0 : mModel.hashCode()) ^
+ (mVersion == null ? 0 : mVersion.hashCode()));
+ }
+
+ @Override
+ public String toString() {
+ return "AccessoryFilter[mManufacturer=\"" + mManufacturer +
+ "\", mModel=\"" + mModel +
+ "\", mVersion=\"" + mVersion + "\"]";
+ }
+ }
+
+ private class MyPackageMonitor extends PackageMonitor {
+
+ public void onPackageAdded(String packageName, int uid) {
+ handlePackageUpdate(packageName);
+ }
+
+ public void onPackageChanged(String packageName, int uid, String[] components) {
+ handlePackageUpdate(packageName);
+ }
+
+ public void onPackageRemoved(String packageName, int uid) {
+ clearDefaults(packageName);
+ }
+ }
+ MyPackageMonitor mPackageMonitor = new MyPackageMonitor();
+
+ public UsbDeviceSettingsManager(Context context) {
+ mContext = context;
+ mPackageManager = context.getPackageManager();
+ synchronized (mLock) {
+ readSettingsLocked();
+ }
+ mPackageMonitor.register(context, true);
+ }
+
+ private void readPreference(XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ String packageName = null;
+ int count = parser.getAttributeCount();
+ for (int i = 0; i < count; i++) {
+ if ("package".equals(parser.getAttributeName(i))) {
+ packageName = parser.getAttributeValue(i);
+ break;
+ }
+ }
+ XmlUtils.nextElement(parser);
+ if ("usb-accessory".equals(parser.getName())) {
+ AccessoryFilter filter = AccessoryFilter.read(parser);
+ mAccessoryPreferenceMap.put(filter, packageName);
+ }
+ XmlUtils.nextElement(parser);
+ }
+
+ private void readSettingsLocked() {
+ FileInputStream stream = null;
+ try {
+ stream = new FileInputStream(sSettingsFile);
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(stream, null);
+
+ XmlUtils.nextElement(parser);
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ String tagName = parser.getName();
+ if ("preference".equals(tagName)) {
+ readPreference(parser);
+ } else {
+ XmlUtils.nextElement(parser);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ Log.w(TAG, "settings file not found");
+ } catch (Exception e) {
+ Log.e(TAG, "error reading settings file, deleting to start fresh", e);
+ sSettingsFile.delete();
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ private void writeSettingsLocked() {
+ FileOutputStream fos = null;
+ try {
+ FileOutputStream fstr = new FileOutputStream(sSettingsFile);
+ Log.d(TAG, "writing settings to " + fstr);
+ BufferedOutputStream str = new BufferedOutputStream(fstr);
+ FastXmlSerializer serializer = new FastXmlSerializer();
+ serializer.setOutput(str, "utf-8");
+ serializer.startDocument(null, true);
+ serializer.setFeature("http://xmlpull.org/v1/doc/features.html#indent-output", true);
+ serializer.startTag(null, "settings");
+
+ for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
+ serializer.startTag(null, "preference");
+ serializer.attribute(null, "package", mAccessoryPreferenceMap.get(filter));
+ filter.write(serializer);
+ serializer.endTag(null, "preference");
+ }
+
+ serializer.endTag(null, "settings");
+ serializer.endDocument();
+
+ str.flush();
+ FileUtils.sync(fstr);
+ str.close();
+ } catch (Exception e) {
+ Log.e(TAG, "error writing settings file, deleting to start fresh", e);
+ sSettingsFile.delete();
+ }
+ }
+
+ // Checks to see if a package matches an accessory.
+ private boolean packageMatchesLocked(ResolveInfo info, String metaDataName,
+ UsbAccessory accessory) {
+ ActivityInfo ai = info.activityInfo;
+
+ XmlResourceParser parser = null;
+ try {
+ parser = ai.loadXmlMetaData(mPackageManager, metaDataName);
+ if (parser == null) {
+ Log.w(TAG, "no meta-data for " + info);
+ return false;
+ }
+
+ XmlUtils.nextElement(parser);
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ String tagName = parser.getName();
+ if (accessory != null && "usb-accessory".equals(tagName)) {
+ AccessoryFilter filter = AccessoryFilter.read(parser);
+ if (filter.matches(accessory)) {
+ return true;
+ }
+ }
+ XmlUtils.nextElement(parser);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load component info " + info.toString(), e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ return false;
+ }
+
+ private final ArrayList<ResolveInfo> getAccessoryMatchesLocked(
+ UsbAccessory accessory, Intent intent) {
+ ArrayList<ResolveInfo> matches = new ArrayList<ResolveInfo>();
+ List<ResolveInfo> resolveInfos = mPackageManager.queryIntentActivities(intent,
+ PackageManager.GET_META_DATA);
+ int count = resolveInfos.size();
+ for (int i = 0; i < count; i++) {
+ ResolveInfo resolveInfo = resolveInfos.get(i);
+ if (packageMatchesLocked(resolveInfo, intent.getAction(), accessory)) {
+ matches.add(resolveInfo);
+ }
+ }
+ return matches;
+ }
+
+ public void accessoryAttached(UsbAccessory accessory) {
+ Intent intent = new Intent(UsbManager.ACTION_USB_ACCESSORY_ATTACHED);
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ ArrayList<ResolveInfo> matches;
+ String defaultPackage;
+ synchronized (mLock) {
+ matches = getAccessoryMatchesLocked(accessory, intent);
+ // Launch our default activity directly, if we have one.
+ // Otherwise we will start the UsbResolverActivity to allow the user to choose.
+ defaultPackage = mAccessoryPreferenceMap.get(new AccessoryFilter(accessory));
+ }
+
+ resolveActivity(intent, matches, defaultPackage, accessory);
+ }
+
+ public void accessoryDetached(UsbAccessory accessory) {
+ // clear temporary permissions for the accessory
+ mAccessoryPermissionMap.remove(accessory);
+
+ Intent intent = new Intent(
+ UsbManager.ACTION_USB_ACCESSORY_DETACHED);
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ mContext.sendBroadcast(intent);
+ }
+
+ private void resolveActivity(Intent intent, ArrayList<ResolveInfo> matches,
+ String defaultPackage, UsbAccessory accessory) {
+ int count = matches.size();
+
+ // don't show the resolver activity if there are no choices available
+ if (count == 0) {
+ if (accessory != null) {
+ String uri = accessory.getUri();
+ if (uri != null && uri.length() > 0) {
+ // display URI to user
+ // start UsbResolverActivity so user can choose an activity
+ Intent dialogIntent = new Intent();
+ dialogIntent.setClassName("com.android.systemui",
+ "com.android.systemui.usb.UsbAccessoryUriActivity");
+ dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ dialogIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ dialogIntent.putExtra("uri", uri);
+ try {
+ mContext.startActivity(dialogIntent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "unable to start UsbAccessoryUriActivity");
+ }
+ }
+ }
+
+ // do nothing
+ return;
+ }
+
+ ResolveInfo defaultRI = null;
+ if (count == 1 && defaultPackage == null) {
+ // Check to see if our single choice is on the system partition.
+ // If so, treat it as our default without calling UsbResolverActivity
+ ResolveInfo rInfo = matches.get(0);
+ if (rInfo.activityInfo != null &&
+ rInfo.activityInfo.applicationInfo != null &&
+ (rInfo.activityInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
+ defaultRI = rInfo;
+ }
+ }
+
+ if (defaultRI == null && defaultPackage != null) {
+ // look for default activity
+ for (int i = 0; i < count; i++) {
+ ResolveInfo rInfo = matches.get(i);
+ if (rInfo.activityInfo != null &&
+ defaultPackage.equals(rInfo.activityInfo.packageName)) {
+ defaultRI = rInfo;
+ break;
+ }
+ }
+ }
+
+ if (defaultRI != null) {
+ // grant permission for default activity
+ grantAccessoryPermission(accessory, defaultRI.activityInfo.applicationInfo.uid);
+
+ // start default activity directly
+ try {
+ intent.setComponent(
+ new ComponentName(defaultRI.activityInfo.packageName,
+ defaultRI.activityInfo.name));
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "startActivity failed", e);
+ }
+ } else {
+ Intent resolverIntent = new Intent();
+ resolverIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+
+ if (count == 1) {
+ // start UsbConfirmActivity if there is only one choice
+ resolverIntent.setClassName("com.android.systemui",
+ "com.android.systemui.usb.UsbConfirmActivity");
+ resolverIntent.putExtra("rinfo", matches.get(0));
+ resolverIntent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ } else {
+ // start UsbResolverActivity so user can choose an activity
+ resolverIntent.setClassName("com.android.systemui",
+ "com.android.systemui.usb.UsbResolverActivity");
+ resolverIntent.putParcelableArrayListExtra("rlist", matches);
+ resolverIntent.putExtra(Intent.EXTRA_INTENT, intent);
+ }
+ try {
+ mContext.startActivity(resolverIntent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "unable to start activity " + resolverIntent);
+ }
+ }
+ }
+
+ private boolean clearCompatibleMatchesLocked(String packageName, AccessoryFilter filter) {
+ boolean changed = false;
+ for (AccessoryFilter test : mAccessoryPreferenceMap.keySet()) {
+ if (filter.matches(test)) {
+ mAccessoryPreferenceMap.remove(test);
+ changed = true;
+ }
+ }
+ return changed;
+ }
+
+ private boolean handlePackageUpdateLocked(String packageName, ActivityInfo aInfo,
+ String metaDataName) {
+ XmlResourceParser parser = null;
+ boolean changed = false;
+
+ try {
+ parser = aInfo.loadXmlMetaData(mPackageManager, metaDataName);
+ if (parser == null) return false;
+
+ XmlUtils.nextElement(parser);
+ while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
+ String tagName = parser.getName();
+ if ("usb-accessory".equals(tagName)) {
+ AccessoryFilter filter = AccessoryFilter.read(parser);
+ if (clearCompatibleMatchesLocked(packageName, filter)) {
+ changed = true;
+ }
+ }
+ XmlUtils.nextElement(parser);
+ }
+ } catch (Exception e) {
+ Log.w(TAG, "Unable to load component info " + aInfo.toString(), e);
+ } finally {
+ if (parser != null) parser.close();
+ }
+ return changed;
+ }
+
+ // Check to see if the package supports any USB devices or accessories.
+ // If so, clear any non-matching preferences for matching devices/accessories.
+ private void handlePackageUpdate(String packageName) {
+ synchronized (mLock) {
+ PackageInfo info;
+ boolean changed = false;
+
+ try {
+ info = mPackageManager.getPackageInfo(packageName,
+ PackageManager.GET_ACTIVITIES | PackageManager.GET_META_DATA);
+ } catch (NameNotFoundException e) {
+ Log.e(TAG, "handlePackageUpdate could not find package " + packageName, e);
+ return;
+ }
+
+ ActivityInfo[] activities = info.activities;
+ if (activities == null) return;
+ for (int i = 0; i < activities.length; i++) {
+ // check for meta-data, both for devices and accessories
+ if (handlePackageUpdateLocked(packageName, activities[i],
+ UsbManager.ACTION_USB_ACCESSORY_ATTACHED)) {
+ changed = true;
+ }
+ }
+
+ if (changed) {
+ writeSettingsLocked();
+ }
+ }
+ }
+
+ public boolean hasPermission(UsbAccessory accessory) {
+ synchronized (mLock) {
+ SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+ if (uidList == null) {
+ return false;
+ }
+ return uidList.get(Binder.getCallingUid());
+ }
+ }
+
+ public void checkPermission(UsbAccessory accessory) {
+ if (!hasPermission(accessory)) {
+ throw new SecurityException("User has not given permission to accessory " + accessory);
+ }
+ }
+
+ private void requestPermissionDialog(Intent intent, String packageName, PendingIntent pi) {
+ int uid = Binder.getCallingUid();
+
+ // compare uid with packageName to foil apps pretending to be someone else
+ try {
+ ApplicationInfo aInfo = mPackageManager.getApplicationInfo(packageName, 0);
+ if (aInfo.uid != uid) {
+ throw new IllegalArgumentException("package " + packageName +
+ " does not match caller's uid " + uid);
+ }
+ } catch (PackageManager.NameNotFoundException e) {
+ throw new IllegalArgumentException("package " + packageName + " not found");
+ }
+
+ long identity = Binder.clearCallingIdentity();
+ intent.setClassName("com.android.systemui",
+ "com.android.systemui.usb.UsbPermissionActivity");
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ intent.putExtra(Intent.EXTRA_INTENT, pi);
+ intent.putExtra("package", packageName);
+ intent.putExtra("uid", uid);
+ try {
+ mContext.startActivity(intent);
+ } catch (ActivityNotFoundException e) {
+ Log.e(TAG, "unable to start UsbPermissionActivity");
+ } finally {
+ Binder.restoreCallingIdentity(identity);
+ }
+ }
+
+ public void requestPermission(UsbAccessory accessory, String packageName, PendingIntent pi) {
+ Intent intent = new Intent();
+
+ // respond immediately if permission has already been granted
+ if (hasPermission(accessory)) {
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ intent.putExtra(UsbManager.EXTRA_PERMISSION_GRANTED, true);
+ try {
+ pi.send(mContext, 0, intent);
+ } catch (PendingIntent.CanceledException e) {
+ Log.w(TAG, "requestPermission PendingIntent was cancelled");
+ }
+ return;
+ }
+
+ intent.putExtra(UsbManager.EXTRA_ACCESSORY, accessory);
+ requestPermissionDialog(intent, packageName, pi);
+ }
+
+ public void setAccessoryPackage(UsbAccessory accessory, String packageName) {
+ AccessoryFilter filter = new AccessoryFilter(accessory);
+ boolean changed = false;
+ synchronized (mLock) {
+ if (packageName == null) {
+ changed = (mAccessoryPreferenceMap.remove(filter) != null);
+ } else {
+ changed = !packageName.equals(mAccessoryPreferenceMap.get(filter));
+ if (changed) {
+ mAccessoryPreferenceMap.put(filter, packageName);
+ }
+ }
+ if (changed) {
+ writeSettingsLocked();
+ }
+ }
+ }
+
+ public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
+ synchronized (mLock) {
+ SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+ if (uidList == null) {
+ uidList = new SparseBooleanArray(1);
+ mAccessoryPermissionMap.put(accessory, uidList);
+ }
+ uidList.put(uid, true);
+ }
+ }
+
+ public boolean hasDefaults(String packageName) {
+ synchronized (mLock) {
+ return mAccessoryPreferenceMap.values().contains(packageName);
+ }
+ }
+
+ public void clearDefaults(String packageName) {
+ synchronized (mLock) {
+ if (clearPackageDefaultsLocked(packageName)) {
+ writeSettingsLocked();
+ }
+ }
+ }
+
+ private boolean clearPackageDefaultsLocked(String packageName) {
+ boolean cleared = false;
+ synchronized (mLock) {
+ if (mAccessoryPreferenceMap.containsValue(packageName)) {
+ // make a copy of the key set to avoid ConcurrentModificationException
+ Object[] keys = mAccessoryPreferenceMap.keySet().toArray();
+ for (int i = 0; i < keys.length; i++) {
+ Object key = keys[i];
+ if (packageName.equals(mAccessoryPreferenceMap.get(key))) {
+ mAccessoryPreferenceMap.remove(key);
+ cleared = true;
+ }
+ }
+ }
+ return cleared;
+ }
+ }
+
+ public void dump(FileDescriptor fd, PrintWriter pw) {
+ synchronized (mLock) {
+ pw.println(" Accessory permissions:");
+ for (UsbAccessory accessory : mAccessoryPermissionMap.keySet()) {
+ pw.print(" " + accessory + ": ");
+ SparseBooleanArray uidList = mAccessoryPermissionMap.get(accessory);
+ int count = uidList.size();
+ for (int i = 0; i < count; i++) {
+ pw.print(Integer.toString(uidList.keyAt(i)) + " ");
+ }
+ pw.println("");
+ }
+ pw.println(" Accessory preferences:");
+ for (AccessoryFilter filter : mAccessoryPreferenceMap.keySet()) {
+ pw.println(" " + filter + ": " + mAccessoryPreferenceMap.get(filter));
+ }
+ }
+ }
+}
diff --git a/services/java/com/android/server/usb/UsbService.java b/services/java/com/android/server/usb/UsbService.java
new file mode 100644
index 0000000..b4789e7
--- /dev/null
+++ b/services/java/com/android/server/usb/UsbService.java
@@ -0,0 +1,480 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.usb;
+
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.hardware.usb.IUsbManager;
+import android.hardware.usb.UsbAccessory;
+import android.hardware.usb.UsbManager;
+import android.net.Uri;
+import android.os.Binder;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.Message;
+import android.os.Parcelable;
+import android.os.ParcelFileDescriptor;
+import android.os.UEventObserver;
+import android.provider.Settings;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.FileDescriptor;
+import java.io.FileNotFoundException;
+import java.io.FileReader;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * UsbService monitors for changes to USB state.
+ * This includes code for both USB host support (where the android device is the host)
+ * as well as USB device support (android device is connected to a USB host).
+ * Accessory mode is a special case of USB device mode, where the android device is
+ * connected to a USB host that supports the android accessory protocol.
+ */
+public class UsbService extends IUsbManager.Stub {
+ private static final String TAG = UsbService.class.getSimpleName();
+ private static final boolean LOG = false;
+
+ private static final String USB_CONNECTED_MATCH =
+ "DEVPATH=/devices/virtual/switch/usb_connected";
+ private static final String USB_CONFIGURATION_MATCH =
+ "DEVPATH=/devices/virtual/switch/usb_configuration";
+ private static final String USB_FUNCTIONS_MATCH =
+ "DEVPATH=/devices/virtual/usb_composite/";
+ private static final String USB_CONNECTED_PATH =
+ "/sys/class/switch/usb_connected/state";
+ private static final String USB_CONFIGURATION_PATH =
+ "/sys/class/switch/usb_configuration/state";
+ private static final String USB_COMPOSITE_CLASS_PATH =
+ "/sys/class/usb_composite";
+
+ private static final int MSG_UPDATE_STATE = 0;
+ private static final int MSG_FUNCTION_ENABLED = 1;
+ private static final int MSG_FUNCTION_DISABLED = 2;
+
+ // Delay for debouncing USB disconnects.
+ // We often get rapid connect/disconnect events when enabling USB functions,
+ // which need debouncing.
+ private static final int UPDATE_DELAY = 1000;
+
+ // current connected and configuration state
+ private int mConnected;
+ private int mConfiguration;
+
+ // last broadcasted connected and configuration state
+ private int mLastConnected = -1;
+ private int mLastConfiguration = -1;
+
+ // lists of enabled and disabled USB functions (for USB device mode)
+ private final ArrayList<String> mEnabledFunctions = new ArrayList<String>();
+ private final ArrayList<String> mDisabledFunctions = new ArrayList<String>();
+
+ private boolean mSystemReady;
+
+ private UsbAccessory mCurrentAccessory;
+ // USB functions that are enabled by default, to restore after exiting accessory mode
+ private final ArrayList<String> mDefaultFunctions = new ArrayList<String>();
+
+ private final Context mContext;
+ private final Object mLock = new Object();
+ private final UsbDeviceSettingsManager mDeviceManager;
+ private final boolean mHasUsbAccessory;
+
+ private final void readCurrentAccessoryLocked() {
+ if (mHasUsbAccessory) {
+ String[] strings = nativeGetAccessoryStrings();
+ if (strings != null) {
+ mCurrentAccessory = new UsbAccessory(strings);
+ Log.d(TAG, "entering USB accessory mode: " + mCurrentAccessory);
+ if (mSystemReady) {
+ mDeviceManager.accessoryAttached(mCurrentAccessory);
+ }
+ } else {
+ Log.e(TAG, "nativeGetAccessoryStrings failed");
+ }
+ }
+ }
+
+ /*
+ * Handles USB function enable/disable events (device mode)
+ */
+ private final void functionEnabledLocked(String function, boolean enabled) {
+ if (enabled) {
+ if (!mEnabledFunctions.contains(function)) {
+ mEnabledFunctions.add(function);
+ }
+ mDisabledFunctions.remove(function);
+
+ if (UsbManager.USB_FUNCTION_ACCESSORY.equals(function)) {
+ readCurrentAccessoryLocked();
+ }
+ } else {
+ if (!mDisabledFunctions.contains(function)) {
+ mDisabledFunctions.add(function);
+ }
+ mEnabledFunctions.remove(function);
+ }
+ }
+
+ /*
+ * Listens for uevent messages from the kernel to monitor the USB state (device mode)
+ */
+ private final UEventObserver mUEventObserver = new UEventObserver() {
+ @Override
+ public void onUEvent(UEventObserver.UEvent event) {
+ if (Log.isLoggable(TAG, Log.VERBOSE)) {
+ Slog.v(TAG, "USB UEVENT: " + event.toString());
+ }
+
+ synchronized (mLock) {
+ String name = event.get("SWITCH_NAME");
+ String state = event.get("SWITCH_STATE");
+ if (name != null && state != null) {
+ try {
+ int intState = Integer.parseInt(state);
+ if ("usb_connected".equals(name)) {
+ mConnected = intState;
+ // trigger an Intent broadcast
+ if (mSystemReady) {
+ // debounce disconnects to avoid problems bringing up USB tethering
+ update(mConnected == 0);
+ }
+ } else if ("usb_configuration".equals(name)) {
+ mConfiguration = intState;
+ // trigger an Intent broadcast
+ if (mSystemReady) {
+ update(mConnected == 0);
+ }
+ }
+ } catch (NumberFormatException e) {
+ Slog.e(TAG, "Could not parse switch state from event " + event);
+ }
+ } else {
+ String function = event.get("FUNCTION");
+ String enabledStr = event.get("ENABLED");
+ if (function != null && enabledStr != null) {
+ // Note: we do not broadcast a change when a function is enabled or disabled.
+ // We just record the state change for the next broadcast.
+ int what = ("1".equals(enabledStr) ?
+ MSG_FUNCTION_ENABLED : MSG_FUNCTION_DISABLED);
+ Message msg = Message.obtain(mHandler, what);
+ msg.obj = function;
+ mHandler.sendMessage(msg);
+ }
+ }
+ }
+ }
+ };
+
+ private final BroadcastReceiver mBootCompletedReceiver = new BroadcastReceiver() {
+ public void onReceive(Context context, Intent intent) {
+ // handle accessories attached at boot time
+ synchronized (mLock) {
+ if (mCurrentAccessory != null) {
+ mDeviceManager.accessoryAttached(mCurrentAccessory);
+ }
+ }
+ }
+ };
+
+ public UsbService(Context context) {
+ mContext = context;
+ mDeviceManager = new UsbDeviceSettingsManager(context);
+ PackageManager pm = mContext.getPackageManager();
+ mHasUsbAccessory = pm.hasSystemFeature(PackageManager.FEATURE_USB_ACCESSORY);
+
+ synchronized (mLock) {
+ init(); // set initial status
+
+ // Watch for USB configuration changes
+ if (mConfiguration >= 0) {
+ mUEventObserver.startObserving(USB_CONNECTED_MATCH);
+ mUEventObserver.startObserving(USB_CONFIGURATION_MATCH);
+ mUEventObserver.startObserving(USB_FUNCTIONS_MATCH);
+ }
+ }
+ }
+
+ private final void init() {
+ char[] buffer = new char[1024];
+ boolean inAccessoryMode = false;
+
+ // Read initial USB state (device mode)
+ mConfiguration = -1;
+ try {
+ FileReader file = new FileReader(USB_CONNECTED_PATH);
+ int len = file.read(buffer, 0, 1024);
+ file.close();
+ mConnected = Integer.valueOf((new String(buffer, 0, len)).trim());
+
+ file = new FileReader(USB_CONFIGURATION_PATH);
+ len = file.read(buffer, 0, 1024);
+ file.close();
+ mConfiguration = Integer.valueOf((new String(buffer, 0, len)).trim());
+
+ } catch (FileNotFoundException e) {
+ Slog.i(TAG, "This kernel does not have USB configuration switch support");
+ } catch (Exception e) {
+ Slog.e(TAG, "" , e);
+ }
+ if (mConfiguration < 0) {
+ // This may happen in the emulator or devices without USB device mode support
+ return;
+ }
+
+ // Read initial list of enabled and disabled functions (device mode)
+ try {
+ File[] files = new File(USB_COMPOSITE_CLASS_PATH).listFiles();
+ for (int i = 0; i < files.length; i++) {
+ File file = new File(files[i], "enable");
+ FileReader reader = new FileReader(file);
+ int len = reader.read(buffer, 0, 1024);
+ reader.close();
+ int value = Integer.valueOf((new String(buffer, 0, len)).trim());
+ String functionName = files[i].getName();
+ if (value == 1) {
+ mEnabledFunctions.add(functionName);
+ if (UsbManager.USB_FUNCTION_ACCESSORY.equals(functionName)) {
+ // The USB accessory driver is on by default, but it might have been
+ // enabled before the USB service has initialized.
+ inAccessoryMode = true;
+ } else if (!UsbManager.USB_FUNCTION_ADB.equals(functionName)) {
+ // adb is enabled/disabled automatically by the adbd daemon,
+ // so don't treat it as a default function.
+ mDefaultFunctions.add(functionName);
+ }
+ } else {
+ mDisabledFunctions.add(functionName);
+ }
+ }
+ } catch (FileNotFoundException e) {
+ Slog.w(TAG, "This kernel does not have USB composite class support");
+ } catch (Exception e) {
+ Slog.e(TAG, "" , e);
+ }
+
+ // handle the case where an accessory switched the driver to accessory mode
+ // before the framework finished booting
+ if (inAccessoryMode) {
+ readCurrentAccessoryLocked();
+
+ // FIXME - if we booted in accessory mode, then we have no way to figure out
+ // which functions are enabled by default.
+ // For now, assume that MTP or mass storage are the only possibilities
+ if (mDisabledFunctions.contains(UsbManager.USB_FUNCTION_MTP)) {
+ mDefaultFunctions.add(UsbManager.USB_FUNCTION_MTP);
+ } else if (mDisabledFunctions.contains(UsbManager.USB_FUNCTION_MASS_STORAGE)) {
+ mDefaultFunctions.add(UsbManager.USB_FUNCTION_MASS_STORAGE);
+ }
+ }
+ }
+
+ public void systemReady() {
+ synchronized (mLock) {
+ update(false);
+ if (mCurrentAccessory != null) {
+ Log.d(TAG, "accessoryAttached at systemReady");
+ // its still too early to handle accessories, so add a BOOT_COMPLETED receiver
+ // to handle this later.
+ mContext.registerReceiver(mBootCompletedReceiver,
+ new IntentFilter(Intent.ACTION_BOOT_COMPLETED));
+ }
+ mSystemReady = true;
+ }
+ }
+
+ /*
+ * Sends a message to update the USB connected and configured state (device mode).
+ * If delayed is true, then we add a small delay in sending the message to debounce
+ * the USB connection when enabling USB tethering.
+ */
+ private final void update(boolean delayed) {
+ mHandler.removeMessages(MSG_UPDATE_STATE);
+ mHandler.sendEmptyMessageDelayed(MSG_UPDATE_STATE, delayed ? UPDATE_DELAY : 0);
+ }
+
+ /* returns the currently attached USB accessory (device mode) */
+ public UsbAccessory getCurrentAccessory() {
+ return mCurrentAccessory;
+ }
+
+ /* opens the currently attached USB accessory (device mode) */
+ public ParcelFileDescriptor openAccessory(UsbAccessory accessory) {
+ synchronized (mLock) {
+ if (mCurrentAccessory == null) {
+ throw new IllegalArgumentException("no accessory attached");
+ }
+ if (!mCurrentAccessory.equals(accessory)) {
+ Log.e(TAG, accessory.toString() + " does not match current accessory "
+ + mCurrentAccessory);
+ throw new IllegalArgumentException("accessory not attached");
+ }
+ mDeviceManager.checkPermission(mCurrentAccessory);
+ return nativeOpenAccessory();
+ }
+ }
+
+ public void setAccessoryPackage(UsbAccessory accessory, String packageName) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ mDeviceManager.setAccessoryPackage(accessory, packageName);
+ }
+
+ public boolean hasAccessoryPermission(UsbAccessory accessory) {
+ return mDeviceManager.hasPermission(accessory);
+ }
+
+ public void requestAccessoryPermission(UsbAccessory accessory, String packageName,
+ PendingIntent pi) {
+ mDeviceManager.requestPermission(accessory, packageName, pi);
+ }
+
+ public void grantAccessoryPermission(UsbAccessory accessory, int uid) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ mDeviceManager.grantAccessoryPermission(accessory, uid);
+ }
+
+ public boolean hasDefaults(String packageName) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ return mDeviceManager.hasDefaults(packageName);
+ }
+
+ public void clearDefaults(String packageName) {
+ mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USB, null);
+ mDeviceManager.clearDefaults(packageName);
+ }
+
+ /*
+ * This handler is for deferred handling of events related to device mode and accessories.
+ */
+ private final Handler mHandler = new Handler() {
+ private void addEnabledFunctionsLocked(Intent intent) {
+ // include state of all USB functions in our extras
+ for (int i = 0; i < mEnabledFunctions.size(); i++) {
+ intent.putExtra(mEnabledFunctions.get(i), UsbManager.USB_FUNCTION_ENABLED);
+ }
+ for (int i = 0; i < mDisabledFunctions.size(); i++) {
+ intent.putExtra(mDisabledFunctions.get(i), UsbManager.USB_FUNCTION_DISABLED);
+ }
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ synchronized (mLock) {
+ switch (msg.what) {
+ case MSG_UPDATE_STATE:
+ if (mConnected != mLastConnected || mConfiguration != mLastConfiguration) {
+ if (mConnected == 0) {
+ if (UsbManager.isFunctionEnabled(
+ UsbManager.USB_FUNCTION_ACCESSORY)) {
+ // make sure accessory mode is off, and restore default functions
+ Log.d(TAG, "exited USB accessory mode");
+ if (!UsbManager.setFunctionEnabled
+ (UsbManager.USB_FUNCTION_ACCESSORY, false)) {
+ Log.e(TAG, "could not disable accessory function");
+ }
+ int count = mDefaultFunctions.size();
+ for (int i = 0; i < count; i++) {
+ String function = mDefaultFunctions.get(i);
+ if (!UsbManager.setFunctionEnabled(function, true)) {
+ Log.e(TAG, "could not reenable function " + function);
+ }
+ }
+
+ if (mCurrentAccessory != null) {
+ mDeviceManager.accessoryDetached(mCurrentAccessory);
+ mCurrentAccessory = null;
+ }
+ }
+ }
+
+ final ContentResolver cr = mContext.getContentResolver();
+ if (Settings.Secure.getInt(cr,
+ Settings.Secure.DEVICE_PROVISIONED, 0) == 0) {
+ Slog.i(TAG, "Device not provisioned, skipping USB broadcast");
+ return;
+ }
+
+ mLastConnected = mConnected;
+ mLastConfiguration = mConfiguration;
+
+ // send a sticky broadcast containing current USB state
+ Intent intent = new Intent(UsbManager.ACTION_USB_STATE);
+ intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+ intent.putExtra(UsbManager.USB_CONNECTED, mConnected != 0);
+ intent.putExtra(UsbManager.USB_CONFIGURATION, mConfiguration);
+ addEnabledFunctionsLocked(intent);
+ mContext.sendStickyBroadcast(intent);
+ }
+ break;
+ case MSG_FUNCTION_ENABLED:
+ case MSG_FUNCTION_DISABLED:
+ functionEnabledLocked((String)msg.obj, msg.what == MSG_FUNCTION_ENABLED);
+ break;
+ }
+ }
+ }
+ };
+
+ @Override
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+ != PackageManager.PERMISSION_GRANTED) {
+ pw.println("Permission Denial: can't dump UsbManager from from pid="
+ + Binder.getCallingPid()
+ + ", uid=" + Binder.getCallingUid());
+ return;
+ }
+
+ synchronized (mLock) {
+ pw.println("USB Manager State:");
+
+ pw.println(" USB Device State:");
+ pw.print(" Enabled Functions: ");
+ for (int i = 0; i < mEnabledFunctions.size(); i++) {
+ pw.print(mEnabledFunctions.get(i) + " ");
+ }
+ pw.println("");
+ pw.print(" Disabled Functions: ");
+ for (int i = 0; i < mDisabledFunctions.size(); i++) {
+ pw.print(mDisabledFunctions.get(i) + " ");
+ }
+ pw.println("");
+ pw.print(" Default Functions: ");
+ for (int i = 0; i < mDefaultFunctions.size(); i++) {
+ pw.print(mDefaultFunctions.get(i) + " ");
+ }
+ pw.println("");
+ pw.println(" mConnected: " + mConnected + ", mConfiguration: " + mConfiguration);
+ pw.println(" mCurrentAccessory: " + mCurrentAccessory);
+
+ mDeviceManager.dump(fd, pw);
+ }
+ }
+
+ // accessory support
+ private native String[] nativeGetAccessoryStrings();
+ private native ParcelFileDescriptor nativeOpenAccessory();
+}
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index c90879d..de8f158 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -8,6 +8,7 @@ LOCAL_SRC_FILES:= \
com_android_server_LightsService.cpp \
com_android_server_PowerManagerService.cpp \
com_android_server_SystemServer.cpp \
+ com_android_server_UsbService.cpp \
com_android_server_VibratorService.cpp \
com_android_server_location_GpsLocationProvider.cpp \
onload.cpp
diff --git a/services/jni/com_android_server_UsbService.cpp b/services/jni/com_android_server_UsbService.cpp
new file mode 100644
index 0000000..92c5008
--- /dev/null
+++ b/services/jni/com_android_server_UsbService.cpp
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "UsbService"
+#include "utils/Log.h"
+
+#include "jni.h"
+#include "JNIHelp.h"
+#include "android_runtime/AndroidRuntime.h"
+#include "utils/Vector.h"
+
+#include <stdio.h>
+#include <asm/byteorder.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <linux/usb/f_accessory.h>
+
+#define DRIVER_NAME "/dev/usb_accessory"
+
+namespace android
+{
+
+static struct file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+ jfieldID mDescriptor;
+} gFileDescriptorOffsets;
+
+static struct parcel_file_descriptor_offsets_t
+{
+ jclass mClass;
+ jmethodID mConstructor;
+} gParcelFileDescriptorOffsets;
+
+static void checkAndClearExceptionFromCallback(JNIEnv* env, const char* methodName) {
+ if (env->ExceptionCheck()) {
+ LOGE("An exception was thrown by callback '%s'.", methodName);
+ LOGE_EX(env);
+ env->ExceptionClear();
+ }
+}
+
+static void set_accessory_string(JNIEnv *env, int fd, int cmd, jobjectArray strArray, int index)
+{
+ char buffer[256];
+
+ buffer[0] = 0;
+ int length = ioctl(fd, cmd, buffer);
+ if (buffer[0]) {
+ jstring obj = env->NewStringUTF(buffer);
+ env->SetObjectArrayElement(strArray, index, obj);
+ env->DeleteLocalRef(obj);
+ }
+}
+
+
+static jobjectArray android_server_UsbService_getAccessoryStrings(JNIEnv *env, jobject thiz)
+{
+ int fd = open(DRIVER_NAME, O_RDWR);
+ if (fd < 0) {
+ LOGE("could not open %s", DRIVER_NAME);
+ return NULL;
+ }
+ jclass stringClass = env->FindClass("java/lang/String");
+ jobjectArray strArray = env->NewObjectArray(6, stringClass, NULL);
+ if (!strArray) goto out;
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_MANUFACTURER, strArray, 0);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_MODEL, strArray, 1);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_DESCRIPTION, strArray, 2);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_VERSION, strArray, 3);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_URI, strArray, 4);
+ set_accessory_string(env, fd, ACCESSORY_GET_STRING_SERIAL, strArray, 5);
+
+out:
+ close(fd);
+ return strArray;
+}
+
+static jobject android_server_UsbService_openAccessory(JNIEnv *env, jobject thiz)
+{
+ int fd = open(DRIVER_NAME, O_RDWR);
+ if (fd < 0) {
+ LOGE("could not open %s", DRIVER_NAME);
+ return NULL;
+ }
+ jobject fileDescriptor = env->NewObject(gFileDescriptorOffsets.mClass,
+ gFileDescriptorOffsets.mConstructor);
+ if (fileDescriptor != NULL) {
+ env->SetIntField(fileDescriptor, gFileDescriptorOffsets.mDescriptor, fd);
+ } else {
+ return NULL;
+ }
+ return env->NewObject(gParcelFileDescriptorOffsets.mClass,
+ gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
+}
+
+static JNINativeMethod method_table[] = {
+ { "nativeGetAccessoryStrings", "()[Ljava/lang/String;",
+ (void*)android_server_UsbService_getAccessoryStrings },
+ { "nativeOpenAccessory","()Landroid/os/ParcelFileDescriptor;",
+ (void*)android_server_UsbService_openAccessory },
+};
+
+int register_android_server_UsbService(JNIEnv *env)
+{
+ jclass clazz = env->FindClass("java/io/FileDescriptor");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class java.io.FileDescriptor");
+ gFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
+ gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
+ LOG_FATAL_IF(gFileDescriptorOffsets.mDescriptor == NULL,
+ "Unable to find descriptor field in java.io.FileDescriptor");
+
+ clazz = env->FindClass("android/os/ParcelFileDescriptor");
+ LOG_FATAL_IF(clazz == NULL, "Unable to find class android.os.ParcelFileDescriptor");
+ gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
+ gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
+ LOG_FATAL_IF(gParcelFileDescriptorOffsets.mConstructor == NULL,
+ "Unable to find constructor for android.os.ParcelFileDescriptor");
+
+ return jniRegisterNativeMethods(env, "com/android/server/usb/UsbService",
+ method_table, NELEM(method_table));
+}
+
+};
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index cd4f0a4..613683b 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -9,6 +9,7 @@ int register_android_server_BatteryService(JNIEnv* env);
int register_android_server_InputManager(JNIEnv* env);
int register_android_server_LightsService(JNIEnv* env);
int register_android_server_PowerManagerService(JNIEnv* env);
+int register_android_server_UsbService(JNIEnv* env);
int register_android_server_VibratorService(JNIEnv* env);
int register_android_server_SystemServer(JNIEnv* env);
int register_android_server_location_GpsLocationProvider(JNIEnv* env);
@@ -32,6 +33,7 @@ extern "C" jint JNI_OnLoad(JavaVM* vm, void* reserved)
register_android_server_LightsService(env);
register_android_server_AlarmManagerService(env);
register_android_server_BatteryService(env);
+ register_android_server_UsbService(env);
register_android_server_VibratorService(env);
register_android_server_SystemServer(env);
register_android_server_location_GpsLocationProvider(env);
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index c9dcef3..dfee803 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -874,8 +874,16 @@ status_t Layer::BufferManager::initEglImage(EGLDisplay dpy,
ssize_t index = mActiveBuffer;
if (index >= 0) {
if (!mFailover) {
- Image& texture(mBufferData[index].texture);
- err = mTextureManager.initEglImage(&texture, dpy, buffer);
+ {
+ // Without that lock, there is a chance of race condition
+ // where while composing a specific index, requestBuf
+ // with the same index can be executed and touch the same data
+ // that is being used in initEglImage.
+ // (e.g. dirty flag in texture)
+ Mutex::Autolock _l(mLock);
+ Image& texture(mBufferData[index].texture);
+ err = mTextureManager.initEglImage(&texture, dpy, buffer);
+ }
// if EGLImage fails, we switch to regular texture mode, and we
// free all resources associated with using EGLImages.
if (err == NO_ERROR) {
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 916d420..21c36e1 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -515,12 +515,6 @@ void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
result.append(buffer);
}
-void LayerBase::shortDump(String8& result, char* scratch, size_t size) const
-{
- LayerBase::dump(result, scratch, size);
-}
-
-
// ---------------------------------------------------------------------------
int32_t LayerBaseClient::sIdentity = 1;
@@ -572,12 +566,6 @@ void LayerBaseClient::dump(String8& result, char* buffer, size_t SIZE) const
result.append(buffer);
}
-
-void LayerBaseClient::shortDump(String8& result, char* scratch, size_t size) const
-{
- LayerBaseClient::dump(result, scratch, size);
-}
-
// ---------------------------------------------------------------------------
LayerBaseClient::Surface::Surface(
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 1470729..afc5ec8 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -206,7 +206,6 @@ public:
/** always call base class first */
virtual void dump(String8& result, char* scratch, size_t size) const;
- virtual void shortDump(String8& result, char* scratch, size_t size) const;
enum { // flags for doTransaction()
@@ -326,7 +325,6 @@ public:
protected:
virtual void dump(String8& result, char* scratch, size_t size) const;
- virtual void shortDump(String8& result, char* scratch, size_t size) const;
private:
mutable Mutex mLock;
diff --git a/services/surfaceflinger/LayerBuffer.cpp b/services/surfaceflinger/LayerBuffer.cpp
index 23506cf..55d859d 100644
--- a/services/surfaceflinger/LayerBuffer.cpp
+++ b/services/surfaceflinger/LayerBuffer.cpp
@@ -93,6 +93,9 @@ bool LayerBuffer::needsBlending() const {
}
void LayerBuffer::setNeedsBlending(bool blending) {
+ if (mNeedsBlending != blending) {
+ mFlinger->invalidateLayerVisibility(this);
+ }
mNeedsBlending = blending;
}
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 4876946..c08e2c9 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1066,12 +1066,8 @@ status_t SurfaceFlinger::removeLayer_l(const sp<LayerBase>& layerBase)
status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)
{
- // First add the layer to the purgatory list, which makes sure it won't
- // go away, then remove it from the main list (through a transaction).
+ // remove the layer from the main list (through a transaction).
ssize_t err = removeLayer_l(layerBase);
- if (err >= 0) {
- mLayerPurgatory.add(layerBase);
- }
layerBase->onRemoved();
@@ -1342,19 +1338,6 @@ status_t SurfaceFlinger::destroySurface(const sp<LayerBaseClient>& layer)
* to use the purgatory.
*/
status_t err = flinger->removeLayer_l(l);
- if (err == NAME_NOT_FOUND) {
- // The surface wasn't in the current list, which means it was
- // removed already, which means it is in the purgatory,
- // and need to be removed from there.
- // This needs to happen from the main thread since its dtor
- // must run from there (b/c of OpenGL ES). Additionally, we
- // can't really acquire our internal lock from
- // destroySurface() -- see postMessage() below.
- ssize_t idx = flinger->mLayerPurgatory.remove(l);
- LOGE_IF(idx < 0,
- "layer=%p is not in the purgatory list", l.get());
- }
-
LOGE_IF(err<0 && err != NAME_NOT_FOUND,
"error removing layer=%p (%s)", l.get(), strerror(-err));
return true;
@@ -1470,13 +1453,8 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
result.append(buffer);
}
- /*
- * Dump the visible layer list
- */
const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
const size_t count = currentLayers.size();
- snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
- result.append(buffer);
for (size_t i=0 ; i<count ; i++) {
const sp<LayerBase>& layer(currentLayers[i]);
layer->dump(result, buffer, SIZE);
@@ -1486,24 +1464,6 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
}
- /*
- * Dump the layers in the purgatory
- */
-
- const size_t purgatorySize = mLayerPurgatory.size();
- snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
- result.append(buffer);
- for (size_t i=0 ; i<purgatorySize ; i++) {
- const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
- layer->shortDump(result, buffer, SIZE);
- }
-
- /*
- * Dump SurfaceFlinger global state
- */
-
- snprintf(buffer, SIZE, "SurfaceFlinger global state\n");
- result.append(buffer);
mWormholeRegion.dump(result, "WormholeRegion");
const DisplayHardware& hw(graphicPlane(0).displayHardware());
snprintf(buffer, SIZE,
@@ -1529,9 +1489,6 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args)
result.append(buffer);
}
- /*
- * Dump gralloc state
- */
const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
alloc.dump(result);
@@ -2427,7 +2384,7 @@ ssize_t UserClient::getTokenForSurface(const sp<ISurface>& sur) const
}
break;
}
- if (++name > 31)
+ if (++name >= SharedBufferStack::NUM_LAYERS_MAX)
name = NO_MEMORY;
} while(name >= 0);
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index a023347..df1ca48 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -370,7 +370,6 @@ private:
volatile int32_t mTransactionFlags;
volatile int32_t mTransactionCount;
Condition mTransactionCV;
- SortedVector< sp<LayerBase> > mLayerPurgatory;
bool mResizeTransationPending;
// protected by mStateLock (but we could use another lock)
diff --git a/services/surfaceflinger/TextureManager.cpp b/services/surfaceflinger/TextureManager.cpp
index c9a15f5..9e24f90 100644
--- a/services/surfaceflinger/TextureManager.cpp
+++ b/services/surfaceflinger/TextureManager.cpp
@@ -186,7 +186,7 @@ status_t TextureManager::loadTexture(Texture* texture,
if (texture->name == -1UL) {
status_t err = initTexture(texture);
LOGE_IF(err, "loadTexture failed in initTexture (%s)", strerror(err));
- return err;
+ if (err != NO_ERROR) return err;
}
if (texture->target != Texture::TEXTURE_2D)
diff --git a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
index 6390d8e..f5e53ef 100644
--- a/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
+++ b/telephony/java/android/telephony/JapanesePhoneNumberFormatter.java
@@ -24,6 +24,7 @@ import android.text.Editable;
*
* 022-229-1234 0223-23-1234 022-301-9876 015-482-7849 0154-91-3478
* 01547-5-4534 090-1234-1234 080-0123-6789
+ * 050-0000-0000 060-0000-0000
* 0800-000-9999 0570-000-000 0276-00-0000
*
* As you can see, there is no straight-forward rule here.
@@ -31,7 +32,7 @@ import android.text.Editable;
*/
/* package */ class JapanesePhoneNumberFormatter {
private static short FORMAT_MAP[] = {
- -100, 10, 220, -15, 410, 530, -15, 670, 780, 1060,
+ -100, 10, 220, -15, 410, 530, 1200, 670, 780, 1060,
-100, -25, 20, 40, 70, 100, 150, 190, 200, 210,
-36, -100, -100, -35, -35, -35, 30, -100, -100, -100,
-35, -35, -35, -35, -35, -35, -35, -45, -35, -35,
@@ -84,7 +85,7 @@ import android.text.Editable;
-35, -25, -25, -25, -25, -25, -25, -25, -25, -25,
-25, -25, -25, -35, -35, -35, -25, -25, -25, 520,
-100, -100, -45, -100, -45, -100, -45, -100, -45, -100,
- -25, -100, -25, 540, 580, 590, 600, 610, 630, 640,
+ -26, -100, -25, 540, 580, 590, 600, 610, 630, 640,
-25, -35, -35, -35, -25, -25, -35, -35, -35, 550,
-35, -35, -25, -25, -25, -25, 560, 570, -25, -35,
-35, -35, -35, -35, -25, -25, -25, -25, -25, -25,
@@ -150,7 +151,8 @@ import android.text.Editable;
-35, 1170, -25, -35, 1180, -35, 1190, -35, -25, -25,
-100, -100, -45, -45, -100, -100, -100, -100, -100, -100,
-25, -35, -35, -35, -35, -35, -35, -25, -25, -35,
- -35, -35, -35, -35, -35, -35, -35, -35, -35, -45};
+ -35, -35, -35, -35, -35, -35, -35, -35, -35, -45,
+ -26, -15, -15, -15, -15, -15, -15, -15, -15, -15};
public static void format(Editable text) {
// Here, "root" means the position of "'":
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 56c641b..b8bf8af 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1350,11 +1350,15 @@ public interface CommandsInterface {
* the password for APN, or NULL
* @param authType
* the PAP / CHAP auth type. Values is one of SETUP_DATA_AUTH_*
+ * @param protocol
+ * one of the PDP_type values in TS 27.007 section 10.1.1.
+ * For example, "IP", "IPV6", "IPV4V6", or "PPP".
* @param result
* Callback message
*/
- public void setupDataCall(String radioTechnology, String profile, String apn,
- String user, String password, String authType, Message result);
+ public void setupDataCall(String radioTechnology, String profile,
+ String apn, String user, String password, String authType,
+ String protocol, Message result);
/**
* Deactivate packet data connection
diff --git a/telephony/java/com/android/internal/telephony/IccUtils.java b/telephony/java/com/android/internal/telephony/IccUtils.java
index 5bd7523..2244ac4 100644
--- a/telephony/java/com/android/internal/telephony/IccUtils.java
+++ b/telephony/java/com/android/internal/telephony/IccUtils.java
@@ -446,7 +446,6 @@ public class IccUtils {
int colorNumber = data[valueIndex++] & 0xFF;
int clutOffset = ((data[valueIndex++] & 0xFF) << 8)
| (data[valueIndex++] & 0xFF);
- length = length - 6;
int[] colorIndexArray = getCLUT(data, clutOffset, colorNumber);
if (true == transparency) {
diff --git a/telephony/java/com/android/internal/telephony/RIL.java b/telephony/java/com/android/internal/telephony/RIL.java
index f549001..e059555 100644
--- a/telephony/java/com/android/internal/telephony/RIL.java
+++ b/telephony/java/com/android/internal/telephony/RIL.java
@@ -1315,7 +1315,8 @@ public final class RIL extends BaseCommands implements CommandsInterface {
: RILConstants.SETUP_DATA_AUTH_NONE;
setupDataCall(Integer.toString(radioTechnology), profile, apn, user,
- password, Integer.toString(authType), result);
+ password, Integer.toString(authType),
+ RILConstants.SETUP_DATA_PROTOCOL_IP, result);
}
@@ -1327,18 +1328,14 @@ public final class RIL extends BaseCommands implements CommandsInterface {
deactivateDataCall(cid, result);
}
- /**
- * The preferred new alternative to setupDefaultPDP that is
- * CDMA-compatible.
- *
- */
public void
setupDataCall(String radioTechnology, String profile, String apn,
- String user, String password, String authType, Message result) {
+ String user, String password, String authType, String protocol,
+ Message result) {
RILRequest rr
= RILRequest.obtain(RIL_REQUEST_SETUP_DATA_CALL, result);
- rr.mp.writeInt(6);
+ rr.mp.writeInt(7);
rr.mp.writeString(radioTechnology);
rr.mp.writeString(profile);
@@ -1346,11 +1343,12 @@ public final class RIL extends BaseCommands implements CommandsInterface {
rr.mp.writeString(user);
rr.mp.writeString(password);
rr.mp.writeString(authType);
+ rr.mp.writeString(protocol);
if (RILJ_LOGD) riljLog(rr.serialString() + "> "
+ requestToString(rr.mRequest) + " " + radioTechnology + " "
+ profile + " " + apn + " " + user + " "
- + password + " " + authType);
+ + password + " " + authType + " " + protocol);
send(rr);
}
@@ -2980,7 +2978,11 @@ public final class RIL extends BaseCommands implements CommandsInterface {
dataCall.active = p.readInt();
dataCall.type = p.readString();
dataCall.apn = p.readString();
- dataCall.address = p.readString();
+ String address = p.readString();
+ if (address != null) {
+ address = address.split(" ")[0];
+ }
+ dataCall.address = address;
response.add(dataCall);
}
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index 888f721..0686791 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -91,11 +91,16 @@ public interface RILConstants {
/* Setup a packet data connection. See ril.h RIL_REQUEST_SETUP_DATA_CALL */
int SETUP_DATA_TECH_CDMA = 0;
int SETUP_DATA_TECH_GSM = 1;
+
int SETUP_DATA_AUTH_NONE = 0;
int SETUP_DATA_AUTH_PAP = 1;
int SETUP_DATA_AUTH_CHAP = 2;
int SETUP_DATA_AUTH_PAP_CHAP = 3;
+ String SETUP_DATA_PROTOCOL_IP = "IP";
+ String SETUP_DATA_PROTOCOL_IPV6 = "IPV6";
+ String SETUP_DATA_PROTOCOL_IPV4V6 = "IPV4V6";
+
/*
cat include/telephony/ril.h | \
egrep '^#define' | \
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index 0865d6f..3890a98 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -737,7 +737,14 @@ public class CDMAPhone extends PhoneBase {
String number = null;
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getContext());
// TODO: The default value of voicemail number should be read from a system property
- number = sp.getString(VM_NUMBER_CDMA, "*86");
+
+ // Read platform settings for dynamic voicemail number
+ if (getContext().getResources().getBoolean(com.android.internal
+ .R.bool.config_telephony_use_own_number_for_voicemail)) {
+ number = sp.getString(VM_NUMBER_CDMA, getLine1Number());
+ } else {
+ number = sp.getString(VM_NUMBER_CDMA, "*86");
+ }
return number;
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
index 95cb1c6..66f35e4 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnection.java
@@ -85,9 +85,12 @@ public class CdmaDataConnection extends DataConnection {
// msg.obj will be returned in AsyncResult.userObj;
Message msg = obtainMessage(EVENT_SETUP_DATA_CONNECTION_DONE, cp);
msg.obj = cp;
- phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA),
- Integer.toString(dataProfile), null, null,
- null, Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP), msg);
+ phone.mCM.setupDataCall(
+ Integer.toString(RILConstants.SETUP_DATA_TECH_CDMA),
+ Integer.toString(dataProfile),
+ null, null, null,
+ Integer.toString(RILConstants.SETUP_DATA_AUTH_PAP_CHAP),
+ RILConstants.SETUP_DATA_PROTOCOL_IP, msg);
}
@Override
diff --git a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
index 9f2a44b..fa80063 100644
--- a/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CdmaDataConnectionTracker.java
@@ -432,7 +432,8 @@ public final class CdmaDataConnectionTracker extends DataConnectionTracker {
} else {
types = mDefaultApnTypes;
}
- mActiveApn = new ApnSetting(0, "", "", "", "", "", "", "", "", "", "", 0, types);
+ mActiveApn = new ApnSetting(0, "", "", "", "", "", "", "", "", "", "",
+ 0, types, "IP", "IP");
Message msg = obtainMessage();
msg.what = EVENT_DATA_SETUP_COMPLETE;
diff --git a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
index 87b0c60..3429099 100644..100755
--- a/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
+++ b/telephony/java/com/android/internal/telephony/cdma/RuimRecords.java
@@ -16,10 +16,13 @@
package com.android.internal.telephony.cdma;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_ISO_COUNTRY;
+import static com.android.internal.telephony.TelephonyProperties.PROPERTY_ICC_OPERATOR_NUMERIC;
import android.os.AsyncResult;
import android.os.Handler;
import android.os.Message;
import android.os.Registrant;
+import android.os.SystemProperties;
import android.util.Log;
import com.android.internal.telephony.AdnRecord;
@@ -59,6 +62,7 @@ public final class RuimRecords extends IccRecords {
private static final int EVENT_RUIM_READY = 1;
private static final int EVENT_RADIO_OFF_OR_NOT_AVAILABLE = 2;
+ private static final int EVENT_GET_IMSI_DONE = 3;
private static final int EVENT_GET_DEVICE_IDENTITY_DONE = 4;
private static final int EVENT_GET_ICCID_DONE = 5;
private static final int EVENT_GET_CDMA_SUBSCRIPTION_DONE = 10;
@@ -114,6 +118,9 @@ public final class RuimRecords extends IccRecords {
adnCache.reset();
+ phone.setSystemProperty(PROPERTY_ICC_OPERATOR_NUMERIC, null);
+ phone.setSystemProperty(PROPERTY_ICC_OPERATOR_ISO_COUNTRY, null);
+
// recordsRequested is set to false indicating that the SIM
// read requests made so far are not valid. This is set to
// true only when fresh set of read requests are made.
@@ -201,6 +208,33 @@ public final class RuimRecords extends IccRecords {
break;
/* IO events */
+ case EVENT_GET_IMSI_DONE:
+ isRecordLoadResponse = true;
+
+ ar = (AsyncResult)msg.obj;
+ if (ar.exception != null) {
+ Log.e(LOG_TAG, "Exception querying IMSI, Exception:" + ar.exception);
+ break;
+ }
+
+ mImsi = (String) ar.result;
+
+ // IMSI (MCC+MNC+MSIN) is at least 6 digits, but not more
+ // than 15 (and usually 15).
+ if (mImsi != null && (mImsi.length() < 6 || mImsi.length() > 15)) {
+ Log.e(LOG_TAG, "invalid IMSI " + mImsi);
+ mImsi = null;
+ }
+
+ Log.d(LOG_TAG, "IMSI: " + mImsi.substring(0, 6) + "xxxxxxxxx");
+
+ String operatorNumeric = getRUIMOperatorNumeric();
+ if (operatorNumeric != null) {
+ if(operatorNumeric.length() <= 6){
+ MccTable.updateMccMncConfiguration(phone, operatorNumeric);
+ }
+ }
+ break;
case EVENT_GET_CDMA_SUBSCRIPTION_DONE:
ar = (AsyncResult)msg.obj;
@@ -291,6 +325,13 @@ public final class RuimRecords extends IccRecords {
// Further records that can be inserted are Operator/OEM dependent
+ String operator = getRUIMOperatorNumeric();
+ SystemProperties.set(PROPERTY_ICC_OPERATOR_NUMERIC, operator);
+
+ if (mImsi != null) {
+ SystemProperties.set(PROPERTY_ICC_OPERATOR_ISO_COUNTRY,
+ MccTable.countryCodeForMcc(Integer.parseInt(mImsi.substring(0,3))));
+ }
recordsLoadedRegistrants.notifyRegistrants(
new AsyncResult(null, null, null));
((CDMAPhone) phone).mRuimCard.broadcastIccStateChangedIntent(
@@ -317,6 +358,9 @@ public final class RuimRecords extends IccRecords {
Log.v(LOG_TAG, "RuimRecords:fetchRuimRecords " + recordsToLoad);
+ phone.mCM.getIMSI(obtainMessage(EVENT_GET_IMSI_DONE));
+ recordsToLoad++;
+
phone.getIccFileHandler().loadEFTransparent(EF_ICCID,
obtainMessage(EVENT_GET_ICCID_DONE));
recordsToLoad++;
diff --git a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
index ebe6467..8a4e0ce 100644..100755
--- a/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
+++ b/telephony/java/com/android/internal/telephony/cdma/sms/BearerData.java
@@ -37,6 +37,9 @@ import com.android.internal.util.HexDump;
import com.android.internal.util.BitwiseInputStream;
import com.android.internal.util.BitwiseOutputStream;
+import android.content.res.Resources;
+
+
/**
* An object to encode and decode CDMA SMS bearer data.
@@ -911,6 +914,16 @@ public final class BearerData {
return true;
}
+ private static String decodeUtf8(byte[] data, int offset, int numFields)
+ throws CodingException
+ {
+ try {
+ return new String(data, offset, numFields, "UTF-8");
+ } catch (java.io.UnsupportedEncodingException ex) {
+ throw new CodingException("UTF-8 decode failed: " + ex);
+ }
+ }
+
private static String decodeUtf16(byte[] data, int offset, int numFields)
throws CodingException
{
@@ -995,9 +1008,15 @@ public final class BearerData {
}
switch (userData.msgEncoding) {
case UserData.ENCODING_OCTET:
+ /*
+ * Octet decoding depends on the carrier service.
+ */
+ boolean decodingtypeUTF8 = Resources.getSystem()
+ .getBoolean(com.android.internal.R.bool.config_sms_utf8_support);
+
// Strip off any padding bytes, meaning any differences between the length of the
- // array and the target length specified by numFields. This is to avoid any confusion
- // by code elsewhere that only considers the payload array length.
+ // array and the target length specified by numFields. This is to avoid any
+ // confusion by code elsewhere that only considers the payload array length.
byte[] payload = new byte[userData.numFields];
int copyLen = userData.numFields < userData.payload.length
? userData.numFields : userData.payload.length;
@@ -1005,9 +1024,13 @@ public final class BearerData {
System.arraycopy(userData.payload, 0, payload, 0, copyLen);
userData.payload = payload;
- // There are many devices in the market that send 8bit text sms (latin encoded) as
- // octet encoded.
- userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
+ if (!decodingtypeUTF8) {
+ // There are many devices in the market that send 8bit text sms (latin encoded) as
+ // octet encoded.
+ userData.payloadStr = decodeLatin(userData.payload, offset, userData.numFields);
+ } else {
+ userData.payloadStr = decodeUtf8(userData.payload, offset, userData.numFields);
+ }
break;
case UserData.ENCODING_IA5:
case UserData.ENCODING_7BIT_ASCII:
diff --git a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
index 05527af..e96ad72 100644
--- a/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
+++ b/telephony/java/com/android/internal/telephony/gsm/ApnSetting.java
@@ -22,6 +22,8 @@ import com.android.internal.telephony.*;
*/
public class ApnSetting {
+ static final String V2_FORMAT_REGEX = "^\\[ApnSettingV2\\]\\s*";
+
String carrier;
String apn;
String proxy;
@@ -35,11 +37,14 @@ public class ApnSetting {
public String[] types;
int id;
String numeric;
+ String protocol;
+ String roamingProtocol;
-
- public ApnSetting(int id, String numeric, String carrier, String apn, String proxy, String port,
+ public ApnSetting(int id, String numeric, String carrier, String apn,
+ String proxy, String port,
String mmsc, String mmsProxy, String mmsPort,
- String user, String password, int authType, String[] types) {
+ String user, String password, int authType, String[] types,
+ String protocol, String roamingProtocol) {
this.id = id;
this.numeric = numeric;
this.carrier = carrier;
@@ -53,40 +58,81 @@ public class ApnSetting {
this.password = password;
this.authType = authType;
this.types = types;
+ this.protocol = protocol;
+ this.roamingProtocol = roamingProtocol;
}
- // data[0] = name
- // data[1] = apn
- // data[2] = proxy
- // data[3] = port
- // data[4] = username
- // data[5] = password
- // data[6] = server
- // data[7] = mmsc
- // data[8] = mmsproxy
- // data[9] = mmsport
- // data[10] = mcc
- // data[11] = mnc
- // data[12] = auth
- // data[13] = first type...
+ /**
+ * Creates an ApnSetting object from a string.
+ *
+ * @param data the string to read.
+ *
+ * The string must be in one of two formats (newlines added for clarity,
+ * spaces are optional):
+ *
+ * v1 format:
+ * <carrier>, <apn>, <proxy>, <port>, <mmsc>, <mmsproxy>,
+ * <mmsport>, <user>, <password>, <authtype>, <mcc>,<mnc>,
+ * <type>[, <type>...]
+ *
+ * v2 format:
+ * [ApnSettingV2] <carrier>, <apn>, <proxy>, <port>, <mmsc>, <mmsproxy>,
+ * <mmsport>, <user>, <password, <authtype>, <mcc>, <mnc>,
+ * <type>[| <type>...], <protocol>, <roaming_protocol>
+ *
+ * Note that the strings generated by toString() do not contain the username
+ * and password and thus cannot be read by this method.
+ *
+ * @see ApnSettingTest
+ */
public static ApnSetting fromString(String data) {
if (data == null) return null;
+
+ int version;
+ // matches() operates on the whole string, so append .* to the regex.
+ if (data.matches(V2_FORMAT_REGEX + ".*")) {
+ version = 2;
+ data = data.replaceFirst(V2_FORMAT_REGEX, "");
+ } else {
+ version = 1;
+ }
+
String[] a = data.split("\\s*,\\s*");
- if (a.length < 14) return null;
- int authType = 0;
+ if (a.length < 14) {
+ return null;
+ }
+
+ int authType;
try {
authType = Integer.parseInt(a[12]);
} catch (Exception e) {
+ authType = 0;
}
- String[] typeArray = new String[a.length - 13];
- System.arraycopy(a, 13, typeArray, 0, a.length - 13);
+
+ String[] typeArray;
+ String protocol, roamingProtocol;
+ if (version == 1) {
+ typeArray = new String[a.length - 13];
+ System.arraycopy(a, 13, typeArray, 0, a.length - 13);
+ protocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
+ roamingProtocol = RILConstants.SETUP_DATA_PROTOCOL_IP;
+ } else {
+ if (a.length < 16) {
+ return null;
+ }
+ typeArray = a[13].split("\\s*\\|\\s*");
+ protocol = a[14];
+ roamingProtocol = a[15];
+ }
+
return new ApnSetting(-1,a[10]+a[11],a[0],a[1],a[2],a[3],a[7],a[8],
- a[9],a[4],a[5],authType,typeArray);
+ a[9],a[4],a[5],authType,typeArray,protocol,roamingProtocol);
}
public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append(carrier)
+ sb.append("[ApnSettingV2] ")
+ .append(carrier)
.append(", ").append(id)
.append(", ").append(numeric)
.append(", ").append(apn)
@@ -95,10 +141,15 @@ public class ApnSetting {
.append(", ").append(mmsProxy)
.append(", ").append(mmsPort)
.append(", ").append(port)
- .append(", ").append(authType);
- for (String t : types) {
- sb.append(", ").append(t);
+ .append(", ").append(authType).append(", ");
+ for (int i = 0; i < types.length; i++) {
+ sb.append(types[i]);
+ if (i < types.length - 1) {
+ sb.append(" | ");
+ }
}
+ sb.append(", ").append(protocol);
+ sb.append(", ").append(roamingProtocol);
return sb.toString();
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
index 09d46dd..3de4c27 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnection.java
@@ -104,9 +104,19 @@ public class GsmDataConnection extends DataConnection {
authType = (apn.user != null) ? RILConstants.SETUP_DATA_AUTH_PAP_CHAP :
RILConstants.SETUP_DATA_AUTH_NONE;
}
- phone.mCM.setupDataCall(Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
- Integer.toString(RILConstants.DATA_PROFILE_DEFAULT), apn.apn, apn.user,
- apn.password, Integer.toString(authType), msg);
+
+ String protocol;
+ if (phone.getServiceState().getRoaming()) {
+ protocol = apn.roamingProtocol;
+ } else {
+ protocol = apn.protocol;
+ }
+
+ phone.mCM.setupDataCall(
+ Integer.toString(RILConstants.SETUP_DATA_TECH_GSM),
+ Integer.toString(RILConstants.DATA_PROFILE_DEFAULT),
+ apn.apn, apn.user, apn.password, Integer.toString(authType),
+ protocol, msg);
}
@Override
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
index ab9cf2a..96005f0 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmDataConnectionTracker.java
@@ -361,6 +361,12 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
@Override
protected boolean isApnTypeActive(String type) {
// TODO: support simultaneous with List instead
+ if (Phone.APN_TYPE_DUN.equals(type)) {
+ ApnSetting dunApn = fetchDunApn();
+ if (dunApn != null) {
+ return ((mActiveApn != null) && (dunApn.toString().equals(mActiveApn.toString())));
+ }
+ }
return mActiveApn != null && mActiveApn.canHandleType(type);
}
@@ -559,7 +565,10 @@ public final class GsmDataConnectionTracker extends DataConnectionTracker {
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.USER)),
cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PASSWORD)),
cursor.getInt(cursor.getColumnIndexOrThrow(Telephony.Carriers.AUTH_TYPE)),
- types);
+ types,
+ cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Carriers.PROTOCOL)),
+ cursor.getString(cursor.getColumnIndexOrThrow(
+ Telephony.Carriers.ROAMING_PROTOCOL)));
result.add(apn);
} while (cursor.moveToNext());
}
diff --git a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
index b642541..ec3d20a 100755
--- a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
@@ -307,8 +307,15 @@ public class UsimPhoneBookManager extends Handler implements IccConstants {
fileIds = mPbrFile.mFileIds.get(recNum);
if (fileIds == null || fileIds.isEmpty()) return;
+
+ int extEf = 0;
+ // Only call fileIds.get while EFEXT1_TAG is available
+ if (fileIds.containsKey(USIM_EFEXT1_TAG)) {
+ extEf = fileIds.get(USIM_EFEXT1_TAG);
+ }
+
mAdnCache.requestLoadAllAdnLike(fileIds.get(USIM_EFADN_TAG),
- fileIds.get(USIM_EFEXT1_TAG), obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
+ extEf, obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
try {
mLock.wait();
} catch (InterruptedException e) {
diff --git a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
index ed578c8..ad43c30 100644
--- a/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
+++ b/telephony/java/com/android/internal/telephony/sip/SipCommandInterface.java
@@ -193,7 +193,7 @@ class SipCommandInterface extends BaseCommands implements CommandsInterface {
public void setupDataCall(String radioTechnology, String profile,
String apn, String user, String password, String authType,
- Message result) {
+ String protcol, Message result) {
}
public void deactivateDataCall(int cid, Message result) {
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index beec177..1fc09ab 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -960,8 +960,9 @@ public final class SimulatedCommands extends BaseCommands
unimplemented(result);
}
- public void setupDataCall(String radioTechnology, String profile, String apn, String user,
- String password, String authType, Message result) {
+ public void setupDataCall(String radioTechnology, String profile,
+ String apn, String user, String password, String authType,
+ String protocol, Message result) {
unimplemented(result);
}
diff --git a/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/ApnSettingTest.java b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/ApnSettingTest.java
new file mode 100644
index 0000000..15cb3b8
--- /dev/null
+++ b/telephony/tests/telephonytests/src/com/android/internal/telephony/gsm/ApnSettingTest.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.telephony.gsm;
+
+import junit.framework.TestCase;
+
+import android.test.suitebuilder.annotation.SmallTest;
+
+public class ApnSettingTest extends TestCase {
+
+ public static final String[] TYPES = {"default", "*"};
+
+ public static void assertApnSettingEqual(ApnSetting a1, ApnSetting a2) {
+ assertEquals(a1.carrier, a2.carrier);
+ assertEquals(a1.apn, a2.apn);
+ assertEquals(a1.proxy, a2.proxy);
+ assertEquals(a1.port, a2.port);
+ assertEquals(a1.mmsc, a2.mmsc);
+ assertEquals(a1.mmsProxy, a2.mmsProxy);
+ assertEquals(a1.mmsPort, a2.mmsPort);
+ assertEquals(a1.user, a2.user);
+ assertEquals(a1.password, a2.password);
+ assertEquals(a1.authType, a2.authType);
+ assertEquals(a1.id, a2.id);
+ assertEquals(a1.numeric, a2.numeric);
+ assertEquals(a1.protocol, a2.protocol);
+ assertEquals(a1.roamingProtocol, a2.roamingProtocol);
+ assertEquals(a1.types.length, a2.types.length);
+ int i;
+ for (i = 0; i < a1.types.length; i++) {
+ assertEquals(a1.types[i], a2.types[i]);
+ }
+ }
+
+ @SmallTest
+ public void testFromString() throws Exception {
+ String[] dunTypes = {"DUN"};
+ String[] mmsTypes = {"mms", "*"};
+
+ ApnSetting expected_apn;
+ String testString;
+
+ // A real-world v1 example string.
+ testString = "Vodafone IT,web.omnitel.it,,,,,,,,,222,10,,DUN";
+ expected_apn = new ApnSetting(
+ -1, "22210", "Vodafone IT", "web.omnitel.it", "", "",
+ "", "", "", "", "", 0, dunTypes, "IP", "IP");
+ assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
+
+ // A v2 string.
+ testString = "[ApnSettingV2] Name,apn,,,,,,,,,123,45,,mms|*,IPV6,IP";
+ expected_apn = new ApnSetting(
+ -1, "12345", "Name", "apn", "", "",
+ "", "", "", "", "", 0, mmsTypes, "IPV6", "IP");
+ assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
+
+ // A v2 string with spaces.
+ testString = "[ApnSettingV2] Name,apn, ,,,,,,,,123,45,,mms|*,IPV4V6, IP";
+ expected_apn = new ApnSetting(
+ -1, "12345", "Name", "apn", "", "",
+ "", "", "", "", "", 0, mmsTypes, "IPV4V6", "IP");
+ assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
+
+ // Return null if insufficient fields given.
+ testString = "[ApnSettingV2] Name,apn,,,,,,,,,123, 45,,mms|*";
+ assertEquals(null, ApnSetting.fromString(testString));
+
+ testString = "Name,apn,,,,,,,,,123, 45,";
+ assertEquals(null, ApnSetting.fromString(testString));
+
+ // Parse (incorrect) V2 format without the tag as V1.
+ testString = "Name,apn,,,,,,,,,123, 45,,mms|*,IPV6";
+ String[] incorrectTypes = {"mms|*", "IPV6"};
+ expected_apn = new ApnSetting(
+ -1, "12345", "Name", "apn", "", "",
+ "", "", "", "", "", 0, incorrectTypes, "IP", "IP");
+ assertApnSettingEqual(expected_apn, ApnSetting.fromString(testString));
+ }
+
+
+ @SmallTest
+ public void testToString() throws Exception {
+ String[] types = {"default", "*"};
+ ApnSetting apn = new ApnSetting(
+ 99, "12345", "Name", "apn", "proxy", "port",
+ "mmsc", "mmsproxy", "mmsport", "user", "password", 0,
+ types, "IPV4V6", "IP");
+ String expected = "[ApnSettingV2] Name, 99, 12345, apn, proxy, " +
+ "mmsc, mmsproxy, mmsport, port, 0, default | *, " +
+ "IPV4V6, IP";
+ assertEquals(expected, apn.toString());
+ }
+}
+
diff --git a/tools/aapt/Bundle.h b/tools/aapt/Bundle.h
index 15570e4..fa84e93 100644
--- a/tools/aapt/Bundle.h
+++ b/tools/aapt/Bundle.h
@@ -40,6 +40,7 @@ public:
mWantUTF16(false), mValues(false),
mCompressionMethod(0), mOutputAPKFile(NULL),
mManifestPackageNameOverride(NULL), mInstrumentationPackageNameOverride(NULL),
+ mIsOverlayPackage(false),
mAutoAddOverlay(false), mAssetSourceDir(NULL), mProguardFile(NULL),
mAndroidManifestFile(NULL), mPublicOutputFile(NULL),
mRClassDir(NULL), mResourceIntermediatesDir(NULL), mManifestMinSdkVersion(NULL),
@@ -92,6 +93,8 @@ public:
void setManifestPackageNameOverride(const char * val) { mManifestPackageNameOverride = val; }
const char* getInstrumentationPackageNameOverride() const { return mInstrumentationPackageNameOverride; }
void setInstrumentationPackageNameOverride(const char * val) { mInstrumentationPackageNameOverride = val; }
+ bool getIsOverlayPackage() const { return mIsOverlayPackage; }
+ void setIsOverlayPackage(bool val) { mIsOverlayPackage = val; }
bool getAutoAddOverlay() { return mAutoAddOverlay; }
void setAutoAddOverlay(bool val) { mAutoAddOverlay = val; }
@@ -219,6 +222,7 @@ private:
const char* mOutputAPKFile;
const char* mManifestPackageNameOverride;
const char* mInstrumentationPackageNameOverride;
+ bool mIsOverlayPackage;
bool mAutoAddOverlay;
const char* mAssetSourceDir;
const char* mProguardFile;
diff --git a/tools/aapt/Main.cpp b/tools/aapt/Main.cpp
index 266a02f..1e63131 100644
--- a/tools/aapt/Main.cpp
+++ b/tools/aapt/Main.cpp
@@ -68,6 +68,7 @@ void usage(void)
" [-S resource-sources [-S resource-sources ...]] "
" [-F apk-file] [-J R-file-dir] \\\n"
" [--product product1,product2,...] \\\n"
+ " [-o] \\\n"
" [raw-files-dir [raw-files-dir] ...]\n"
"\n"
" Package the android resources. It will read assets and resources that are\n"
@@ -105,6 +106,7 @@ void usage(void)
" -j specify a jar or zip file containing classes to include\n"
" -k junk path of file(s) added\n"
" -m make package directories under location specified by -J\n"
+ " -o create overlay package (ie only resources; expects <overlay-package> in manifest)\n"
#if 0
" -p pseudolocalize the default configuration\n"
#endif
@@ -275,6 +277,9 @@ int main(int argc, char* const argv[])
case 'm':
bundle.setMakePackageDirs(true);
break;
+ case 'o':
+ bundle.setIsOverlayPackage(true);
+ break;
#if 0
case 'p':
bundle.setPseudolocalize(true);
diff --git a/tools/aapt/ResourceTable.cpp b/tools/aapt/ResourceTable.cpp
index 818c3c6..6459d0e 100644
--- a/tools/aapt/ResourceTable.cpp
+++ b/tools/aapt/ResourceTable.cpp
@@ -3674,7 +3674,9 @@ sp<ResourceTable::Package> ResourceTable::getPackage(const String16& package)
{
sp<Package> p = mPackages.valueFor(package);
if (p == NULL) {
- if (mIsAppPackage) {
+ if (mBundle->getIsOverlayPackage()) {
+ p = new Package(package, 0x00);
+ } else if (mIsAppPackage) {
if (mHaveAppPackage) {
fprintf(stderr, "Adding multiple application package resources; only one is allowed.\n"
"Use -x to create extended resources.\n");
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index c0d7427..19248bf 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -504,7 +504,8 @@ void printXMLBlock(ResXMLTree* block)
namespaces.pop();
} else if (code == ResXMLTree::TEXT) {
size_t len;
- printf("%sC: \"%s\"\n", prefix.string(), String8(block->getText(&len)).string());
+ printf("%sC: \"%s\"\n", prefix.string(), ResTable::normalizeForOutput(
+ String8(block->getText(&len)).string()).string());
}
}
diff --git a/tools/layoutlib/.gitignore b/tools/layoutlib/.gitignore
index 0ec5000..c5e82d7 100644
--- a/tools/layoutlib/.gitignore
+++ b/tools/layoutlib/.gitignore
@@ -1,2 +1 @@
-bridge/bin
-create/bin
+bin \ No newline at end of file
diff --git a/tools/layoutlib/README b/tools/layoutlib/README
new file mode 100644
index 0000000..0fea9bd
--- /dev/null
+++ b/tools/layoutlib/README
@@ -0,0 +1,4 @@
+Layoutlib is a custom version of the android View framework designed to run inside Eclipse.
+The goal of the library is to provide layout rendering in Eclipse that are very very close to their rendering on devices.
+
+None of the com.android.* or android.* classes in layoutlib run on devices. \ No newline at end of file
diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath
index 70140d8..9fb000e 100644
--- a/tools/layoutlib/bridge/.classpath
+++ b/tools/layoutlib/bridge/.classpath
@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry excluding="org/kxml2/io/" kind="src" path="src"/>
- <classpathentry kind="src" path="tests"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
- <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
- <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/layoutlib_api/layoutlib_api-prebuilt.jar"/>
- <classpathentry kind="var" path="ANDROID_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_SRC/dalvik/libcore/xml/src/main/java"/>
- <classpathentry kind="var" path="ANDROID_OUT_FRAMEWORK/layoutlib.jar" sourcepath="/ANDROID_SRC/frameworks/base/core/java"/>
- <classpathentry kind="var" path="ANDROID_OUT_FRAMEWORK/ninepatch.jar" sourcepath="/ANDROID_SRC/development/tools/ninepatch/src"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/layoutlib_api/layoutlib_api-prebuilt.jar"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/ninepatch/ninepatch-prebuilt.jar"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/tools-common/tools-common-prebuilt.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index b7a602a..687a91f 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -17,15 +17,22 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_JAVA_RESOURCE_DIRS := resources
+
LOCAL_JAVA_LIBRARIES := \
kxml2-2.3.0 \
layoutlib_api-prebuilt \
- ninepatch
+ tools-common-prebuilt
-LOCAL_STATIC_JAVA_LIBRARIES := temp_layoutlib
+LOCAL_STATIC_JAVA_LIBRARIES := \
+ temp_layoutlib \
+ ninepatch-prebuilt
LOCAL_MODULE := layoutlib
include $(BUILD_HOST_JAVA_LIBRARY)
+# Build all sub-directories
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_wifi_signal_4_fully.png
new file mode 100644
index 0000000..bd44b52
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/hdpi/status_bar_background.9.png b/tools/layoutlib/bridge/resources/bars/hdpi/status_bar_background.9.png
new file mode 100644
index 0000000..a4be298
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/hdpi/status_bar_background.9.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.png b/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.png
new file mode 100644
index 0000000..c629387
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/stat_sys_wifi_signal_4_fully.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/mdpi/status_bar_background.9.png b/tools/layoutlib/bridge/resources/bars/mdpi/status_bar_background.9.png
new file mode 100644
index 0000000..eb7c1a4
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/mdpi/status_bar_background.9.png
Binary files differ
diff --git a/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml b/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
new file mode 100644
index 0000000..d3c492e
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_weight="1"/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"/>
+ <ImageView
+ android:layout_height="wrap_content"
+ android:layout_width="wrap_content"
+ android:layout_marginLeft="3dip"
+ android:layout_marginRight="5dip"/>
+</merge>
diff --git a/tools/layoutlib/bridge/resources/bars/title_bar.xml b/tools/layoutlib/bridge/resources/bars/title_bar.xml
new file mode 100644
index 0000000..76d78d9
--- /dev/null
+++ b/tools/layoutlib/bridge/resources/bars/title_bar.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"/>
+</merge>
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
new file mode 100644
index 0000000..413894b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.res;
+
+import com.android.layoutlib.bridge.impl.RenderSessionImpl;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link Theme}
+ *
+ * Through the layoutlib_create tool, the original methods of Theme have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class Resources_Theme_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static TypedArray obtainStyledAttributes(
+ Resources thisResources, Theme thisTheme,
+ int[] attrs) {
+ return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static TypedArray obtainStyledAttributes(
+ Resources thisResources, Theme thisTheme,
+ int resid, int[] attrs)
+ throws NotFoundException {
+ return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid, attrs);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static TypedArray obtainStyledAttributes(
+ Resources thisResources, Theme thisTheme,
+ AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
+ return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(
+ set, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean resolveAttribute(
+ Resources thisResources, Theme thisTheme,
+ int resid, TypedValue outValue,
+ boolean resolveRefs) {
+ return RenderSessionImpl.getCurrentContext().resolveThemeAttribute(
+ resid, outValue, resolveRefs);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
new file mode 100644
index 0000000..a50a2bd
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Composite;
+
+/**
+ * Delegate implementing the native methods of android.graphics.AvoidXfermode
+ *
+ * Through the layoutlib_create tool, the original native methods of AvoidXfermode have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original AvoidXfermode class.
+ *
+ * Because this extends {@link Xfermode_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
+ * {@link Xfermode_Delegate}.
+ *
+ */
+public class AvoidXfermode_Delegate extends Xfermode_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Composite getComposite(int alpha) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Avoid Xfermodes are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int opColor, int tolerance, int nativeMode) {
+ AvoidXfermode_Delegate newDelegate = new AvoidXfermode_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
deleted file mode 100644
index 35f022e..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * 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 java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.imageio.ImageIO;
-
-public final class Bitmap extends _Original_Bitmap {
-
- private BufferedImage mImage;
-
- public Bitmap(File input) throws IOException {
- super(1, true, null, -1);
-
- mImage = ImageIO.read(input);
- }
-
- public Bitmap(InputStream is) throws IOException {
- super(1, true, null, -1);
-
- mImage = ImageIO.read(is);
- }
-
- Bitmap(BufferedImage image) {
- super(1, true, null, -1);
- mImage = image;
- }
-
- public BufferedImage getImage() {
- return mImage;
- }
-
- // ----- overriden methods
-
- public enum Config {
- // these native values must match up with the enum in SkBitmap.h
- ALPHA_8 (2),
- RGB_565 (4),
- ARGB_4444 (5),
- ARGB_8888 (6);
-
- Config(int ni) {
- this.nativeInt = ni;
- }
- final int nativeInt;
-
- /* package */ static Config nativeToConfig(int ni) {
- return sConfigs[ni];
- }
-
- private static Config sConfigs[] = {
- null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
- };
- }
-
- @Override
- public int getWidth() {
- return mImage.getWidth();
- }
-
- @Override
- public int getHeight() {
- return mImage.getHeight();
- }
-
- /**
- * Returns an immutable bitmap from the source bitmap. The new bitmap may
- * be the same object as source, or a copy may have been made.
- */
- public static Bitmap createBitmap(Bitmap src) {
- return createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), null, false);
- }
-
- /**
- * Returns an immutable bitmap from the specified subset of the source
- * bitmap. The new bitmap may be the same object as source, or a copy may
- * have been made.
- *
- * @param source The bitmap we are subsetting
- * @param x The x coordinate of the first pixel in source
- * @param y The y coordinate of the first pixel in source
- * @param width The number of pixels in each row
- * @param height The number of rows
- */
- public static Bitmap createBitmap(Bitmap source, int x, int y,
- int width, int height) {
- return new Bitmap(source.mImage.getSubimage(x, y, width, height));
- }
-
- /**
- * Returns an immutable bitmap from subset of the source bitmap,
- * transformed by the optional matrix.
- *
- * @param source The bitmap we are subsetting
- * @param x The x coordinate of the first pixel in source
- * @param y The y coordinate of the first pixel in source
- * @param width The number of pixels in each row
- * @param height The number of rows
- * @param m Option matrix to be applied to the pixels
- * @param filter true if the source should be filtered.
- * Only applies if the matrix contains more than just
- * translation.
- * @return A bitmap that represents the specified subset of source
- * @throws IllegalArgumentException if the x, y, width, height values are
- * outside of the dimensions of the source bitmap.
- */
- public static Bitmap createBitmap(Bitmap source, int x, int y, int width,
- int height, Matrix m, boolean filter) {
- checkXYSign(x, y);
- checkWidthHeight(width, height);
- if (x + width > source.getWidth()) {
- throw new IllegalArgumentException(
- "x + width must be <= bitmap.width()");
- }
- if (y + height > source.getHeight()) {
- throw new IllegalArgumentException(
- "y + height must be <= bitmap.height()");
- }
-
- // check if we can just return our argument unchanged
- if (!source.isMutable() && x == 0 && y == 0
- && width == source.getWidth() && height == source.getHeight()
- && (m == null || m.isIdentity())) {
- return source;
- }
-
- if (m == null || m.isIdentity()) {
- return new Bitmap(source.mImage.getSubimage(x, y, width, height));
- }
-
- int neww = width;
- int newh = height;
- Paint paint;
-
- Rect srcR = new Rect(x, y, x + width, y + height);
- RectF dstR = new RectF(0, 0, width, height);
-
- /* the dst should have alpha if the src does, or if our matrix
- doesn't preserve rectness
- */
- boolean hasAlpha = source.hasAlpha() || !m.rectStaysRect();
- RectF deviceR = new RectF();
- m.mapRect(deviceR, dstR);
- neww = Math.round(deviceR.width());
- newh = Math.round(deviceR.height());
-
- Canvas canvas = new Canvas(neww, newh);
-
- canvas.translate(-deviceR.left, -deviceR.top);
- canvas.concat(m);
- paint = new Paint();
- paint.setFilterBitmap(filter);
- if (!m.rectStaysRect()) {
- paint.setAntiAlias(true);
- }
-
- canvas.drawBitmap(source, srcR, dstR, paint);
-
- return new Bitmap(canvas.getImage());
- }
-
- /**
- * Returns a mutable bitmap with the specified width and height.
- *
- * @param width The width of the bitmap
- * @param height The height of the bitmap
- * @param config The bitmap config to create.
- * @throws IllegalArgumentException if the width or height are <= 0
- */
- public static Bitmap createBitmap(int width, int height, Config config) {
- return new Bitmap(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB));
- }
-
- /**
- * Returns a immutable bitmap with the specified width and height, with each
- * pixel value set to the corresponding value in the colors array.
- *
- * @param colors Array of {@link Color} used to initialize the pixels.
- * @param offset Number of values to skip before the first color in the
- * array of colors.
- * @param stride Number of colors in the array between rows (must be >=
- * width or <= -width).
- * @param width The width of the bitmap
- * @param height The height of the bitmap
- * @param config The bitmap config to create. If the config does not
- * support per-pixel alpha (e.g. RGB_565), then the alpha
- * bytes in the colors[] will be ignored (assumed to be FF)
- * @throws IllegalArgumentException if the width or height are <= 0, or if
- * the color array's length is less than the number of pixels.
- */
- public static Bitmap createBitmap(int colors[], int offset, int stride,
- int width, int height, Config config) {
- checkWidthHeight(width, height);
- if (Math.abs(stride) < width) {
- throw new IllegalArgumentException("abs(stride) must be >= width");
- }
- int lastScanline = offset + (height - 1) * stride;
- int length = colors.length;
- if (offset < 0 || (offset + width > length)
- || lastScanline < 0
- || (lastScanline + width > length)) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // TODO: create an immutable bitmap...
- throw new UnsupportedOperationException();
- }
-
- /**
- * Returns a immutable bitmap with the specified width and height, with each
- * pixel value set to the corresponding value in the colors array.
- *
- * @param colors Array of {@link Color} used to initialize the pixels.
- * This array must be at least as large as width * height.
- * @param width The width of the bitmap
- * @param height The height of the bitmap
- * @param config The bitmap config to create. If the config does not
- * support per-pixel alpha (e.g. RGB_565), then the alpha
- * bytes in the colors[] will be ignored (assumed to be FF)
- * @throws IllegalArgumentException if the width or height are <= 0, or if
- * the color array's length is less than the number of pixels.
- */
- public static Bitmap createBitmap(int colors[], int width, int height,
- Config config) {
- return createBitmap(colors, 0, width, width, height, config);
- }
-
- public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
- int dstHeight, boolean filter) {
- Matrix m;
- synchronized (Bitmap.class) {
- // small pool of just 1 matrix
- m = sScaleMatrix;
- sScaleMatrix = null;
- }
-
- if (m == null) {
- m = new Matrix();
- }
-
- final int width = src.getWidth();
- final int height = src.getHeight();
- final float sx = dstWidth / (float)width;
- final float sy = dstHeight / (float)height;
- m.setScale(sx, sy);
- Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
-
- synchronized (Bitmap.class) {
- // do we need to check for null? why not just assign everytime?
- if (sScaleMatrix == null) {
- sScaleMatrix = m;
- }
- }
-
- return b;
- }
-
-
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
deleted file mode 100644
index e978fe8..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-import android.content.res.AssetManager;
-import android.content.res.Resources;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-
-import java.io.BufferedInputStream;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Creates Bitmap objects from various sources, including files, streams,
- * and byte-arrays.
- */
-public class BitmapFactory {
- public static class Options {
- /**
- * Create a default Options object, which if left unchanged will give
- * the same result from the decoder as if null were passed.
- */
- public Options() {
- inDither = true;
- inScaled = true;
- }
-
- /**
- * If set to true, the decoder will return null (no bitmap), but
- * the out... fields will still be set, allowing the caller to query
- * the bitmap without having to allocate the memory for its pixels.
- */
- public boolean inJustDecodeBounds;
-
- /**
- * If set to a value > 1, requests the decoder to subsample the original
- * image, returning a smaller image to save memory. The sample size is
- * the number of pixels in either dimension that correspond to a single
- * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
- * an image that is 1/4 the width/height of the original, and 1/16 the
- * number of pixels. Any value <= 1 is treated the same as 1. Note: the
- * decoder will try to fulfill this request, but the resulting bitmap
- * may have different dimensions that precisely what has been requested.
- * Also, powers of 2 are often faster/easier for the decoder to honor.
- */
- public int inSampleSize;
-
- /**
- * If this is non-null, the decoder will try to decode into this
- * internal configuration. If it is null, or the request cannot be met,
- * the decoder will try to pick the best matching config based on the
- * system's screen depth, and characteristics of the original image such
- * as if it has per-pixel alpha (requiring a config that also does).
- */
- public Bitmap.Config inPreferredConfig;
-
- /**
- * If dither is true, the decoder will attempt to dither the decoded
- * image.
- */
- public boolean inDither;
-
- /**
- * The pixel density to use for the bitmap. This will always result
- * in the returned bitmap having a density set for it (see
- * {@link Bitmap#setDensity(int) Bitmap.setDensity(int)). In addition,
- * if {@link #inScaled} is set (which it is by default} and this
- * density does not match {@link #inTargetDensity}, then the bitmap
- * will be scaled to the target density before being returned.
- *
- * <p>If this is 0,
- * {@link BitmapFactory#decodeResource(Resources, int)},
- * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
- * and {@link BitmapFactory#decodeResourceStream}
- * will fill in the density associated with the resource. The other
- * functions will leave it as-is and no density will be applied.
- *
- * @see #inTargetDensity
- * @see #inScreenDensity
- * @see #inScaled
- * @see Bitmap#setDensity(int)
- * @see android.util.DisplayMetrics#densityDpi
- */
- public int inDensity;
-
- /**
- * The pixel density of the destination this bitmap will be drawn to.
- * This is used in conjunction with {@link #inDensity} and
- * {@link #inScaled} to determine if and how to scale the bitmap before
- * returning it.
- *
- * <p>If this is 0,
- * {@link BitmapFactory#decodeResource(Resources, int)},
- * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
- * and {@link BitmapFactory#decodeResourceStream}
- * will fill in the density associated the Resources object's
- * DisplayMetrics. The other
- * functions will leave it as-is and no scaling for density will be
- * performed.
- *
- * @see #inDensity
- * @see #inScreenDensity
- * @see #inScaled
- * @see android.util.DisplayMetrics#densityDpi
- */
- public int inTargetDensity;
-
- /**
- * The pixel density of the actual screen that is being used. This is
- * purely for applications running in density compatibility code, where
- * {@link #inTargetDensity} is actually the density the application
- * sees rather than the real screen density.
- *
- * <p>By setting this, you
- * allow the loading code to avoid scaling a bitmap that is currently
- * in the screen density up/down to the compatibility density. Instead,
- * if {@link #inDensity} is the same as {@link #inScreenDensity}, the
- * bitmap will be left as-is. Anything using the resulting bitmap
- * must also used {@link Bitmap#getScaledWidth(int)
- * Bitmap.getScaledWidth} and {@link Bitmap#getScaledHeight
- * Bitmap.getScaledHeight} to account for any different between the
- * bitmap's density and the target's density.
- *
- * <p>This is never set automatically for the caller by
- * {@link BitmapFactory} itself. It must be explicitly set, since the
- * caller must deal with the resulting bitmap in a density-aware way.
- *
- * @see #inDensity
- * @see #inTargetDensity
- * @see #inScaled
- * @see android.util.DisplayMetrics#densityDpi
- */
- public int inScreenDensity;
-
- /**
- * When this flag is set, if {@link #inDensity} and
- * {@link #inTargetDensity} are not 0, the
- * bitmap will be scaled to match {@link #inTargetDensity} when loaded,
- * rather than relying on the graphics system scaling it each time it
- * is drawn to a Canvas.
- *
- * <p>This flag is turned on by default and should be turned off if you need
- * a non-scaled version of the bitmap. Nine-patch bitmaps ignore this
- * flag and are always scaled.
- */
- public boolean inScaled;
-
- /**
- * If this is set to true, then the resulting bitmap will allocate its
- * pixels such that they can be purged if the system needs to reclaim
- * memory. In that instance, when the pixels need to be accessed again
- * (e.g. the bitmap is drawn, getPixels() is called), they will be
- * automatically re-decoded.
- *
- * For the re-decode to happen, the bitmap must have access to the
- * encoded data, either by sharing a reference to the input
- * or by making a copy of it. This distinction is controlled by
- * inInputShareable. If this is true, then the bitmap may keep a shallow
- * reference to the input. If this is false, then the bitmap will
- * explicitly make a copy of the input data, and keep that. Even if
- * sharing is allowed, the implementation may still decide to make a
- * deep copy of the input data.
- */
- public boolean inPurgeable;
-
- /**
- * This field works in conjuction with inPurgeable. If inPurgeable is
- * false, then this field is ignored. If inPurgeable is true, then this
- * field determines whether the bitmap can share a reference to the
- * input data (inputstream, array, etc.) or if it must make a deep copy.
- */
- public boolean inInputShareable;
-
- /**
- * Normally bitmap allocations count against the dalvik heap, which
- * means they help trigger GCs when a lot have been allocated. However,
- * in rare cases, the caller may want to allocate the bitmap outside of
- * that heap. To request that, set inNativeAlloc to true. In these
- * rare instances, it is solely up to the caller to ensure that OOM is
- * managed explicitly by calling bitmap.recycle() as soon as such a
- * bitmap is no longer needed.
- *
- * @hide pending API council approval
- */
- public boolean inNativeAlloc;
-
- /**
- * The resulting width of the bitmap, set independent of the state of
- * inJustDecodeBounds. However, if there is an error trying to decode,
- * outWidth will be set to -1.
- */
- public int outWidth;
-
- /**
- * The resulting height of the bitmap, set independent of the state of
- * inJustDecodeBounds. However, if there is an error trying to decode,
- * outHeight will be set to -1.
- */
- public int outHeight;
-
- /**
- * If known, this string is set to the mimetype of the decoded image.
- * If not know, or there is an error, it is set to null.
- */
- public String outMimeType;
-
- /**
- * Temp storage to use for decoding. Suggest 16K or so.
- */
- public byte[] inTempStorage;
-
- private native void requestCancel();
-
- /**
- * Flag to indicate that cancel has been called on this object. This
- * is useful if there's an intermediary that wants to first decode the
- * bounds and then decode the image. In that case the intermediary
- * can check, inbetween the bounds decode and the image decode, to see
- * if the operation is canceled.
- */
- public boolean mCancel;
-
- /**
- * This can be called from another thread while this options object is
- * inside a decode... call. Calling this will notify the decoder that
- * it should cancel its operation. This is not guaranteed to cancel
- * the decode, but if it does, the decoder... operation will return
- * null, or if inJustDecodeBounds is true, will set outWidth/outHeight
- * to -1
- */
- public void requestCancelDecode() {
- mCancel = true;
- requestCancel();
- }
- }
-
- /**
- * Decode a file path into a bitmap. If the specified file name is null,
- * or cannot be decoded into a bitmap, the function returns null.
- *
- * @param pathName complete path name for the file to be decoded.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeFile(String pathName, Options opts) {
- Bitmap bm = null;
- InputStream stream = null;
- try {
- stream = new FileInputStream(pathName);
- bm = decodeStream(stream, null, opts);
- } catch (Exception e) {
- /* do nothing.
- If the exception happened on open, bm will be null.
- */
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- // do nothing here
- }
- }
- }
- return bm;
- }
-
- /**
- * Decode a file path into a bitmap. If the specified file name is null,
- * or cannot be decoded into a bitmap, the function returns null.
- *
- * @param pathName complete path name for the file to be decoded.
- * @return the resulting decoded bitmap, or null if it could not be decoded.
- */
- public static Bitmap decodeFile(String pathName) {
- return decodeFile(pathName, null);
- }
-
- /**
- * Decode a new Bitmap from an InputStream. This InputStream was obtained from
- * resources, which we pass to be able to scale the bitmap accordingly.
- */
- public static Bitmap decodeResourceStream(Resources res, TypedValue value,
- InputStream is, Rect pad, Options opts) {
-
- if (opts == null) {
- opts = new Options();
- }
-
- if (opts.inDensity == 0 && value != null) {
- final int density = value.density;
- if (density == TypedValue.DENSITY_DEFAULT) {
- opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
- } else if (density != TypedValue.DENSITY_NONE) {
- opts.inDensity = density;
- }
- }
-
- if (opts.inTargetDensity == 0 && res != null) {
- opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
- }
-
- return decodeStream(is, pad, opts);
- }
-
- /**
- * Synonym for opening the given resource and calling
- * {@link #decodeResourceStream}.
- *
- * @param res The resources object containing the image data
- * @param id The resource id of the image data
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeResource(Resources res, int id, Options opts) {
- Bitmap bm = null;
- InputStream is = null;
-
- try {
- final TypedValue value = new TypedValue();
- is = res.openRawResource(id, value);
-
- bm = decodeResourceStream(res, value, is, null, opts);
- } catch (Exception e) {
- /* do nothing.
- If the exception happened on open, bm will be null.
- If it happened on close, bm is still valid.
- */
- } finally {
- try {
- if (is != null) is.close();
- } catch (IOException e) {
- // Ignore
- }
- }
-
- return bm;
- }
-
- /**
- * Synonym for {@link #decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}
- * will null Options.
- *
- * @param res The resources object containing the image data
- * @param id The resource id of the image data
- * @return The decoded bitmap, or null if the image could not be decode.
- */
- public static Bitmap decodeResource(Resources res, int id) {
- return decodeResource(res, id, null);
- }
-
- /**
- * Decode an immutable bitmap from the specified byte array.
- *
- * @param data byte array of compressed image data
- * @param offset offset into imageData for where the decoder should begin
- * parsing.
- * @param length the number of bytes, beginning at offset, to parse
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
- if ((offset | length) < 0 || data.length < offset + length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // FIXME: implement as needed, but it's unlikely that this is needed in the context of the bridge.
- return null;
- //return nativeDecodeByteArray(data, offset, length, opts);
- }
-
- /**
- * Decode an immutable bitmap from the specified byte array.
- *
- * @param data byte array of compressed image data
- * @param offset offset into imageData for where the decoder should begin
- * parsing.
- * @param length the number of bytes, beginning at offset, to parse
- * @return The decoded bitmap, or null if the image could not be decode.
- */
- public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
- return decodeByteArray(data, offset, length, null);
- }
-
- /**
- * Decode an input stream into a bitmap. If the input stream is null, or
- * cannot be used to decode a bitmap, the function returns null.
- * The stream's position will be where ever it was after the encoded data
- * was read.
- *
- * @param is The input stream that holds the raw data to be decoded into a
- * bitmap.
- * @param outPadding If not null, return the padding rect for the bitmap if
- * it exists, otherwise set padding to [-1,-1,-1,-1]. If
- * no bitmap is returned (null) then padding is
- * unchanged.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
- // we don't throw in this case, thus allowing the caller to only check
- // the cache, and not force the image to be decoded.
- if (is == null) {
- return null;
- }
-
- // we need mark/reset to work properly
-
- if (!is.markSupported()) {
- is = new BufferedInputStream(is, 16 * 1024);
- }
-
- // so we can call reset() if a given codec gives up after reading up to
- // this many bytes. FIXME: need to find out from the codecs what this
- // value should be.
- is.mark(1024);
-
- Bitmap bm;
-
- if (is instanceof AssetManager.AssetInputStream) {
- // FIXME: log this.
- return null;
- } else {
- // pass some temp storage down to the native code. 1024 is made up,
- // but should be large enough to avoid too many small calls back
- // into is.read(...) This number is not related to the value passed
- // to mark(...) above.
- try {
- bm = new Bitmap(is);
- } catch (IOException e) {
- return null;
- }
- }
-
- return finishDecode(bm, outPadding, opts);
- }
-
- private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
- if (bm == null || opts == null) {
- return bm;
- }
-
- final int density = opts.inDensity;
- if (density == 0) {
- return bm;
- }
-
- bm.setDensity(density);
- final int targetDensity = opts.inTargetDensity;
- if (targetDensity == 0 || density == targetDensity
- || density == opts.inScreenDensity) {
- return bm;
- }
-
- byte[] np = bm.getNinePatchChunk();
- final boolean isNinePatch = false; //np != null && NinePatch.isNinePatchChunk(np);
- if (opts.inScaled || isNinePatch) {
- float scale = targetDensity / (float)density;
- // TODO: This is very inefficient and should be done in native by Skia
- final Bitmap oldBitmap = bm;
- bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
- (int) (bm.getHeight() * scale + 0.5f), true);
- oldBitmap.recycle();
-
- if (isNinePatch) {
- //np = nativeScaleNinePatch(np, scale, outPadding);
- bm.setNinePatchChunk(np);
- }
- bm.setDensity(targetDensity);
- }
-
- return bm;
- }
-
- /**
- * Decode an input stream into a bitmap. If the input stream is null, or
- * cannot be used to decode a bitmap, the function returns null.
- * The stream's position will be where ever it was after the encoded data
- * was read.
- *
- * @param is The input stream that holds the raw data to be decoded into a
- * bitmap.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeStream(InputStream is) {
- return decodeStream(is, null, null);
- }
-
- /**
- * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
- * return null. The position within the descriptor will not be changed when
- * this returns, so the descriptor can be used again as-is.
- *
- * @param fd The file descriptor containing the bitmap data to decode
- * @param outPadding If not null, return the padding rect for the bitmap if
- * it exists, otherwise set padding to [-1,-1,-1,-1]. If
- * no bitmap is returned (null) then padding is
- * unchanged.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return the decoded bitmap, or null
- */
- public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
- return null;
-
- /* FIXME: implement as needed
- try {
- if (MemoryFile.isMemoryFile(fd)) {
- int mappedlength = MemoryFile.getMappedSize(fd);
- MemoryFile file = new MemoryFile(fd, mappedlength, "r");
- InputStream is = file.getInputStream();
- Bitmap bm = decodeStream(is, outPadding, opts);
- return finishDecode(bm, outPadding, opts);
- }
- } catch (IOException ex) {
- // invalid filedescriptor, no need to call nativeDecodeFileDescriptor()
- return null;
- }
- //Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
- //return finishDecode(bm, outPadding, opts);
- */
- }
-
- /**
- * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
- * return null. The position within the descriptor will not be changed when
- * this returns, so the descriptor can be used again as is.
- *
- * @param fd The file descriptor containing the bitmap data to decode
- * @return the decoded bitmap, or null
- */
- public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
- return decodeFileDescriptor(fd, null, null);
- }
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
new file mode 100644
index 0000000..9c86e80
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeResources.NinePatchInputStream;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.ninepatch.NinePatchChunk;
+import com.android.resources.Density;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.BitmapFactory.Options;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Delegate implementing the native methods of android.graphics.BitmapFactory
+ *
+ * Through the layoutlib_create tool, the original native methods of BitmapFactory have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ */
+/*package*/ class BitmapFactory_Delegate {
+
+ // ------ Java delegates ------
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
+ if (bm == null || opts == null) {
+ return bm;
+ }
+
+ final int density = opts.inDensity;
+ if (density == 0) {
+ return bm;
+ }
+
+ bm.setDensity(density);
+ final int targetDensity = opts.inTargetDensity;
+ if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
+ return bm;
+ }
+
+ byte[] np = bm.getNinePatchChunk();
+ final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
+ // DELEGATE CHANGE: never scale 9-patch
+ if (opts.inScaled && isNinePatch == false) {
+ float scale = targetDensity / (float)density;
+ // TODO: This is very inefficient and should be done in native by Skia
+ final Bitmap oldBitmap = bm;
+ bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
+ (int) (bm.getHeight() * scale + 0.5f), true);
+ oldBitmap.recycle();
+
+ if (isNinePatch) {
+ np = nativeScaleNinePatch(np, scale, outPadding);
+ bm.setNinePatchChunk(np);
+ }
+ bm.setDensity(targetDensity);
+ }
+
+ return bm;
+ }
+
+
+ // ------ Native Delegates ------
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetDefaultConfig(int nativeConfig) {
+ // pass
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage,
+ Rect padding, Options opts) {
+ Bitmap bm = null;
+
+ Density density = Density.MEDIUM;
+ if (opts != null) {
+ density = Density.getEnum(opts.inDensity);
+ }
+
+ try {
+ if (is instanceof NinePatchInputStream) {
+ NinePatchInputStream npis = (NinePatchInputStream) is;
+ npis.disableFakeMarkSupport();
+
+ // load the bitmap as a nine patch
+ com.android.ninepatch.NinePatch ninePatch = com.android.ninepatch.NinePatch.load(
+ npis, true /*is9Patch*/, false /*convert*/);
+
+ // get the bitmap and chunk objects.
+ bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(), true /*isMutable*/,
+ density);
+ NinePatchChunk chunk = ninePatch.getChunk();
+
+ // put the chunk in the bitmap
+ bm.setNinePatchChunk(NinePatch_Delegate.serialize(chunk));
+
+ // read the padding
+ int[] paddingarray = chunk.getPadding();
+ padding.left = paddingarray[0];
+ padding.top = paddingarray[1];
+ padding.right = paddingarray[2];
+ padding.bottom = paddingarray[3];
+ } else {
+ // load the bitmap directly.
+ bm = Bitmap_Delegate.createBitmap(is, true, density);
+ }
+ } catch (IOException e) {
+ Bridge.getLog().error(null,"Failed to load image" , e, null);
+ }
+
+ return bm;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
+ Rect padding, Options opts) {
+ return null;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts) {
+ return null;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset,
+ int length, Options opts) {
+ return null;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad) {
+ // don't scale for now. This should not be called anyway since we re-implement
+ // BitmapFactory.finishDecode();
+ return chunk;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader.java
deleted file mode 100644
index ad3974c..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * 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 java.awt.Paint;
-
-public class BitmapShader extends Shader {
-
- // we hold on just for the GC, since our native counterpart is using it
- private final Bitmap mBitmap;
-
- /**
- * Call this to create a new shader that will draw with a bitmap.
- *
- * @param bitmap The bitmap to use inside the shader
- * @param tileX The tiling mode for x to draw the bitmap in.
- * @param tileY The tiling mode for y to draw the bitmap in.
- */
- public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
- mBitmap = bitmap;
- }
-
- //---------- Custom methods
-
- public Bitmap getBitmap() {
- return mBitmap;
- }
-
- @Override
- Paint getJavaPaint() {
- return null;
- }
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
new file mode 100644
index 0000000..8eb0693
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -0,0 +1,240 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Shader.TileMode;
+
+/**
+ * Delegate implementing the native methods of android.graphics.BitmapShader
+ *
+ * Through the layoutlib_create tool, the original native methods of BitmapShader have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original BitmapShader class.
+ *
+ * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
+ *
+ * @see Shader_Delegate
+ *
+ */
+public class BitmapShader_Delegate extends Shader_Delegate {
+
+ // ---- delegate data ----
+ private java.awt.Paint mJavaPaint;
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public java.awt.Paint getJavaPaint() {
+ return mJavaPaint;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ // no message since isSupported returns true;
+ return null;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int native_bitmap, int shaderTileModeX,
+ int shaderTileModeY) {
+ Bitmap_Delegate bitmap = Bitmap_Delegate.getDelegate(native_bitmap);
+ if (bitmap == null) {
+ return 0;
+ }
+
+ BitmapShader_Delegate newDelegate = new BitmapShader_Delegate(
+ bitmap.getImage(),
+ Shader_Delegate.getTileMode(shaderTileModeX),
+ Shader_Delegate.getTileMode(shaderTileModeY));
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private BitmapShader_Delegate(java.awt.image.BufferedImage image,
+ TileMode tileModeX, TileMode tileModeY) {
+ mJavaPaint = new BitmapShaderPaint(image, tileModeX, tileModeY);
+ }
+
+ private class BitmapShaderPaint implements java.awt.Paint {
+ private final java.awt.image.BufferedImage mImage;
+ private final TileMode mTileModeX;
+ private final TileMode mTileModeY;
+
+ BitmapShaderPaint(java.awt.image.BufferedImage image,
+ TileMode tileModeX, TileMode tileModeY) {
+ mImage = image;
+ mTileModeX = tileModeX;
+ mTileModeY = tileModeY;
+ }
+
+ public java.awt.PaintContext createContext(
+ java.awt.image.ColorModel colorModel,
+ java.awt.Rectangle deviceBounds,
+ java.awt.geom.Rectangle2D userBounds,
+ java.awt.geom.AffineTransform xform,
+ java.awt.RenderingHints hints) {
+
+ java.awt.geom.AffineTransform canvasMatrix;
+ try {
+ canvasMatrix = xform.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in BitmapShader", e, null /*data*/);
+ canvasMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
+ try {
+ localMatrix = localMatrix.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in BitmapShader", e, null /*data*/);
+ localMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ return new BitmapShaderContext(canvasMatrix, localMatrix, colorModel);
+ }
+
+ private class BitmapShaderContext implements java.awt.PaintContext {
+
+ private final java.awt.geom.AffineTransform mCanvasMatrix;
+ private final java.awt.geom.AffineTransform mLocalMatrix;
+ private final java.awt.image.ColorModel mColorModel;
+
+ public BitmapShaderContext(
+ java.awt.geom.AffineTransform canvasMatrix,
+ java.awt.geom.AffineTransform localMatrix,
+ java.awt.image.ColorModel colorModel) {
+ mCanvasMatrix = canvasMatrix;
+ mLocalMatrix = localMatrix;
+ mColorModel = colorModel;
+ }
+
+ public void dispose() {
+ }
+
+ public java.awt.image.ColorModel getColorModel() {
+ return mColorModel;
+ }
+
+ public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
+ java.awt.image.BufferedImage.TYPE_INT_ARGB);
+
+ int[] data = new int[w*h];
+
+ int index = 0;
+ float[] pt1 = new float[2];
+ float[] pt2 = new float[2];
+ for (int iy = 0 ; iy < h ; iy++) {
+ for (int ix = 0 ; ix < w ; ix++) {
+ // handle the canvas transform
+ pt1[0] = x + ix;
+ pt1[1] = y + iy;
+ mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ // handle the local matrix.
+ pt1[0] = pt2[0];
+ pt1[1] = pt2[1];
+ mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ data[index++] = getColor(pt2[0], pt2[1]);
+ }
+ }
+
+ image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
+
+ return image.getRaster();
+ }
+ }
+
+ /**
+ * Returns a color for an arbitrary point.
+ */
+ private int getColor(float fx, float fy) {
+ int x = getCoordinate(Math.round(fx), mImage.getWidth(), mTileModeX);
+ int y = getCoordinate(Math.round(fy), mImage.getHeight(), mTileModeY);
+
+ return mImage.getRGB(x, y);
+ }
+
+ private int getCoordinate(int i, int size, TileMode mode) {
+ if (i < 0) {
+ switch (mode) {
+ case CLAMP:
+ i = 0;
+ break;
+ case REPEAT:
+ i = size - 1 - (-i % size);
+ break;
+ case MIRROR:
+ // this is the same as the positive side, just make the value positive
+ // first.
+ i = -i;
+ int count = i / size;
+ i = i % size;
+
+ if ((count % 2) == 1) {
+ i = size - 1 - i;
+ }
+ break;
+ }
+ } else if (i >= size) {
+ switch (mode) {
+ case CLAMP:
+ i = size - 1;
+ break;
+ case REPEAT:
+ i = i % size;
+ break;
+ case MIRROR:
+ int count = i / size;
+ i = i % size;
+
+ if ((count % 2) == 1) {
+ i = size - 1 - i;
+ }
+ break;
+ }
+ }
+
+ return i;
+ }
+
+
+ public int getTransparency() {
+ return java.awt.Paint.TRANSLUCENT;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
new file mode 100644
index 0000000..87c3eb6
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -0,0 +1,542 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.resources.Density;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.os.Parcel;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.Buffer;
+import java.util.Arrays;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Bitmap
+ *
+ * Through the layoutlib_create tool, the original native methods of Bitmap have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Bitmap class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Bitmap_Delegate {
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Bitmap_Delegate> sManager =
+ new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+ private final Config mConfig;
+ private BufferedImage mImage;
+ private boolean mHasAlpha = true;
+
+ // ---- Public Helper methods ----
+
+ /**
+ * Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
+ */
+ public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
+ return sManager.getDelegate(bitmap.mNativeBitmap);
+ }
+
+ /**
+ * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
+ */
+ public static Bitmap_Delegate getDelegate(int native_bitmap) {
+ return sManager.getDelegate(native_bitmap);
+ }
+
+ /**
+ * Creates and returns a {@link Bitmap} initialized with the given file content.
+ *
+ * @param input the file from which to read the bitmap content
+ * @param isMutable whether the bitmap is mutable
+ * @param density the density associated with the bitmap
+ *
+ * @see Bitmap#isMutable()
+ * @see Bitmap#getDensity()
+ */
+ public static Bitmap createBitmap(File input, boolean isMutable, Density density)
+ throws IOException {
+ // create a delegate with the content of the file.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
+
+ return createBitmap(delegate, isMutable, density.getDpiValue());
+ }
+
+ /**
+ * Creates and returns a {@link Bitmap} initialized with the given stream content.
+ *
+ * @param input the stream from which to read the bitmap content
+ * @param isMutable whether the bitmap is mutable
+ * @param density the density associated with the bitmap
+ *
+ * @see Bitmap#isMutable()
+ * @see Bitmap#getDensity()
+ */
+ public static Bitmap createBitmap(InputStream input, boolean isMutable, Density density)
+ throws IOException {
+ // create a delegate with the content of the stream.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
+
+ return createBitmap(delegate, isMutable, density.getDpiValue());
+ }
+
+ /**
+ * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
+ *
+ * @param image the bitmap content
+ * @param isMutable whether the bitmap is mutable
+ * @param density the density associated with the bitmap
+ *
+ * @see Bitmap#isMutable()
+ * @see Bitmap#getDensity()
+ */
+ public static Bitmap createBitmap(BufferedImage image, boolean isMutable,
+ Density density) throws IOException {
+ // create a delegate with the given image.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888);
+
+ return createBitmap(delegate, isMutable, density.getDpiValue());
+ }
+
+ /**
+ * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
+ */
+ public static BufferedImage getImage(Bitmap bitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
+ if (delegate == null) {
+ return null;
+ }
+
+ return delegate.mImage;
+ }
+
+ public static int getBufferedImageType(int nativeBitmapConfig) {
+ switch (Config.sConfigs[nativeBitmapConfig]) {
+ case ALPHA_8:
+ return BufferedImage.TYPE_INT_ARGB;
+ case RGB_565:
+ return BufferedImage.TYPE_INT_ARGB;
+ case ARGB_4444:
+ return BufferedImage.TYPE_INT_ARGB;
+ case ARGB_8888:
+ return BufferedImage.TYPE_INT_ARGB;
+ }
+
+ return BufferedImage.TYPE_INT_ARGB;
+ }
+
+ /**
+ * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
+ */
+ public BufferedImage getImage() {
+ return mImage;
+ }
+
+ /**
+ * Returns the Android bitmap config. Note that this not the config of the underlying
+ * Java2D bitmap.
+ */
+ public Config getConfig() {
+ return mConfig;
+ }
+
+ /**
+ * Returns the hasAlpha rendering hint
+ * @return true if the bitmap alpha should be used at render time
+ */
+ public boolean hasAlpha() {
+ return mHasAlpha && mConfig != Config.RGB_565;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
+ int height, int nativeConfig, boolean mutable) {
+ int imageType = getBufferedImageType(nativeConfig);
+
+ // create the image
+ BufferedImage image = new BufferedImage(width, height, imageType);
+
+ if (colors != null) {
+ image.setRGB(0, 0, width, height, colors, offset, stride);
+ }
+
+ // create a delegate with the content of the stream.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.sConfigs[nativeConfig]);
+
+ return createBitmap(delegate, mutable, Bitmap.getDefaultDensity());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable) {
+ Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(srcBitmap);
+ if (srcBmpDelegate == null) {
+ return null;
+ }
+
+ BufferedImage srcImage = srcBmpDelegate.getImage();
+
+ int width = srcImage.getWidth();
+ int height = srcImage.getHeight();
+
+ int imageType = getBufferedImageType(nativeConfig);
+
+ // create the image
+ BufferedImage image = new BufferedImage(width, height, imageType);
+
+ // copy the source image into the image.
+ int[] argb = new int[width * height];
+ srcImage.getRGB(0, 0, width, height, argb, 0, width);
+ image.setRGB(0, 0, width, height, argb, 0, width);
+
+ // create a delegate with the content of the stream.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.sConfigs[nativeConfig]);
+
+ return createBitmap(delegate, isMutable, Bitmap.getDefaultDensity());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int nativeBitmap) {
+ sManager.removeJavaReferenceFor(nativeBitmap);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeRecycle(int nativeBitmap) {
+ sManager.removeJavaReferenceFor(nativeBitmap);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeCompress(int nativeBitmap, int format, int quality,
+ OutputStream stream, byte[] tempStorage) {
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "Bitmap.compress() is not supported", null /*data*/);
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeErase(int nativeBitmap, int color) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ BufferedImage image = delegate.mImage;
+
+ Graphics2D g = image.createGraphics();
+ try {
+ g.setColor(new java.awt.Color(color, true));
+
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ } finally {
+ g.dispose();
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeWidth(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mImage.getWidth();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeHeight(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mImage.getHeight();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeRowBytes(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mImage.getWidth();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConfig(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mConfig.nativeInt;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeHasAlpha(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return true;
+ }
+
+ return delegate.mHasAlpha;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeGetPixel(int nativeBitmap, int x, int y) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mImage.getRGB(x, y);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeGetPixels(int nativeBitmap, int[] pixels, int offset,
+ int stride, int x, int y, int width, int height) {
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.getImage().getRGB(x, y, width, height, pixels, offset, stride);
+ }
+
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetPixel(int nativeBitmap, int x, int y, int color) {
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.getImage().setRGB(x, y, color);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetPixels(int nativeBitmap, int[] colors, int offset,
+ int stride, int x, int y, int width, int height) {
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.getImage().setRGB(x, y, width, height, colors, offset, stride);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst) {
+ // FIXME implement native delegate
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Bitmap.copyPixelsToBuffer is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeCopyPixelsFromBuffer(int nb, Buffer src) {
+ // FIXME implement native delegate
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Bitmap.copyPixelsFromBuffer is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeCreateFromParcel(Parcel p) {
+ // This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only
+ // used during aidl call so really this should not be called.
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "AIDL is not suppored, and therefore Bitmaps cannot be created from parcels.",
+ null /*data*/);
+ return null;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeWriteToParcel(int nativeBitmap, boolean isMutable,
+ int density, Parcel p) {
+ // This is only called when sending a bitmap through aidl, so really this should not
+ // be called.
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "AIDL is not suppored, and therefore Bitmaps cannot be written to parcels.",
+ null /*data*/);
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeExtractAlpha(int nativeBitmap, int nativePaint,
+ int[] offsetXY) {
+ Bitmap_Delegate bitmap = sManager.getDelegate(nativeBitmap);
+ if (bitmap == null) {
+ return null;
+ }
+
+ // get the paint which can be null if nativePaint is 0.
+ Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
+
+ if (paint != null && paint.getMaskFilter() != null) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
+ "MaskFilter not supported in Bitmap.extractAlpha",
+ null, null /*data*/);
+ }
+
+ int alpha = paint != null ? paint.getAlpha() : 0xFF;
+ BufferedImage image = createCopy(bitmap.getImage(), BufferedImage.TYPE_INT_ARGB, alpha);
+
+ // create the delegate. The actual Bitmap config is only an alpha channel
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ALPHA_8);
+
+ // the density doesn't matter, it's set by the Java method.
+ return createBitmap(delegate, false /*isMutable*/,
+ Density.DEFAULT_DENSITY /*density*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativePrepareToDraw(int nativeBitmap) {
+ // nothing to be done here.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetHasAlpha(int nativeBitmap, boolean hasAlpha) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mHasAlpha = hasAlpha;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeSameAs(int nb0, int nb1) {
+ Bitmap_Delegate delegate1 = sManager.getDelegate(nb0);
+ if (delegate1 == null) {
+ return false;
+ }
+
+ Bitmap_Delegate delegate2 = sManager.getDelegate(nb1);
+ if (delegate2 == null) {
+ return false;
+ }
+
+ BufferedImage image1 = delegate1.getImage();
+ BufferedImage image2 = delegate2.getImage();
+ if (delegate1.mConfig != delegate2.mConfig ||
+ image1.getWidth() != image2.getWidth() ||
+ image1.getHeight() != image2.getHeight()) {
+ return false;
+ }
+
+ // get the internal data
+ int w = image1.getWidth();
+ int h = image2.getHeight();
+ int[] argb1 = new int[w*h];
+ int[] argb2 = new int[w*h];
+
+ image1.getRGB(0, 0, w, h, argb1, 0, w);
+ image2.getRGB(0, 0, w, h, argb2, 0, w);
+
+ // compares
+ if (delegate1.mConfig == Config.ALPHA_8) {
+ // in this case we have to manually compare the alpha channel as the rest is garbage.
+ final int length = w*h;
+ for (int i = 0 ; i < length ; i++) {
+ if ((argb1[i] & 0xFF000000) != (argb2[i] & 0xFF000000)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return Arrays.equals(argb1, argb2);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private Bitmap_Delegate(BufferedImage image, Config config) {
+ mImage = image;
+ mConfig = config;
+ }
+
+ private static Bitmap createBitmap(Bitmap_Delegate delegate, boolean isMutable, int density) {
+ // get its native_int
+ int nativeInt = sManager.addNewDelegate(delegate);
+
+ // and create/return a new Bitmap with it
+ return new Bitmap(nativeInt, isMutable, null /*ninePatchChunk*/, density);
+ }
+
+ /**
+ * Creates and returns a copy of a given BufferedImage.
+ * <p/>
+ * if alpha is different than 255, then it is applied to the alpha channel of each pixel.
+ *
+ * @param image the image to copy
+ * @param imageType the type of the new image
+ * @param alpha an optional alpha modifier
+ * @return a new BufferedImage
+ */
+ /*package*/ static BufferedImage createCopy(BufferedImage image, int imageType, int alpha) {
+ int w = image.getWidth();
+ int h = image.getHeight();
+
+ BufferedImage result = new BufferedImage(w, h, imageType);
+
+ int[] argb = new int[w * h];
+ image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
+
+ if (alpha != 255) {
+ final int length = argb.length;
+ for (int i = 0 ; i < length; i++) {
+ int a = (argb[i] >>> 24 * alpha) / 255;
+ argb[i] = (a << 24) | (argb[i] & 0x00FFFFFF);
+ }
+ }
+
+ result.setRGB(0, 0, w, h, argb, 0, w);
+
+ return result;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
new file mode 100644
index 0000000..4becba1
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.BlurMaskFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of BlurMaskFilter have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original BlurMaskFilter class.
+ *
+ * Because this extends {@link MaskFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link MaskFilter_Delegate}.
+ *
+ * @see MaskFilter_Delegate
+ *
+ */
+public class BlurMaskFilter_Delegate extends MaskFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Blur Mask Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConstructor(float radius, int style) {
+ BlurMaskFilter_Delegate newDelegate = new BlurMaskFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
deleted file mode 100644
index d5d315e..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas.java
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * 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 com.android.layoutlib.api.ILayoutLog;
-
-import android.graphics.DrawFilter;
-import android.graphics.Picture;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Region;
-import android.graphics.Xfermode;
-import android.graphics.Paint.Align;
-import android.graphics.Paint.FontInfo;
-import android.graphics.Paint.Style;
-import android.graphics.Region.Op;
-
-import java.awt.AlphaComposite;
-import java.awt.BasicStroke;
-import java.awt.Color;
-import java.awt.Composite;
-import java.awt.Graphics2D;
-import java.awt.Rectangle;
-import java.awt.RenderingHints;
-import java.awt.geom.AffineTransform;
-import java.awt.image.BufferedImage;
-import java.util.List;
-import java.util.Stack;
-
-import javax.microedition.khronos.opengles.GL;
-
-/**
- * Re-implementation of the Canvas, 100% in java on top of a BufferedImage.
- */
-public class Canvas extends _Original_Canvas {
-
- private BufferedImage mBufferedImage;
- private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>();
- private final ILayoutLog mLogger;
-
- public Canvas() {
- mLogger = null;
- // the mBufferedImage will be taken from a bitmap in #setBitmap()
- }
-
- public Canvas(Bitmap bitmap) {
- mLogger = null;
- mBufferedImage = bitmap.getImage();
- mGraphicsStack.push(mBufferedImage.createGraphics());
- }
-
- public Canvas(int nativeCanvas) {
- mLogger = null;
- throw new UnsupportedOperationException("Can't create Canvas(int)");
- }
-
- public Canvas(javax.microedition.khronos.opengles.GL gl) {
- mLogger = null;
- throw new UnsupportedOperationException("Can't create Canvas(javax.microedition.khronos.opengles.GL)");
- }
-
- // custom constructors for our use.
- public Canvas(int width, int height, ILayoutLog logger) {
- mLogger = logger;
- mBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- mGraphicsStack.push(mBufferedImage.createGraphics());
- }
-
- public Canvas(int width, int height) {
- this(width, height, null /* logger*/);
- }
-
- // custom mehtods
- public BufferedImage getImage() {
- return mBufferedImage;
- }
-
- public Graphics2D getGraphics2d() {
- return mGraphicsStack.peek();
- }
-
- public void dispose() {
- while (mGraphicsStack.size() > 0) {
- mGraphicsStack.pop().dispose();
- }
- }
-
- /**
- * Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
- * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
- */
- private Graphics2D getCustomGraphics(Paint paint) {
- // make new one
- Graphics2D g = getGraphics2d();
- g = (Graphics2D)g.create();
-
- // configure it
- g.setColor(new Color(paint.getColor()));
- int alpha = paint.getAlpha();
- float falpha = alpha / 255.f;
-
- Style style = paint.getStyle();
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- PathEffect e = paint.getPathEffect();
- if (e instanceof DashPathEffect) {
- DashPathEffect dpe = (DashPathEffect)e;
- g.setStroke(new BasicStroke(
- paint.getStrokeWidth(),
- paint.getStrokeCap().getJavaCap(),
- paint.getStrokeJoin().getJavaJoin(),
- paint.getStrokeMiter(),
- dpe.getIntervals(),
- dpe.getPhase()));
- } else {
- g.setStroke(new BasicStroke(
- paint.getStrokeWidth(),
- paint.getStrokeCap().getJavaCap(),
- paint.getStrokeJoin().getJavaJoin(),
- paint.getStrokeMiter()));
- }
- }
-
- Xfermode xfermode = paint.getXfermode();
- if (xfermode instanceof PorterDuffXfermode) {
- PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode();
-
- setModeInGraphics(mode, g, falpha);
- } else {
- if (mLogger != null && xfermode != null) {
- mLogger.warning(String.format(
- "Xfermode '%1$s' is not supported in the Layout Editor.",
- xfermode.getClass().getCanonicalName()));
- }
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
- }
-
- Shader shader = paint.getShader();
- if (shader != null) {
- java.awt.Paint shaderPaint = shader.getJavaPaint();
- if (shaderPaint != null) {
- g.setPaint(shaderPaint);
- } else {
- if (mLogger != null) {
- mLogger.warning(String.format(
- "Shader '%1$s' is not supported in the Layout Editor.",
- shader.getClass().getCanonicalName()));
- }
- }
- }
-
- return g;
- }
-
- private void setModeInGraphics(PorterDuff.Mode mode, Graphics2D g, float falpha) {
- switch (mode) {
- case CLEAR:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha));
- break;
- case DARKEN:
- break;
- case DST:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST, falpha));
- break;
- case DST_ATOP:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha));
- break;
- case DST_IN:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha));
- break;
- case DST_OUT:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha));
- break;
- case DST_OVER:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha));
- break;
- case LIGHTEN:
- break;
- case MULTIPLY:
- break;
- case SCREEN:
- break;
- case SRC:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, falpha));
- break;
- case SRC_ATOP:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha));
- break;
- case SRC_IN:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha));
- break;
- case SRC_OUT:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha));
- break;
- case SRC_OVER:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
- break;
- case XOR:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.XOR, falpha));
- break;
- }
- }
-
-
- // --------------------
- // OVERRIDEN ENUMS
- // This is needed since we rename Canvas into _Original_Canvas
- // --------------------
-
- public enum EdgeType {
- BW(0), //!< treat edges by just rounding to nearest pixel boundary
- AA(1); //!< treat edges by rounding-out, since they may be antialiased
-
- EdgeType(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
-
- // --------------------
- // OVERRIDEN METHODS
- // --------------------
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap)
- */
- @Override
- public void setBitmap(Bitmap bitmap) {
- mBufferedImage = bitmap.getImage();
- mGraphicsStack.push(mBufferedImage.createGraphics());
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#translate(float, float)
- */
- @Override
- public void translate(float dx, float dy) {
- getGraphics2d().translate(dx, dy);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#save()
- */
- @Override
- public int save() {
- // get the current save count
- int count = mGraphicsStack.size();
-
- // create a new graphics and add it to the stack
- Graphics2D g = (Graphics2D)getGraphics2d().create();
- mGraphicsStack.push(g);
-
- // return the old save count
- return count;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#save(int)
- */
- @Override
- public int save(int saveFlags) {
- // For now we ignore saveFlags
- return save();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#restore()
- */
- @Override
- public void restore() {
- mGraphicsStack.pop();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#restoreToCount(int)
- */
- @Override
- public void restoreToCount(int saveCount) {
- while (mGraphicsStack.size() > saveCount) {
- mGraphicsStack.pop();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getSaveCount()
- */
- @Override
- public int getSaveCount() {
- return mGraphicsStack.size();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(float, float, float, float, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRect(float left, float top, float right, float bottom, Op op) {
- return clipRect(left, top, right, bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(float, float, float, float)
- */
- @Override
- public boolean clipRect(float left, float top, float right, float bottom) {
- getGraphics2d().clipRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
- return true;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(int, int, int, int)
- */
- @Override
- public boolean clipRect(int left, int top, int right, int bottom) {
- getGraphics2d().clipRect(left, top, right-left, bottom-top);
- return true;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.Rect, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRect(Rect rect, Op op) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.Rect)
- */
- @Override
- public boolean clipRect(Rect rect) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.RectF, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRect(RectF rect, Op op) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.RectF)
- */
- @Override
- public boolean clipRect(RectF rect) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- public boolean quickReject(RectF rect, EdgeType type) {
- return false;
- }
-
- @Override
- public boolean quickReject(RectF rect, _Original_Canvas.EdgeType type) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public boolean quickReject(Path path, EdgeType type) {
- return false;
- }
-
- @Override
- public boolean quickReject(Path path, _Original_Canvas.EdgeType type) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public boolean quickReject(float left, float top, float right, float bottom,
- EdgeType type) {
- return false;
- }
-
- @Override
- public boolean quickReject(float left, float top, float right, float bottom,
- _Original_Canvas.EdgeType type) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Retrieve the clip bounds, returning true if they are non-empty.
- *
- * @param bounds Return the clip bounds here. If it is null, ignore it but
- * still return true if the current clip is non-empty.
- * @return true if the current clip is non-empty.
- */
- @Override
- public boolean getClipBounds(Rect bounds) {
- Rectangle rect = getGraphics2d().getClipBounds();
- if (rect != null) {
- bounds.left = rect.x;
- bounds.top = rect.y;
- bounds.right = rect.x + rect.width;
- bounds.bottom = rect.y + rect.height;
- return true;
- }
- return false;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawColor(int, android.graphics.PorterDuff.Mode)
- */
- @Override
- public void drawColor(int color, PorterDuff.Mode mode) {
- Graphics2D g = getGraphics2d();
-
- // save old color
- Color c = g.getColor();
-
- Composite composite = g.getComposite();
-
- // get the alpha from the color
- int alpha = color >>> 24;
- float falpha = alpha / 255.f;
-
- setModeInGraphics(mode, g, falpha);
-
- g.setColor(new Color(color));
-
- g.fillRect(0, 0, getWidth(), getHeight());
-
- g.setComposite(composite);
-
- // restore color
- g.setColor(c);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawColor(int)
- */
- @Override
- public void drawColor(int color) {
- drawColor(color, PorterDuff.Mode.SRC_OVER);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawARGB(int, int, int, int)
- */
- @Override
- public void drawARGB(int a, int r, int g, int b) {
- drawColor(a << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRGB(int, int, int)
- */
- @Override
- public void drawRGB(int r, int g, int b) {
- drawColor(0xFF << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getWidth()
- */
- @Override
- public int getWidth() {
- return mBufferedImage.getWidth();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getHeight()
- */
- @Override
- public int getHeight() {
- return mBufferedImage.getHeight();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPaint(android.graphics.Paint)
- */
- @Override
- public void drawPaint(Paint paint) {
- drawColor(paint.getColor());
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
- drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
- (int)left, (int)top,
- (int)left+bitmap.getWidth(), (int)top+bitmap.getHeight(), paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
- boolean needsRestore = false;
- if (matrix.isIdentity() == false) {
- // create a new graphics and apply the matrix to it
- save(); // this creates a new Graphics2D, and stores it for children call to use
- needsRestore = true;
- Graphics2D g = getGraphics2d(); // get the newly create Graphics2D
-
- // get the Graphics2D current matrix
- AffineTransform currentTx = g.getTransform();
- // get the AffineTransform from the matrix
- AffineTransform matrixTx = matrix.getTransform();
-
- // combine them so that the matrix is applied after.
- currentTx.preConcatenate(matrixTx);
-
- // give it to the graphics as a new matrix replacing all previous transform
- g.setTransform(currentTx);
- }
-
- // draw the bitmap
- drawBitmap(bitmap, 0, 0, paint);
-
- if (needsRestore) {
- // remove the new graphics
- restore();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
- if (src == null) {
- drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
- dst.left, dst.top, dst.right, dst.bottom, paint);
- } else {
- drawBitmap(bitmap, src.left, src.top, src.width(), src.height(),
- dst.left, dst.top, dst.right, dst.bottom, paint);
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
- if (src == null) {
- drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
- (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint);
- } else {
- drawBitmap(bitmap, src.left, src.top, src.width(), src.height(),
- (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint);
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width,
- int height, boolean hasAlpha, Paint paint) {
- throw new UnsupportedOperationException();
- }
-
- private void drawBitmap(Bitmap bitmap, int sleft, int stop, int sright, int sbottom, int dleft,
- int dtop, int dright, int dbottom, Paint paint) {
- BufferedImage image = bitmap.getImage();
-
- Graphics2D g = getGraphics2d();
-
- Composite c = null;
-
- if (paint != null) {
- if (paint.isFilterBitmap()) {
- g = (Graphics2D)g.create();
- g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
- RenderingHints.VALUE_INTERPOLATION_BILINEAR);
- }
-
- if (paint.getAlpha() != 0xFF) {
- c = g.getComposite();
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
- paint.getAlpha()/255.f));
- }
- }
-
- g.drawImage(image, dleft, dtop, dright, dbottom,
- sleft, stop, sright, sbottom, null);
-
- if (paint != null) {
- if (paint.isFilterBitmap()) {
- g.dispose();
- }
- if (c != null) {
- g.setComposite(c);
- }
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#rotate(float, float, float)
- */
- @Override
- public void rotate(float degrees, float px, float py) {
- if (degrees != 0) {
- Graphics2D g = getGraphics2d();
- g.translate(px, py);
- g.rotate(Math.toRadians(degrees));
- g.translate(-px, -py);
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#rotate(float)
- */
- @Override
- public void rotate(float degrees) {
- getGraphics2d().rotate(Math.toRadians(degrees));
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#scale(float, float, float, float)
- */
- @Override
- public void scale(float sx, float sy, float px, float py) {
- Graphics2D g = getGraphics2d();
- g.translate(px, py);
- g.scale(sx, sy);
- g.translate(-px, -py);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#scale(float, float)
- */
- @Override
- public void scale(float sx, float sy) {
- getGraphics2d().scale(sx, sy);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
- // WARNING: the logic in this method is similar to Paint.measureText.
- // Any change to this method should be reflected in Paint.measureText
- Graphics2D g = getGraphics2d();
-
- g = (Graphics2D)g.create();
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-
- // set the color. because this only handles RGB, the alpha channel is handled
- // as a composite.
- g.setColor(new Color(paint.getColor()));
- int alpha = paint.getAlpha();
- float falpha = alpha / 255.f;
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
-
-
- // Paint.TextAlign indicates how the text is positioned relative to X.
- // LEFT is the default and there's nothing to do.
- if (paint.getTextAlign() != Align.LEFT) {
- float m = paint.measureText(text, index, count);
- if (paint.getTextAlign() == Align.CENTER) {
- x -= m / 2;
- } else if (paint.getTextAlign() == Align.RIGHT) {
- x -= m;
- }
- }
-
- List<FontInfo> fonts = paint.getFonts();
- try {
- if (fonts.size() > 0) {
- FontInfo mainFont = fonts.get(0);
- int i = index;
- int lastIndex = index + count;
- while (i < lastIndex) {
- // always start with the main font.
- int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
- if (upTo == -1) {
- // draw all the rest and exit.
- g.setFont(mainFont.mFont);
- g.drawChars(text, i, lastIndex - i, (int)x, (int)y);
- return;
- } else if (upTo > 0) {
- // draw what's possible
- g.setFont(mainFont.mFont);
- g.drawChars(text, i, upTo - i, (int)x, (int)y);
-
- // compute the width that was drawn to increase x
- x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
-
- // move index to the first non displayed char.
- i = upTo;
-
- // don't call continue at this point. Since it is certain the main font
- // cannot display the font a index upTo (now ==i), we move on to the
- // fallback fonts directly.
- }
-
- // no char supported, attempt to read the next char(s) with the
- // fallback font. In this case we only test the first character
- // and then go back to test with the main font.
- // Special test for 2-char characters.
- boolean foundFont = false;
- for (int f = 1 ; f < fonts.size() ; f++) {
- FontInfo fontInfo = fonts.get(f);
-
- // need to check that the font can display the character. We test
- // differently if the char is a high surrogate.
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
- upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
- if (upTo == -1) {
- // draw that char
- g.setFont(fontInfo.mFont);
- g.drawChars(text, i, charCount, (int)x, (int)y);
-
- // update x
- x += fontInfo.mMetrics.charsWidth(text, i, charCount);
-
- // update the index in the text, and move on
- i += charCount;
- foundFont = true;
- break;
-
- }
- }
-
- // in case no font can display the char, display it with the main font.
- // (it'll put a square probably)
- if (foundFont == false) {
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-
- g.setFont(mainFont.mFont);
- g.drawChars(text, i, charCount, (int)x, (int)y);
-
- // measure it to advance x
- x += mainFont.mMetrics.charsWidth(text, i, charCount);
-
- // and move to the next chars.
- i += charCount;
- }
- }
- }
- } finally {
- g.dispose();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
- drawText(text.toString().toCharArray(), start, end - start, x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(java.lang.String, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(String text, float x, float y, Paint paint) {
- drawText(text.toCharArray(), 0, text.length(), x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(java.lang.String, int, int, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(String text, int start, int end, float x, float y, Paint paint) {
- drawText(text.toCharArray(), start, end - start, x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRect(android.graphics.RectF, android.graphics.Paint)
- */
- @Override
- public void drawRect(RectF rect, Paint paint) {
- doDrawRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRect(float, float, float, float, android.graphics.Paint)
- */
- @Override
- public void drawRect(float left, float top, float right, float bottom, Paint paint) {
- doDrawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top), paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRect(android.graphics.Rect, android.graphics.Paint)
- */
- @Override
- public void drawRect(Rect r, Paint paint) {
- doDrawRect(r.left, r.top, r.width(), r.height(), paint);
- }
-
- private final void doDrawRect(int left, int top, int width, int height, Paint paint) {
- if (width > 0 && height > 0) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillRect(left, top, width, height);
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawRect(left, top, width, height);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint)
- */
- @Override
- public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
- if (rect.width() > 0 && rect.height() > 0) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
-
- int arcWidth = (int)(rx * 2);
- int arcHeight = (int)(ry * 2);
-
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
- arcWidth, arcHeight);
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
- arcWidth, arcHeight);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawLine(float, float, float, float, android.graphics.Paint)
- */
- @Override
- public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawLines(float[], int, int, android.graphics.Paint)
- */
- @Override
- public void drawLines(float[] pts, int offset, int count, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- for (int i = 0 ; i < count ; i += 4) {
- g.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
- (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawLines(float[], android.graphics.Paint)
- */
- @Override
- public void drawLines(float[] pts, Paint paint) {
- drawLines(pts, 0, pts.length, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawCircle(float, float, float, android.graphics.Paint)
- */
- @Override
- public void drawCircle(float cx, float cy, float radius, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- int size = (int)(radius * 2);
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillOval((int)(cx - radius), (int)(cy - radius), size, size);
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawOval((int)(cx - radius), (int)(cy - radius), size, size);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawOval(android.graphics.RectF, android.graphics.Paint)
- */
- @Override
- public void drawOval(RectF oval, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPath(android.graphics.Path, android.graphics.Paint)
- */
- @Override
- public void drawPath(Path path, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fill(path.getAwtShape());
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.draw(path.getAwtShape());
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setMatrix(android.graphics.Matrix)
- */
- @Override
- public void setMatrix(Matrix matrix) {
- // get the new current graphics
- Graphics2D g = getGraphics2d();
-
- // and apply the matrix
- g.setTransform(matrix.getTransform());
-
- if (mLogger != null && matrix.hasPerspective()) {
- mLogger.warning("android.graphics.Canvas#setMatrix(android.graphics.Matrix) only supports affine transformations in the Layout Editor.");
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#concat(android.graphics.Matrix)
- */
- @Override
- public void concat(Matrix matrix) {
- // get the current top graphics2D object.
- Graphics2D g = getGraphics2d();
-
- // get its current matrix
- AffineTransform currentTx = g.getTransform();
- // get the AffineTransform of the given matrix
- AffineTransform matrixTx = matrix.getTransform();
-
- // combine them so that the given matrix is applied after.
- currentTx.preConcatenate(matrixTx);
-
- // give it to the graphics2D as a new matrix replacing all previous transform
- g.setTransform(currentTx);
- }
-
-
- // --------------------
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipPath(android.graphics.Path, android.graphics.Region.Op)
- */
- @Override
- public boolean clipPath(Path path, Op op) {
- // TODO Auto-generated method stub
- return super.clipPath(path, op);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipPath(android.graphics.Path)
- */
- @Override
- public boolean clipPath(Path path) {
- // TODO Auto-generated method stub
- return super.clipPath(path);
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRegion(android.graphics.Region, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRegion(Region region, Op op) {
- // TODO Auto-generated method stub
- return super.clipRegion(region, op);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRegion(android.graphics.Region)
- */
- @Override
- public boolean clipRegion(Region region) {
- // TODO Auto-generated method stub
- return super.clipRegion(region);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint)
- */
- @Override
- public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
- Paint paint) {
- // TODO Auto-generated method stub
- super.drawArc(oval, startAngle, sweepAngle, useCenter, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint)
- */
- @Override
- public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
- int vertOffset, int[] colors, int colorOffset, Paint paint) {
- // TODO Auto-generated method stub
- super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.Rect)
- */
- @Override
- public void drawPicture(Picture picture, Rect dst) {
- // TODO Auto-generated method stub
- super.drawPicture(picture, dst);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.RectF)
- */
- @Override
- public void drawPicture(Picture picture, RectF dst) {
- // TODO Auto-generated method stub
- super.drawPicture(picture, dst);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPicture(android.graphics.Picture)
- */
- @Override
- public void drawPicture(Picture picture) {
- // TODO Auto-generated method stub
- super.drawPicture(picture);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPoint(float, float, android.graphics.Paint)
- */
- @Override
- public void drawPoint(float x, float y, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPoint(x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPoints(float[], int, int, android.graphics.Paint)
- */
- @Override
- public void drawPoints(float[] pts, int offset, int count, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPoints(pts, offset, count, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPoints(float[], android.graphics.Paint)
- */
- @Override
- public void drawPoints(float[] pts, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPoints(pts, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPosText(char[], int, int, float[], android.graphics.Paint)
- */
- @Override
- public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPosText(text, index, count, pos, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPosText(java.lang.String, float[], android.graphics.Paint)
- */
- @Override
- public void drawPosText(String text, float[] pos, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPosText(text, pos, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint)
- */
- @Override
- public void drawTextOnPath(char[] text, int index, int count, Path path, float offset,
- float offset2, Paint paint) {
- // TODO Auto-generated method stub
- super.drawTextOnPath(text, index, count, path, offset, offset2, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint)
- */
- @Override
- public void drawTextOnPath(String text, Path path, float offset, float offset2, Paint paint) {
- // TODO Auto-generated method stub
- super.drawTextOnPath(text, path, offset, offset2, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint)
- */
- @Override
- public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
- float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
- int indexOffset, int indexCount, Paint paint) {
- // TODO Auto-generated method stub
- super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors, colorOffset,
- indices, indexOffset, indexCount, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getDrawFilter()
- */
- @Override
- public DrawFilter getDrawFilter() {
- // TODO Auto-generated method stub
- return super.getDrawFilter();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getGL()
- */
- @Override
- public GL getGL() {
- // TODO Auto-generated method stub
- return super.getGL();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getMatrix()
- */
- @Override
- public Matrix getMatrix() {
- // TODO Auto-generated method stub
- return super.getMatrix();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getMatrix(android.graphics.Matrix)
- */
- @Override
- public void getMatrix(Matrix ctm) {
- // TODO Auto-generated method stub
- super.getMatrix(ctm);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#isOpaque()
- */
- @Override
- public boolean isOpaque() {
- // TODO Auto-generated method stub
- return super.isOpaque();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayer(float, float, float, float, android.graphics.Paint, int)
- */
- @Override
- public int saveLayer(float left, float top, float right, float bottom, Paint paint,
- int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayer(left, top, right, bottom, paint, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayer(android.graphics.RectF, android.graphics.Paint, int)
- */
- @Override
- public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayer(bounds, paint, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayerAlpha(float, float, float, float, int, int)
- */
- @Override
- public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
- int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayerAlpha(android.graphics.RectF, int, int)
- */
- @Override
- public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayerAlpha(bounds, alpha, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setDrawFilter(android.graphics.DrawFilter)
- */
- @Override
- public void setDrawFilter(DrawFilter filter) {
- // TODO Auto-generated method stub
- super.setDrawFilter(filter);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setViewport(int, int)
- */
- @Override
- public void setViewport(int width, int height) {
- // TODO Auto-generated method stub
- super.setViewport(width, height);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#skew(float, float)
- */
- @Override
- public void skew(float sx, float sy) {
- // TODO Auto-generated method stub
- super.skew(sx, sy);
- }
-
-
-
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
new file mode 100644
index 0000000..49c1e4b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -0,0 +1,1357 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.layoutlib.bridge.impl.GcSnapshot;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Bitmap.Config;
+import android.graphics.Paint_Delegate.FontInfo;
+import android.text.TextUtils;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.image.BufferedImage;
+import java.util.List;
+
+
+/**
+ * Delegate implementing the native methods of android.graphics.Canvas
+ *
+ * Through the layoutlib_create tool, the original native methods of Canvas have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Canvas class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Canvas_Delegate {
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Canvas_Delegate> sManager =
+ new DelegateManager<Canvas_Delegate>(Canvas_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ private final static boolean[] sBoolOut = new boolean[1];
+
+ // ---- delegate data ----
+ private Bitmap_Delegate mBitmap;
+ private GcSnapshot mSnapshot;
+
+ private DrawFilter_Delegate mDrawFilter = null;
+
+ // ---- Public Helper methods ----
+
+ /**
+ * Returns the native delegate associated to a given {@link Canvas} object.
+ */
+ public static Canvas_Delegate getDelegate(Canvas canvas) {
+ return sManager.getDelegate(canvas.mNativeCanvas);
+ }
+
+ /**
+ * Returns the native delegate associated to a given an int referencing a {@link Canvas} object.
+ */
+ public static Canvas_Delegate getDelegate(int native_canvas) {
+ return sManager.getDelegate(native_canvas);
+ }
+
+ /**
+ * Returns the current {@link Graphics2D} used to draw.
+ */
+ public GcSnapshot getSnapshot() {
+ return mSnapshot;
+ }
+
+ /**
+ * Returns the {@link DrawFilter} delegate or null if none have been set.
+ *
+ * @return the delegate or null.
+ */
+ public DrawFilter_Delegate getDrawFilter() {
+ return mDrawFilter;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isOpaque(Canvas thisCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return false;
+ }
+
+ return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getWidth(Canvas thisCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.mBitmap.getImage().getWidth();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getHeight(Canvas thisCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.mBitmap.getImage().getHeight();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.getSnapshot().translate(dx, dy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.getSnapshot().scale(sx, sy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the current top graphics2D object.
+ GcSnapshot g = canvasDelegate.getSnapshot();
+
+ // get its current matrix
+ AffineTransform currentTx = g.getTransform();
+ // get the AffineTransform for the given skew.
+ float[] mtx = Matrix_Delegate.getSkew(kx, ky);
+ AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
+
+ // combine them so that the given matrix is applied after.
+ currentTx.preConcatenate(matrixTx);
+
+ // give it to the graphics2D as a new matrix replacing all previous transform
+ g.setTransform(currentTx);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
+ return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
+ return clipRect(thisCanvas, (float) rect.left, (float) rect.top,
+ (float) rect.right, (float) rect.bottom);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
+ float bottom) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return false;
+ }
+
+ return canvasDelegate.clipRect(left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
+ int bottom) {
+
+ return clipRect(thisCanvas, (float) left, (float) top, (float) right, (float) bottom);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int save(Canvas thisCanvas) {
+ return save(thisCanvas, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int save(Canvas thisCanvas, int saveFlags) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.save(saveFlags);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void restore(Canvas thisCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.restore();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getSaveCount(Canvas thisCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.getSnapshot().size();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.restoreTo(saveCount);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void drawText(Canvas thisCanvas,
+ String text, float x, float y, Paint paint) {
+ native_drawText(thisCanvas.mNativeCanvas, text, 0, text.length(), x, y,
+ paint.mNativePaint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
+ Paint paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPoint is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPoint is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void drawLines(Canvas thisCanvas,
+ final float[] pts, final int offset, final int count,
+ Paint paint) {
+ draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
+ false /*forceSrcMode*/, new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ for (int i = 0 ; i < count ; i += 4) {
+ graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
+ (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
+ }
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void freeCaches() {
+ // nothing to be done here.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int initRaster(int nativeBitmapOrZero) {
+ if (nativeBitmapOrZero > 0) {
+ // get the Bitmap from the int
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero);
+
+ // create a new Canvas_Delegate with the given bitmap and return its new native int.
+ Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // create a new Canvas_Delegate and return its new native int.
+ Canvas_Delegate newDelegate = new Canvas_Delegate();
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int initGL() {
+ // not supported.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.setBitmap(bitmapDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetViewport(int nCanvas, int w, int h) {
+ // only useful in GL which is not supported, so no need to do anything.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds,
+ int paint, int layerFlags) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
+ if (paintDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.saveLayer(bounds, paintDelegate, layerFlags);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_saveLayer(int nativeCanvas, float l,
+ float t, float r, float b,
+ int paint, int layerFlags) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
+ if (paintDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.saveLayer(new RectF(l, t, r, b),
+ paintDelegate, layerFlags);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_saveLayerAlpha(int nativeCanvas,
+ RectF bounds, int alpha,
+ int layerFlags) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.saveLayerAlpha(bounds, alpha, layerFlags);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_saveLayerAlpha(int nativeCanvas, float l,
+ float t, float r, float b,
+ int alpha, int layerFlags) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
+ }
+
+
+ @LayoutlibDelegate
+ /*package*/ static void native_concat(int nCanvas, int nMatrix) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ // get the current top graphics2D object.
+ GcSnapshot snapshot = canvasDelegate.getSnapshot();
+
+ // get its current matrix
+ AffineTransform currentTx = snapshot.getTransform();
+ // get the AffineTransform of the given matrix
+ AffineTransform matrixTx = matrixDelegate.getAffineTransform();
+
+ // combine them so that the given matrix is applied after.
+ currentTx.preConcatenate(matrixTx);
+
+ // give it to the graphics2D as a new matrix replacing all previous transform
+ snapshot.setTransform(currentTx);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setMatrix(int nCanvas, int nMatrix) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ // get the current top graphics2D object.
+ GcSnapshot snapshot = canvasDelegate.getSnapshot();
+
+ // get the AffineTransform of the given matrix
+ AffineTransform matrixTx = matrixDelegate.getAffineTransform();
+
+ // give it to the graphics2D as a new matrix replacing all previous transform
+ snapshot.setTransform(matrixTx);
+
+ if (matrixDelegate.hasPerspective()) {
+ assert false;
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
+ "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
+ "supports affine transformations.", null, null /*data*/);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_clipRect(int nCanvas,
+ float left, float top,
+ float right, float bottom,
+ int regionOp) {
+
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return false;
+ }
+
+ return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_clipPath(int nativeCanvas,
+ int nativePath,
+ int regionOp) {
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return true;
+ }
+
+ Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath);
+ if (pathDelegate == null) {
+ return true;
+ }
+
+ return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_clipRegion(int nativeCanvas,
+ int nativeRegion,
+ int regionOp) {
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return true;
+ }
+
+ Region_Delegate region = Region_Delegate.getDelegate(nativeRegion);
+ if (region == null) {
+ return true;
+ }
+
+ return canvasDelegate.mSnapshot.clip(region.getJavaArea(), regionOp);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetDrawFilter(int nativeCanvas, int nativeFilter) {
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter);
+
+ if (canvasDelegate.mDrawFilter != null &&
+ canvasDelegate.mDrawFilter.isSupported() == false) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER,
+ canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_getClipBounds(int nativeCanvas,
+ Rect bounds) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return false;
+ }
+
+ Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds();
+ if (rect != null && rect.isEmpty() == false) {
+ bounds.left = rect.x;
+ bounds.top = rect.y;
+ bounds.right = rect.x + rect.width;
+ bounds.bottom = rect.y + rect.height;
+ return true;
+ }
+
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_getCTM(int canvas, int matrix) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ AffineTransform transform = canvasDelegate.getSnapshot().getTransform();
+ matrixDelegate.set(Matrix_Delegate.makeValues(transform));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_quickReject(int nativeCanvas,
+ RectF rect,
+ int native_edgeType) {
+ // FIXME properly implement quickReject
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_quickReject(int nativeCanvas,
+ int path,
+ int native_edgeType) {
+ // FIXME properly implement quickReject
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_quickReject(int nativeCanvas,
+ float left, float top,
+ float right, float bottom,
+ int native_edgeType) {
+ // FIXME properly implement quickReject
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g, int b) {
+ native_drawColor(nativeCanvas, 0xFF000000 | r << 16 | (g&0xFF) << 8 | (b&0xFF),
+ PorterDuff.Mode.SRC_OVER.nativeInt);
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawARGB(int nativeCanvas, int a, int r, int g, int b) {
+ native_drawColor(nativeCanvas, a << 24 | (r&0xFF) << 16 | (g&0xFF) << 8 | (b&0xFF),
+ PorterDuff.Mode.SRC_OVER.nativeInt);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawColor(int nativeCanvas, int color) {
+ native_drawColor(nativeCanvas, color, PorterDuff.Mode.SRC_OVER.nativeInt);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawColor(int nativeCanvas, final int color, final int mode) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ final int w = canvasDelegate.mBitmap.getImage().getWidth();
+ final int h = canvasDelegate.mBitmap.getImage().getHeight();
+ draw(nativeCanvas, new GcSnapshot.Drawable() {
+
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ // reset its transform just in case
+ graphics.setTransform(new AffineTransform());
+
+ // set the color
+ graphics.setColor(new Color(color, true /*alpha*/));
+
+ Composite composite = PorterDuffXfermode_Delegate.getComposite(
+ PorterDuffXfermode_Delegate.getPorterDuffMode(mode), 0xFF);
+ if (composite != null) {
+ graphics.setComposite(composite);
+ }
+
+ graphics.fillRect(0, 0, w, h);
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPaint(int nativeCanvas, int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPaint is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawLine(int nativeCanvas,
+ final float startX, final float startY, final float stopX, final float stopY,
+ int paint) {
+
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawRect(int nativeCanvas, RectF rect,
+ int paint) {
+ native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawRect(int nativeCanvas,
+ final float left, final float top, final float right, final float bottom, int paint) {
+
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ int style = paintDelegate.getStyle();
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fillRect((int)left, (int)top,
+ (int)(right-left), (int)(bottom-top));
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.drawRect((int)left, (int)top,
+ (int)(right-left), (int)(bottom-top));
+ }
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawOval(int nativeCanvas, final RectF oval, int paint) {
+ if (oval.right > oval.left && oval.bottom > oval.top) {
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ int style = paintDelegate.getStyle();
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fillOval((int)oval.left, (int)oval.top,
+ (int)oval.width(), (int)oval.height());
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.drawOval((int)oval.left, (int)oval.top,
+ (int)oval.width(), (int)oval.height());
+ }
+ }
+ });
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawCircle(int nativeCanvas,
+ float cx, float cy, float radius, int paint) {
+ native_drawOval(nativeCanvas,
+ new RectF(cx - radius, cy - radius, radius*2, radius*2),
+ paint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawArc(int nativeCanvas,
+ final RectF oval, final float startAngle, final float sweep,
+ final boolean useCenter, int paint) {
+ if (oval.right > oval.left && oval.bottom > oval.top) {
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ int style = paintDelegate.getStyle();
+
+ Arc2D.Float arc = new Arc2D.Float(
+ oval.left, oval.top, oval.width(), oval.height(),
+ -startAngle, -sweep,
+ useCenter ? Arc2D.PIE : Arc2D.OPEN);
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fill(arc);
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.draw(arc);
+ }
+ }
+ });
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawRoundRect(int nativeCanvas,
+ final RectF rect, final float rx, final float ry, int paint) {
+
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ int style = paintDelegate.getStyle();
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fillRoundRect(
+ (int)rect.left, (int)rect.top,
+ (int)rect.width(), (int)rect.height(),
+ (int)rx, (int)ry);
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.drawRoundRect(
+ (int)rect.left, (int)rect.top,
+ (int)rect.width(), (int)rect.height(),
+ (int)rx, (int)ry);
+ }
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPath(int nativeCanvas, int path, int paint) {
+ final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ Shape shape = pathDelegate.getJavaShape();
+ int style = paintDelegate.getStyle();
+
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fill(shape);
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.draw(shape);
+ }
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
+ float left, float top,
+ int nativePaintOrZero,
+ int canvasDensity,
+ int screenDensity,
+ int bitmapDensity) {
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ BufferedImage image = bitmapDelegate.getImage();
+ float right = left + image.getWidth();
+ float bottom = top + image.getHeight();
+
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
+ 0, 0, image.getWidth(), image.getHeight(),
+ (int)left, (int)top, (int)right, (int)bottom);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
+ Rect src, RectF dst,
+ int nativePaintOrZero,
+ int screenDensity,
+ int bitmapDensity) {
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ BufferedImage image = bitmapDelegate.getImage();
+
+ if (src == null) {
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
+ 0, 0, image.getWidth(), image.getHeight(),
+ (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
+ } else {
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
+ src.left, src.top, src.width(), src.height(),
+ (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap,
+ Rect src, Rect dst,
+ int nativePaintOrZero,
+ int screenDensity,
+ int bitmapDensity) {
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ BufferedImage image = bitmapDelegate.getImage();
+
+ if (src == null) {
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
+ 0, 0, image.getWidth(), image.getHeight(),
+ dst.left, dst.top, dst.right, dst.bottom);
+ } else {
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
+ src.left, src.top, src.width(), src.height(),
+ dst.left, dst.top, dst.right, dst.bottom);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors,
+ int offset, int stride, final float x,
+ final float y, int width, int height,
+ boolean hasAlpha,
+ int nativePaintOrZero) {
+
+ // create a temp BufferedImage containing the content.
+ final BufferedImage image = new BufferedImage(width, height,
+ hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
+ image.setRGB(0, 0, width, height, colors, offset, stride);
+
+ draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ if (paint != null && paint.isFilterBitmap()) {
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ }
+
+ graphics.drawImage(image, (int) x, (int) y, null);
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
+ int nMatrix, int nPaint) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the delegate from the native int, which can be null
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
+
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nBitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut);
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ final AffineTransform mtx = matrixDelegate.getAffineTransform();
+
+ canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ if (paint != null && paint.isFilterBitmap()) {
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ }
+
+ //FIXME add support for canvas, screen and bitmap densities.
+ graphics.drawImage(image, mtx, null);
+ }
+ }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
+ int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors,
+ int colorOffset, int nPaint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawBitmapMesh is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDrawVertices(int nCanvas, int mode, int n,
+ float[] verts, int vertOffset,
+ float[] texs, int texOffset,
+ int[] colors, int colorOffset,
+ short[] indices, int indexOffset,
+ int indexCount, int nPaint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawVertices is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawText(int nativeCanvas,
+ final char[] text, final int index, final int count,
+ final float startX, final float startY, int paint) {
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paintDelegate) {
+ // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
+ // Any change to this method should be reflected in Paint.measureText
+ // Paint.TextAlign indicates how the text is positioned relative to X.
+ // LEFT is the default and there's nothing to do.
+ float x = startX;
+ float y = startY;
+ if (paintDelegate.getTextAlign() != Paint.Align.LEFT.nativeInt) {
+ float m = paintDelegate.measureText(text, index, count);
+ if (paintDelegate.getTextAlign() == Paint.Align.CENTER.nativeInt) {
+ x -= m / 2;
+ } else if (paintDelegate.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
+ x -= m;
+ }
+ }
+
+ List<FontInfo> fonts = paintDelegate.getFonts();
+
+ if (fonts.size() > 0) {
+ FontInfo mainFont = fonts.get(0);
+ int i = index;
+ int lastIndex = index + count;
+ while (i < lastIndex) {
+ // always start with the main font.
+ int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+ if (upTo == -1) {
+ // draw all the rest and exit.
+ graphics.setFont(mainFont.mFont);
+ graphics.drawChars(text, i, lastIndex - i, (int)x, (int)y);
+ return;
+ } else if (upTo > 0) {
+ // draw what's possible
+ graphics.setFont(mainFont.mFont);
+ graphics.drawChars(text, i, upTo - i, (int)x, (int)y);
+
+ // compute the width that was drawn to increase x
+ x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+
+ // move index to the first non displayed char.
+ i = upTo;
+
+ // don't call continue at this point. Since it is certain the main font
+ // cannot display the font a index upTo (now ==i), we move on to the
+ // fallback fonts directly.
+ }
+
+ // no char supported, attempt to read the next char(s) with the
+ // fallback font. In this case we only test the first character
+ // and then go back to test with the main font.
+ // Special test for 2-char characters.
+ boolean foundFont = false;
+ for (int f = 1 ; f < fonts.size() ; f++) {
+ FontInfo fontInfo = fonts.get(f);
+
+ // need to check that the font can display the character. We test
+ // differently if the char is a high surrogate.
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+ if (upTo == -1) {
+ // draw that char
+ graphics.setFont(fontInfo.mFont);
+ graphics.drawChars(text, i, charCount, (int)x, (int)y);
+
+ // update x
+ x += fontInfo.mMetrics.charsWidth(text, i, charCount);
+
+ // update the index in the text, and move on
+ i += charCount;
+ foundFont = true;
+ break;
+
+ }
+ }
+
+ // in case no font can display the char, display it with the main font.
+ // (it'll put a square probably)
+ if (foundFont == false) {
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+
+ graphics.setFont(mainFont.mFont);
+ graphics.drawChars(text, i, charCount, (int)x, (int)y);
+
+ // measure it to advance x
+ x += mainFont.mMetrics.charsWidth(text, i, charCount);
+
+ // and move to the next chars.
+ i += charCount;
+ }
+ }
+ }
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawText(int nativeCanvas, String text,
+ int start, int end, float x,
+ float y, int paint) {
+ int count = end - start;
+ char[] buffer = TemporaryBuffer.obtain(count);
+ TextUtils.getChars(text, start, end, buffer, 0);
+
+ native_drawText(nativeCanvas, buffer, 0, count, x, y, paint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPosText(int nativeCanvas,
+ char[] text, int index,
+ int count, float[] pos,
+ int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPosText is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPosText(int nativeCanvas,
+ String text, float[] pos,
+ int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPosText is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawTextOnPath(int nativeCanvas,
+ char[] text, int index,
+ int count, int path,
+ float hOffset,
+ float vOffset,
+ int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawTextOnPath(int nativeCanvas,
+ String text, int path,
+ float hOffset,
+ float vOffset,
+ int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPicture(int nativeCanvas,
+ int nativePicture) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPicture is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int nativeCanvas) {
+ // get the delegate from the native int so that it can be disposed.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.dispose();
+
+ // remove it from the manager.
+ sManager.removeJavaReferenceFor(nativeCanvas);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ /**
+ * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint.
+ * <p>Note that the drawable may actually be executed several times if there are
+ * layers involved (see {@link #saveLayer(RectF, int, int)}.
+ */
+ private static void draw(int nCanvas, int nPaint, boolean compositeOnly, boolean forceSrcMode,
+ GcSnapshot.Drawable drawable) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the paint which can be null if nPaint is 0;
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
+
+ canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode);
+ }
+
+ /**
+ * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided
+ * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}.
+ * <p>Note that the drawable may actually be executed several times if there are
+ * layers involved (see {@link #saveLayer(RectF, int, int)}.
+ */
+ private static void draw(int nCanvas, GcSnapshot.Drawable drawable) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.mSnapshot.draw(drawable);
+ }
+
+ private Canvas_Delegate(Bitmap_Delegate bitmap) {
+ mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap);
+ }
+
+ private Canvas_Delegate() {
+ mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/);
+ }
+
+ /**
+ * Disposes of the {@link Graphics2D} stack.
+ */
+ private void dispose() {
+ mSnapshot.dispose();
+ }
+
+ private int save(int saveFlags) {
+ // get the current save count
+ int count = mSnapshot.size();
+
+ mSnapshot = mSnapshot.save(saveFlags);
+
+ // return the old save count
+ return count;
+ }
+
+ private int saveLayerAlpha(RectF rect, int alpha, int saveFlags) {
+ Paint_Delegate paint = new Paint_Delegate();
+ paint.setAlpha(alpha);
+ return saveLayer(rect, paint, saveFlags);
+ }
+
+ private int saveLayer(RectF rect, Paint_Delegate paint, int saveFlags) {
+ // get the current save count
+ int count = mSnapshot.size();
+
+ mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags);
+
+ // return the old save count
+ return count;
+ }
+
+ /**
+ * Restores the {@link GcSnapshot} to <var>saveCount</var>
+ * @param saveCount the saveCount
+ */
+ private void restoreTo(int saveCount) {
+ mSnapshot = mSnapshot.restoreTo(saveCount);
+ }
+
+ /**
+ * Restores the {@link GcSnapshot} to <var>saveCount</var>
+ * @param saveCount the saveCount
+ */
+ private void restore() {
+ mSnapshot = mSnapshot.restore();
+ }
+
+ private boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
+ return mSnapshot.clipRect(left, top, right, bottom, regionOp);
+ }
+
+ private void setBitmap(Bitmap_Delegate bitmap) {
+ mBitmap = bitmap;
+ assert mSnapshot.size() == 1;
+ mSnapshot.setBitmap(mBitmap);
+ }
+
+ private static void drawBitmap(
+ int nativeCanvas,
+ Bitmap_Delegate bitmap,
+ int nativePaintOrZero,
+ final int sleft, final int stop, final int sright, final int sbottom,
+ final int dleft, final int dtop, final int dright, final int dbottom) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the paint, which could be null if the int is 0
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
+
+ final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut);
+
+ draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0],
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ if (paint != null && paint.isFilterBitmap()) {
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ }
+
+ //FIXME add support for canvas, screen and bitmap densities.
+ graphics.drawImage(image, dleft, dtop, dright, dbottom,
+ sleft, stop, sright, sbottom, null);
+ }
+ });
+ }
+
+
+ /**
+ * Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate.
+ * The image returns, through a 1-size boolean array, whether the drawing code should
+ * use a SRC composite no matter what the paint says.
+ *
+ * @param bitmap the bitmap
+ * @param paint the paint that will be used to draw
+ * @param forceSrcMode whether the composite will have to be SRC
+ * @return the image to draw
+ */
+ private static BufferedImage getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint,
+ boolean[] forceSrcMode) {
+ BufferedImage image = bitmap.getImage();
+ forceSrcMode[0] = false;
+
+ // if the bitmap config is alpha_8, then we erase all color value from it
+ // before drawing it.
+ if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) {
+ fixAlpha8Bitmap(image);
+ } else if (bitmap.hasAlpha() == false) {
+ // hasAlpha is merely a rendering hint. There can in fact be alpha values
+ // in the bitmap but it should be ignored at drawing time.
+ // There is two ways to do this:
+ // - override the composite to be SRC. This can only be used if the composite
+ // was going to be SRC or SRC_OVER in the first place
+ // - Create a different bitmap to draw in which all the alpha channel values is set
+ // to 0xFF.
+ if (paint != null) {
+ Xfermode_Delegate xfermodeDelegate = paint.getXfermode();
+ if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) {
+ PorterDuff.Mode mode =
+ ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode();
+
+ forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER ||
+ mode == PorterDuff.Mode.SRC;
+ }
+ }
+
+ // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB
+ if (forceSrcMode[0] == false) {
+ image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF);
+ }
+ }
+
+ return image;
+ }
+
+ private static void fixAlpha8Bitmap(final BufferedImage image) {
+ int w = image.getWidth();
+ int h = image.getHeight();
+ int[] argb = new int[w * h];
+ image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
+
+ final int length = argb.length;
+ for (int i = 0 ; i < length; i++) {
+ argb[i] &= 0xFF000000;
+ }
+ image.setRGB(0, 0, w, h, argb, 0, w);
+ }
+}
+
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
new file mode 100644
index 0000000..4c692c2
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.ColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of ColorFilter have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original ColorFilter class.
+ *
+ * This also serve as a base class for all ColorFilter delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class ColorFilter_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<ColorFilter_Delegate> sManager =
+ new DelegateManager<ColorFilter_Delegate>(ColorFilter_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static ColorFilter_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int native_instance) {
+ sManager.removeJavaReferenceFor(native_instance);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
new file mode 100644
index 0000000..d4c5b8d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.ColorMatrixColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of ColorMatrixColorFilter have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original ColorMatrixColorFilter class.
+ *
+ * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link ColorFilter_Delegate}.
+ *
+ * @see ColorFilter_Delegate
+ *
+ */
+public class ColorMatrixColorFilter_Delegate extends ColorFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "ColorMatrix Color Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeColorMatrixFilter(float[] array) {
+ ColorMatrixColorFilter_Delegate newDelegate = new ColorMatrixColorFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java
new file mode 100644
index 0000000..7c04a87
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.ComposePathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of ComposePathEffect have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original ComposePathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public class ComposePathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Compose Path Effects are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int outerpe, int innerpe) {
+ ComposePathEffect_Delegate newDelegate = new ComposePathEffect_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader.java
deleted file mode 100644
index 863d64a..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/ComposeShader.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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 java.awt.Paint;
-
-/** A subclass of shader that returns the composition of two other shaders, combined by
- an {@link android.graphics.Xfermode} subclass.
-*/
-public class ComposeShader extends Shader {
- /** Create a new compose shader, given shaders A, B, and a combining mode.
- When the mode is applied, it will be given the result from shader A as its
- "dst", and the result of from shader B as its "src".
- @param shaderA The colors from this shader are seen as the "dst" by the mode
- @param shaderB The colors from this shader are seen as the "src" by the mode
- @param mode The mode that combines the colors from the two shaders. If mode
- is null, then SRC_OVER is assumed.
- */
- public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) {
- // FIXME Implement shader
- }
-
- /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
- When the mode is applied, it will be given the result from shader A as its
- "dst", and the result of from shader B as its "src".
- @param shaderA The colors from this shader are seen as the "dst" by the mode
- @param shaderB The colors from this shader are seen as the "src" by the mode
- @param mode The PorterDuff mode that combines the colors from the two shaders.
- */
- public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) {
- // FIXME Implement shader
- }
-
- @Override
- Paint getJavaPaint() {
- return null;
- }
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
new file mode 100644
index 0000000..fcc12d7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Paint;
+
+/**
+ * Delegate implementing the native methods of android.graphics.ComposeShader
+ *
+ * Through the layoutlib_create tool, the original native methods of ComposeShader have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original ComposeShader class.
+ *
+ * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
+ *
+ * @see Shader_Delegate
+ *
+ */
+public class ComposeShader_Delegate extends Shader_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Paint getJavaPaint() {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Compose Shaders are not supported in Layout Preview mode.";
+ }
+
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate1(int native_shaderA, int native_shaderB,
+ int native_mode) {
+ // FIXME not supported yet.
+ ComposeShader_Delegate newDelegate = new ComposeShader_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate2(int native_shaderA, int native_shaderB,
+ int porterDuffMode) {
+ // FIXME not supported yet.
+ ComposeShader_Delegate newDelegate = new ComposeShader_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java
new file mode 100644
index 0000000..b0f8168
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.CornerPathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of CornerPathEffect have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original CornerPathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public class CornerPathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Corner Path Effects are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(float radius) {
+ CornerPathEffect_Delegate newDelegate = new CornerPathEffect_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect.java b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect.java
deleted file mode 100644
index 46d4c70..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.graphics;
-
-public class DashPathEffect extends PathEffect {
-
- private final float[] mIntervals;
- private final float mPhase;
-
- /**
- * The intervals array must contain an even number of entries (>=2), with
- * the even indices specifying the "on" intervals, and the odd indices
- * specifying the "off" intervals. phase is an offset into the intervals
- * array (mod the sum of all of the intervals). The intervals array
- * controls the length of the dashes. The paint's strokeWidth controls the
- * thickness of the dashes.
- * Note: this patheffect only affects drawing with the paint's style is set
- * to STROKE or STROKE_AND_FILL. It is ignored if the drawing is done with
- * style == FILL.
- * @param intervals array of ON and OFF distances
- * @param phase offset into the intervals array
- */
- public DashPathEffect(float intervals[], float phase) {
- if (intervals.length < 2) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- mIntervals = intervals;
- mPhase = phase;
- }
-
- public float[] getIntervals() {
- return mIntervals;
- }
-
- public float getPhase() {
- return mPhase;
- }
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
new file mode 100644
index 0000000..d97c2ec
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.BasicStroke;
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.DashPathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of DashPathEffect have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original DashPathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
+ * {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public final class DashPathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ private final float[] mIntervals;
+ private final float mPhase;
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ return new BasicStroke(
+ paint.getStrokeWidth(),
+ paint.getJavaCap(),
+ paint.getJavaJoin(),
+ paint.getJavaStrokeMiter(),
+ mIntervals,
+ mPhase);
+ }
+
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ // no message since isSupported returns true;
+ return null;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(float intervals[], float phase) {
+ DashPathEffect_Delegate newDelegate = new DashPathEffect_Delegate(intervals, phase);
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private DashPathEffect_Delegate(float intervals[], float phase) {
+ mIntervals = new float[intervals.length];
+ System.arraycopy(intervals, 0, mIntervals, 0, intervals.length);
+ mPhase = phase;
+ }
+}
+
diff --git a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
new file mode 100644
index 0000000..ec4a810
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.DiscretePathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of DiscretePathEffect have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original DiscretePathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public class DiscretePathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Discrete Path Effects are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(float length, float deviation) {
+ DiscretePathEffect_Delegate newDelegate = new DiscretePathEffect_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
new file mode 100644
index 0000000..870c46b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.DrawFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of DrawFilter have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original DrawFilter class.
+ *
+ * This also serve as a base class for all DrawFilter delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class DrawFilter_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<DrawFilter_Delegate> sManager =
+ new DelegateManager<DrawFilter_Delegate>(DrawFilter_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static DrawFilter_Delegate getDelegate(int nativeDrawFilter) {
+ return sManager.getDelegate(nativeDrawFilter);
+ }
+
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int nativeDrawFilter) {
+ sManager.removeJavaReferenceFor(nativeDrawFilter);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
new file mode 100644
index 0000000..ebc1c1d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.EmbossMaskFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of EmbossMaskFilter have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original EmbossMaskFilter class.
+ *
+ * Because this extends {@link MaskFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link MaskFilter_Delegate}.
+ *
+ * @see MaskFilter_Delegate
+ *
+ */
+public class EmbossMaskFilter_Delegate extends MaskFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Emboss Mask Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConstructor(float[] direction, float ambient,
+ float specular, float blurRadius) {
+ EmbossMaskFilter_Delegate newDelegate = new EmbossMaskFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/GradientShader.java b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
index 8c5a2a4..38c092d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/GradientShader.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
@@ -16,23 +16,28 @@
package android.graphics;
+import android.graphics.Shader.TileMode;
/**
- * Base class for Gradient shader. This is not a standard android class and is just used
- * as a base class for the re-implemented gradient classes.
- *
- * It also provides a base class to handle common code between the different shaders'
- * implementations of {@link java.awt.Paint}.
- *
- * @see LinearGradient
- * @see RadialGradient
- * @see SweepGradient
+ * Base class for true Gradient shader delegate.
*/
-public abstract class GradientShader extends Shader {
+public abstract class Gradient_Delegate extends Shader_Delegate {
protected final int[] mColors;
protected final float[] mPositions;
+ @Override
+ public boolean isSupported() {
+ // all gradient shaders are supported.
+ return true;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ // all gradient shaders are supported, no need for a gradient support
+ return null;
+ }
+
/**
* Creates the base shader and do some basic test on the parameters.
*
@@ -41,7 +46,7 @@ public abstract class GradientShader extends Shader {
* corresponding color in the colors array. If this is null, the
* the colors are distributed evenly along the gradient line.
*/
- protected GradientShader(int colors[], float positions[]) {
+ protected Gradient_Delegate(int colors[], float positions[]) {
if (colors.length < 2) {
throw new IllegalArgumentException("needs >= 2 number of colors");
}
@@ -90,7 +95,7 @@ public abstract class GradientShader extends Shader {
* Pre-computes the colors for the gradient. This must be called once before any call
* to {@link #getGradientColor(float)}
*/
- protected synchronized void precomputeGradientColors() {
+ protected void precomputeGradientColors() {
if (mGradient == null) {
// actually create an array with an extra size, so that we can really go
// from 0 to SIZE (100%), or currentPos in the loop below will never equal 1.0
@@ -126,20 +131,23 @@ public abstract class GradientShader extends Shader {
pos = 0.f;
break;
case REPEAT:
- // remove the integer part to stay in the [0,1] range
- // careful: this is a negative value, so use ceil instead of floor
- pos = pos - (float)Math.ceil(pos);
+ // remove the integer part to stay in the [0,1] range.
+ // we also need to invert the value from [-1,0] to [0, 1]
+ pos = pos - (float)Math.floor(pos);
break;
case MIRROR:
+ // this is the same as the positive side, just make the value positive
+ // first.
+ pos = Math.abs(pos);
+
// get the integer and the decimal part
- // careful: this is a negative value, so use ceil instead of floor
- int intPart = (int)Math.ceil(pos);
+ int intPart = (int)Math.floor(pos);
pos = pos - intPart;
- // 0 -> -1 : mirrored order
- // -1 -> -2: normal order
+ // 0 -> 1 : normal order
+ // 1 -> 2: mirrored
// etc..
- // this means if the intpart is even we invert
- if ((intPart % 2) == 0) {
+ // this means if the intpart is odd we invert
+ if ((intPart % 2) == 1) {
pos = 1.f - pos;
}
break;
@@ -199,7 +207,5 @@ public abstract class GradientShader extends Shader {
private int computeChannel(int c1, int c2, float percent) {
return c1 + (int)((percent * (c2-c1)) + .5);
}
-
-
}
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
new file mode 100644
index 0000000..51e0576
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.LayerRasterizer
+ *
+ * Through the layoutlib_create tool, the original native methods of LayerRasterizer have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original LayerRasterizer class.
+ *
+ * Because this extends {@link Rasterizer_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link Rasterizer_Delegate}.
+ *
+ * @see Rasterizer_Delegate
+ *
+ */
+public class LayerRasterizer_Delegate extends Rasterizer_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Layer Rasterizers are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConstructor() {
+ LayerRasterizer_Delegate newDelegate = new LayerRasterizer_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeAddLayer(int native_layer, int native_paint, float dx, float dy) {
+
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
new file mode 100644
index 0000000..3afe965
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.LightingColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of LightingColorFilter have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original LightingColorFilter class.
+ *
+ * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link ColorFilter_Delegate}.
+ *
+ * @see ColorFilter_Delegate
+ *
+ */
+public class LightingColorFilter_Delegate extends ColorFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Lighting Color Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int native_CreateLightingFilter(int mul, int add) {
+ LightingColorFilter_Delegate newDelegate = new LightingColorFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient.java
deleted file mode 100644
index 10c4a5e..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * 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;
-
-public class LinearGradient extends GradientShader {
-
- private java.awt.Paint mJavaPaint;
-
- /**
- * Create a shader that draws a linear gradient along a line.
- *
- * @param x0 The x-coordinate for the start of the gradient line
- * @param y0 The y-coordinate for the start of the gradient line
- * @param x1 The x-coordinate for the end of the gradient line
- * @param y1 The y-coordinate for the end of the gradient line
- * @param colors The colors to be distributed along the gradient line
- * @param positions May be null. The relative positions [0..1] of each
- * corresponding color in the colors array. If this is null, the
- * the colors are distributed evenly along the gradient line.
- * @param tile The Shader tiling mode
- */
- public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
- TileMode tile) {
- super(colors, positions);
- mJavaPaint = new LinearGradientPaint(x0, y0, x1, y1, mColors, mPositions, tile);
- }
-
- /**
- * Create a shader that draws a linear gradient along a line.
- *
- * @param x0 The x-coordinate for the start of the gradient line
- * @param y0 The y-coordinate for the start of the gradient line
- * @param x1 The x-coordinate for the end of the gradient line
- * @param y1 The y-coordinate for the end of the gradient line
- * @param color0 The color at the start of the gradient line.
- * @param color1 The color at the end of the gradient line.
- * @param tile The Shader tiling mode
- */
- public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
- TileMode tile) {
- this(x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/, tile);
- }
-
- // ---------- Custom Methods
-
- @Override
- java.awt.Paint getJavaPaint() {
- return mJavaPaint;
- }
-
- /**
- * Linear Gradient (Java) Paint able to handle more than 2 points, as
- * {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile
- * modes.
- */
- private static class LinearGradientPaint extends GradientPaint {
-
- private final float mX0;
- private final float mY0;
- private final float mDx;
- private final float mDy;
- private final float mDSize2;
-
- public LinearGradientPaint(float x0, float y0, float x1, float y1, int colors[],
- float positions[], TileMode tile) {
- super(colors, positions, tile);
- mX0 = x0;
- mY0 = y0;
- mDx = x1 - x0;
- mDy = y1 - y0;
- mDSize2 = mDx * mDx + mDy * mDy;
- }
-
- public java.awt.PaintContext createContext(
- java.awt.image.ColorModel colorModel,
- java.awt.Rectangle deviceBounds,
- java.awt.geom.Rectangle2D userBounds,
- java.awt.geom.AffineTransform xform,
- java.awt.RenderingHints hints) {
- precomputeGradientColors();
- return new LinearGradientPaintContext(colorModel);
- }
-
- private class LinearGradientPaintContext implements java.awt.PaintContext {
-
- private final java.awt.image.ColorModel mColorModel;
-
- public LinearGradientPaintContext(java.awt.image.ColorModel colorModel) {
- mColorModel = colorModel;
- // FIXME: so far all this is always the same rect gotten in getRaster with an indentity matrix?
- }
-
- public void dispose() {
- }
-
- public java.awt.image.ColorModel getColorModel() {
- return mColorModel;
- }
-
- public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
- java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
- java.awt.image.BufferedImage.TYPE_INT_ARGB);
-
- int[] data = new int[w*h];
-
- if (mDx == 0) { // vertical gradient
- // compute first column and copy to all other columns
- int index = 0;
- for (int iy = 0 ; iy < h ; iy++) {
- int color = getColor(iy + y, mY0, mDy);
- for (int ix = 0 ; ix < w ; ix++) {
- data[index++] = color;
- }
- }
- } else if (mDy == 0) { // horizontal
- // compute first line in a tmp array and copy to all lines
- int[] line = new int[w];
- for (int ix = 0 ; ix < w ; ix++) {
- line[ix] = getColor(ix + x, mX0, mDx);
- }
-
- for (int iy = 0 ; iy < h ; iy++) {
- System.arraycopy(line, 0, data, iy*w, line.length);
- }
- } else {
- int index = 0;
- for (int iy = 0 ; iy < h ; iy++) {
- for (int ix = 0 ; ix < w ; ix++) {
- data[index++] = getColor(ix + x, iy + y);
- }
- }
- }
-
- image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
-
- return image.getRaster();
- }
- }
-
- /** Returns a color for the easy vertical/horizontal mode */
- private int getColor(float absPos, float refPos, float refSize) {
- float pos = (absPos - refPos) / refSize;
-
- return getGradientColor(pos);
- }
-
- /**
- * Returns a color for an arbitrary point.
- */
- private int getColor(float x, float y) {
- // find the x position on the gradient vector.
- float _x = (mDx*mDy*(y-mY0) + mDy*mDy*mX0 + mDx*mDx*x) / mDSize2;
- // from it get the position relative to the vector
- float pos = (float) ((_x - mX0) / mDx);
-
- return getGradientColor(pos);
- }
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
new file mode 100644
index 0000000..a735ea1
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Shader.TileMode;
+
+/**
+ * Delegate implementing the native methods of android.graphics.LinearGradient
+ *
+ * Through the layoutlib_create tool, the original native methods of LinearGradient have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original LinearGradient class.
+ *
+ * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
+ *
+ * @see Shader_Delegate
+ *
+ */
+public final class LinearGradient_Delegate extends Gradient_Delegate {
+
+ // ---- delegate data ----
+ private java.awt.Paint mJavaPaint;
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public java.awt.Paint getJavaPaint() {
+ return mJavaPaint;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate1(
+ float x0, float y0, float x1, float y1,
+ int colors[], float positions[], int tileMode) {
+ LinearGradient_Delegate newDelegate = new LinearGradient_Delegate(x0, y0, x1, y1,
+ colors, positions, Shader_Delegate.getTileMode(tileMode));
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate2(
+ float x0, float y0, float x1, float y1,
+ int color0, int color1, int tileMode) {
+ return nativeCreate1(x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/,
+ tileMode);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ /**
+ * Create a shader that draws a linear gradient along a line.
+ *
+ * @param x0 The x-coordinate for the start of the gradient line
+ * @param y0 The y-coordinate for the start of the gradient line
+ * @param x1 The x-coordinate for the end of the gradient line
+ * @param y1 The y-coordinate for the end of the gradient line
+ * @param colors The colors to be distributed along the gradient line
+ * @param positions May be null. The relative positions [0..1] of each
+ * corresponding color in the colors array. If this is null, the
+ * the colors are distributed evenly along the gradient line.
+ * @param tile The Shader tiling mode
+ */
+ private LinearGradient_Delegate(float x0, float y0, float x1, float y1,
+ int colors[], float positions[], TileMode tile) {
+ super(colors, positions);
+ mJavaPaint = new LinearGradientPaint(x0, y0, x1, y1, mColors, mPositions, tile);
+ }
+
+ // ---- Custom Java Paint ----
+ /**
+ * Linear Gradient (Java) Paint able to handle more than 2 points, as
+ * {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile
+ * modes.
+ */
+ private class LinearGradientPaint extends GradientPaint {
+
+ private final float mX0;
+ private final float mY0;
+ private final float mDx;
+ private final float mDy;
+ private final float mDSize2;
+
+ public LinearGradientPaint(float x0, float y0, float x1, float y1, int colors[],
+ float positions[], TileMode tile) {
+ super(colors, positions, tile);
+ mX0 = x0;
+ mY0 = y0;
+ mDx = x1 - x0;
+ mDy = y1 - y0;
+ mDSize2 = mDx * mDx + mDy * mDy;
+ }
+
+ public java.awt.PaintContext createContext(
+ java.awt.image.ColorModel colorModel,
+ java.awt.Rectangle deviceBounds,
+ java.awt.geom.Rectangle2D userBounds,
+ java.awt.geom.AffineTransform xform,
+ java.awt.RenderingHints hints) {
+ precomputeGradientColors();
+
+ java.awt.geom.AffineTransform canvasMatrix;
+ try {
+ canvasMatrix = xform.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in LinearGradient", e, null /*data*/);
+ canvasMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
+ try {
+ localMatrix = localMatrix.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in LinearGradient", e, null /*data*/);
+ localMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ return new LinearGradientPaintContext(canvasMatrix, localMatrix, colorModel);
+ }
+
+ private class LinearGradientPaintContext implements java.awt.PaintContext {
+
+ private final java.awt.geom.AffineTransform mCanvasMatrix;
+ private final java.awt.geom.AffineTransform mLocalMatrix;
+ private final java.awt.image.ColorModel mColorModel;
+
+ private LinearGradientPaintContext(
+ java.awt.geom.AffineTransform canvasMatrix,
+ java.awt.geom.AffineTransform localMatrix,
+ java.awt.image.ColorModel colorModel) {
+ mCanvasMatrix = canvasMatrix;
+ mLocalMatrix = localMatrix;
+ mColorModel = colorModel;
+ }
+
+ public void dispose() {
+ }
+
+ public java.awt.image.ColorModel getColorModel() {
+ return mColorModel;
+ }
+
+ public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
+ java.awt.image.BufferedImage.TYPE_INT_ARGB);
+
+ int[] data = new int[w*h];
+
+ int index = 0;
+ float[] pt1 = new float[2];
+ float[] pt2 = new float[2];
+ for (int iy = 0 ; iy < h ; iy++) {
+ for (int ix = 0 ; ix < w ; ix++) {
+ // handle the canvas transform
+ pt1[0] = x + ix;
+ pt1[1] = y + iy;
+ mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ // handle the local matrix.
+ pt1[0] = pt2[0];
+ pt1[1] = pt2[1];
+ mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ data[index++] = getColor(pt2[0], pt2[1]);
+ }
+ }
+
+ image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
+
+ return image.getRaster();
+ }
+ }
+
+ /**
+ * Returns a color for an arbitrary point.
+ */
+ private int getColor(float x, float y) {
+ float pos;
+ if (mDx == 0) {
+ pos = (y - mY0) / mDy;
+ } else if (mDy == 0) {
+ pos = (x - mX0) / mDx;
+ } else {
+ // find the x position on the gradient vector.
+ float _x = (mDx*mDy*(y-mY0) + mDy*mDy*mX0 + mDx*mDx*x) / mDSize2;
+ // from it get the position relative to the vector
+ pos = (_x - mX0) / mDx;
+ }
+
+ return getGradientColor(pos);
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
new file mode 100644
index 0000000..c2f27e4
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.MaskFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of MaskFilter have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original MaskFilter class.
+ *
+ * This also serve as a base class for all MaskFilter delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class MaskFilter_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<MaskFilter_Delegate> sManager =
+ new DelegateManager<MaskFilter_Delegate>(MaskFilter_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static MaskFilter_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int native_filter) {
+ sManager.removeJavaReferenceFor(native_filter);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix.java b/tools/layoutlib/bridge/src/android/graphics/Matrix.java
deleted file mode 100644
index 9e30671..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix.java
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * 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 java.awt.geom.AffineTransform;
-import java.awt.geom.NoninvertibleTransformException;
-
-
-/**
- * A matrix implementation overridden by the LayoutLib bridge.
- */
-public class Matrix extends _Original_Matrix {
-
- float mValues[] = new float[9];
-
- /**
- * Create an identity matrix
- */
- public Matrix() {
- reset();
- }
-
- /**
- * Create a matrix that is a (deep) copy of src
- * @param src The matrix to copy into this matrix
- */
- public Matrix(Matrix src) {
- set(src);
- }
-
- /**
- * Creates a Matrix object from the float array. The array becomes the internal storage
- * of the object.
- * @param data
- */
- private Matrix(float[] data) {
- assert data.length != 9;
- mValues = data;
- }
-
- //---------- Custom Methods
-
- /**
- * Adds the given transformation to the current Matrix
- * <p/>This in effect does this = this*matrix
- * @param matrix
- */
- private void addTransform(float[] matrix) {
- float[] tmp = new float[9];
-
- // first row
- tmp[0] = matrix[0] * mValues[0] + matrix[1] * mValues[3] + matrix[2] * mValues[6];
- tmp[1] = matrix[0] * mValues[1] + matrix[1] * mValues[4] + matrix[2] * mValues[7];
- tmp[2] = matrix[0] * mValues[2] + matrix[1] * mValues[5] + matrix[2] * mValues[8];
-
- // 2nd row
- tmp[3] = matrix[3] * mValues[0] + matrix[4] * mValues[3] + matrix[5] * mValues[6];
- tmp[4] = matrix[3] * mValues[1] + matrix[4] * mValues[4] + matrix[5] * mValues[7];
- tmp[5] = matrix[3] * mValues[2] + matrix[4] * mValues[5] + matrix[5] * mValues[8];
-
- // 3rd row
- tmp[6] = matrix[6] * mValues[0] + matrix[7] * mValues[3] + matrix[8] * mValues[6];
- tmp[7] = matrix[6] * mValues[1] + matrix[7] * mValues[4] + matrix[8] * mValues[7];
- tmp[8] = matrix[6] * mValues[2] + matrix[7] * mValues[5] + matrix[8] * mValues[8];
-
- // copy the result over to mValues
- mValues = tmp;
- }
-
- public AffineTransform getTransform() {
- // the AffineTransform constructor takes the value in a different order
- // for a matrix [ 0 1 2 ]
- // [ 3 4 5 ]
- // the order is 0, 3, 1, 4, 2, 5...
- return new AffineTransform(mValues[0], mValues[3], mValues[1],
- mValues[4], mValues[2], mValues[5]);
- }
-
- public boolean hasPerspective() {
- return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1);
- }
-
- //----------
-
- /**
- * Returns true if the matrix is identity.
- * This maybe faster than testing if (getType() == 0)
- */
- @Override
- public boolean isIdentity() {
- for (int i = 0, k = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++, k++) {
- if (mValues[k] != ((i==j) ? 1 : 0)) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /**
- * Returns true if will map a rectangle to another rectangle. This can be
- * true if the matrix is identity, scale-only, or rotates a multiple of 90
- * degrees.
- */
- @Override
- public boolean rectStaysRect() {
- return (computeTypeMask() & kRectStaysRect_Mask) != 0;
- }
-
- /**
- * (deep) copy the src matrix into this matrix. If src is null, reset this
- * matrix to the identity matrix.
- */
- public void set(Matrix src) {
- if (src == null) {
- reset();
- } else {
- System.arraycopy(src.mValues, 0, mValues, 0, mValues.length);
- }
- }
-
- @Override
- public void set(_Original_Matrix src) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /** Returns true if obj is a Matrix and its values equal our values.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj != null && obj instanceof Matrix) {
- Matrix matrix = (Matrix)obj;
- for (int i = 0 ; i < 9 ; i++) {
- if (mValues[i] != matrix.mValues[i]) {
- return false;
- }
- }
-
- return true;
- }
-
- return false;
- }
-
- /** Set the matrix to identity */
- @Override
- public void reset() {
- for (int i = 0, k = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++, k++) {
- mValues[k] = ((i==j) ? 1 : 0);
- }
- }
- }
-
- /** Set the matrix to translate by (dx, dy). */
- @Override
- public void setTranslate(float dx, float dy) {
- mValues[0] = 1;
- mValues[1] = 0;
- mValues[2] = dx;
- mValues[3] = 0;
- mValues[4] = 1;
- mValues[5] = dy;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
- }
-
- /**
- * Set the matrix to scale by sx and sy, with a pivot point at (px, py).
- * The pivot point is the coordinate that should remain unchanged by the
- * specified transformation.
- */
- @Override
- public void setScale(float sx, float sy, float px, float py) {
- // TODO: do it in one pass
-
- // translate so that the pivot is in 0,0
- mValues[0] = 1;
- mValues[1] = 0;
- mValues[2] = -px;
- mValues[3] = 0;
- mValues[4] = 1;
- mValues[5] = -py;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
-
- // scale
- addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
- }
-
- /** Set the matrix to scale by sx and sy. */
- @Override
- public void setScale(float sx, float sy) {
- mValues[0] = sx;
- mValues[1] = 0;
- mValues[2] = 0;
- mValues[3] = 0;
- mValues[4] = sy;
- mValues[5] = 0;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
- }
-
- /**
- * Set the matrix to rotate by the specified number of degrees, with a pivot
- * point at (px, py). The pivot point is the coordinate that should remain
- * unchanged by the specified transformation.
- */
- @Override
- public void setRotate(float degrees, float px, float py) {
- // TODO: do it in one pass
-
- // translate so that the pivot is in 0,0
- mValues[0] = 1;
- mValues[1] = 0;
- mValues[2] = -px;
- mValues[3] = 0;
- mValues[4] = 1;
- mValues[5] = -py;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
-
- // scale
- double rad = Math.toRadians(degrees);
- float cos = (float)Math.cos(rad);
- float sin = (float)Math.sin(rad);
- addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
- }
-
- /**
- * Set the matrix to rotate about (0,0) by the specified number of degrees.
- */
- @Override
- public void setRotate(float degrees) {
- double rad = Math.toRadians(degrees);
- float cos = (float)Math.cos(rad);
- float sin = (float)Math.sin(rad);
-
- mValues[0] = cos;
- mValues[1] = -sin;
- mValues[2] = 0;
- mValues[3] = sin;
- mValues[4] = cos;
- mValues[5] = 0;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
- }
-
- /**
- * Set the matrix to rotate by the specified sine and cosine values, with a
- * pivot point at (px, py). The pivot point is the coordinate that should
- * remain unchanged by the specified transformation.
- */
- @Override
- public void setSinCos(float sinValue, float cosValue, float px, float py) {
- // TODO: do it in one pass
-
- // translate so that the pivot is in 0,0
- mValues[0] = 1;
- mValues[1] = 0;
- mValues[2] = -px;
- mValues[3] = 0;
- mValues[4] = 1;
- mValues[5] = -py;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
-
- // scale
- addTransform(new float[] { cosValue, -sinValue, 0, sinValue, cosValue, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
- }
-
- /** Set the matrix to rotate by the specified sine and cosine values. */
- @Override
- public void setSinCos(float sinValue, float cosValue) {
- mValues[0] = cosValue;
- mValues[1] = -sinValue;
- mValues[2] = 0;
- mValues[3] = sinValue;
- mValues[4] = cosValue;
- mValues[5] = 0;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
- }
-
- /**
- * Set the matrix to skew by sx and sy, with a pivot point at (px, py).
- * The pivot point is the coordinate that should remain unchanged by the
- * specified transformation.
- */
- @Override
- public void setSkew(float kx, float ky, float px, float py) {
- // TODO: do it in one pass
-
- // translate so that the pivot is in 0,0
- mValues[0] = 1;
- mValues[1] = 0;
- mValues[2] = -px;
- mValues[3] = 0;
- mValues[4] = 1;
- mValues[5] = -py;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
-
- // scale
- addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
- }
-
- /** Set the matrix to skew by sx and sy. */
- @Override
- public void setSkew(float kx, float ky) {
- mValues[0] = 1;
- mValues[1] = kx;
- mValues[2] = -0;
- mValues[3] = ky;
- mValues[4] = 1;
- mValues[5] = 0;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
- }
-
- /**
- * Set the matrix to the concatenation of the two specified matrices,
- * returning true if the the result can be represented. Either of the two
- * matrices may also be the target matrix. this = a * b
- */
- public boolean setConcat(Matrix a, Matrix b) {
- if (a == this) {
- preConcat(b);
- } else if (b == this) {
- postConcat(b);
- } else {
- Matrix tmp = new Matrix(b);
- tmp.addTransform(a.mValues);
- set(tmp);
- }
-
- return true;
- }
-
- @Override
- public boolean setConcat(_Original_Matrix a, _Original_Matrix b) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Preconcats the matrix with the specified translation.
- * M' = M * T(dx, dy)
- */
- @Override
- public boolean preTranslate(float dx, float dy) {
- // create a matrix that will be multiply by this
- Matrix m = new Matrix(new float[] { 1, 0, dx, 0, 1, dy, 0, 0, 1 });
- m.addTransform(this.mValues);
-
- System.arraycopy(m.mValues, 0, mValues, 0, 9);
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified scale.
- * M' = M * S(sx, sy, px, py)
- */
- @Override
- public boolean preScale(float sx, float sy, float px, float py) {
- Matrix m = new Matrix();
- m.setScale(sx, sy, px, py);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified scale.
- * M' = M * S(sx, sy)
- */
- @Override
- public boolean preScale(float sx, float sy) {
- Matrix m = new Matrix();
- m.setScale(sx, sy);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified rotation.
- * M' = M * R(degrees, px, py)
- */
- @Override
- public boolean preRotate(float degrees, float px, float py) {
- Matrix m = new Matrix();
- m.setRotate(degrees, px, py);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified rotation.
- * M' = M * R(degrees)
- */
- @Override
- public boolean preRotate(float degrees) {
- Matrix m = new Matrix();
- m.setRotate(degrees);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified skew.
- * M' = M * K(kx, ky, px, py)
- */
- @Override
- public boolean preSkew(float kx, float ky, float px, float py) {
- Matrix m = new Matrix();
- m.setSkew(kx, ky, px, py);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified skew.
- * M' = M * K(kx, ky)
- */
- @Override
- public boolean preSkew(float kx, float ky) {
- Matrix m = new Matrix();
- m.setSkew(kx, ky);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified matrix.
- * M' = M * other
- */
- public boolean preConcat(Matrix other) {
- Matrix m = new Matrix(other);
- other.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- @Override
- public boolean preConcat(_Original_Matrix other) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Postconcats the matrix with the specified translation.
- * M' = T(dx, dy) * M
- */
- @Override
- public boolean postTranslate(float dx, float dy) {
- addTransform(new float[] { 1, 0, dx, 0, 1, dy, 0, 0, 1 });
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified scale.
- * M' = S(sx, sy, px, py) * M
- */
- @Override
- public boolean postScale(float sx, float sy, float px, float py) {
- // TODO: do it in one pass
- // translate so that the pivot is in 0,0
- addTransform(new float[] { 1, 0, -px, 0, 1, py, 0, 0, 1 });
- // scale
- addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
-
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified scale.
- * M' = S(sx, sy) * M
- */
- @Override
- public boolean postScale(float sx, float sy) {
- addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 });
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified rotation.
- * M' = R(degrees, px, py) * M
- */
- @Override
- public boolean postRotate(float degrees, float px, float py) {
- // TODO: do it in one pass
- // translate so that the pivot is in 0,0
- addTransform(new float[] { 1, 0, -px, 0, 1, py, 0, 0, 1 });
- // scale
- double rad = Math.toRadians(degrees);
- float cos = (float)Math.cos(rad);
- float sin = (float)Math.sin(rad);
- addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
-
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified rotation.
- * M' = R(degrees) * M
- */
- @Override
- public boolean postRotate(float degrees) {
- double rad = Math.toRadians(degrees);
- float cos = (float)Math.cos(rad);
- float sin = (float)Math.sin(rad);
- addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 });
-
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified skew.
- * M' = K(kx, ky, px, py) * M
- */
- @Override
- public boolean postSkew(float kx, float ky, float px, float py) {
- // TODO: do it in one pass
- // translate so that the pivot is in 0,0
- addTransform(new float[] { 1, 0, -px, 0, 1, py, 0, 0, 1 });
- // scale
- addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
-
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified skew.
- * M' = K(kx, ky) * M
- */
- @Override
- public boolean postSkew(float kx, float ky) {
- addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
-
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified matrix.
- * M' = other * M
- */
- public boolean postConcat(Matrix other) {
- addTransform(other.mValues);
-
- return true;
- }
-
- @Override
- public boolean postConcat(_Original_Matrix other) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /** Controlls how the src rect should align into the dst rect for
- setRectToRect().
- */
- public enum ScaleToFit {
- /**
- * Scale in X and Y independently, so that src matches dst exactly.
- * This may change the aspect ratio of the src.
- */
- FILL (0),
- /**
- * Compute a scale that will maintain the original src aspect ratio,
- * but will also ensure that src fits entirely inside dst. At least one
- * axis (X or Y) will fit exactly. START aligns the result to the
- * left and top edges of dst.
- */
- START (1),
- /**
- * Compute a scale that will maintain the original src aspect ratio,
- * but will also ensure that src fits entirely inside dst. At least one
- * axis (X or Y) will fit exactly. The result is centered inside dst.
- */
- CENTER (2),
- /**
- * Compute a scale that will maintain the original src aspect ratio,
- * but will also ensure that src fits entirely inside dst. At least one
- * axis (X or Y) will fit exactly. END aligns the result to the
- * right and bottom edges of dst.
- */
- END (3);
-
- // the native values must match those in SkMatrix.h
- ScaleToFit(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
- /**
- * Set the matrix to the scale and translate values that map the source
- * rectangle to the destination rectangle, returning true if the result
- * can be represented.
- *
- * @param src the source rectangle to map from.
- * @param dst the destination rectangle to map to.
- * @param stf the ScaleToFit option
- * @return true if the matrix can be represented by the rectangle mapping.
- */
- public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) {
- if (dst == null || src == null) {
- throw new NullPointerException();
- }
-
- if (src.isEmpty()) {
- reset();
- return false;
- }
-
- if (dst.isEmpty()) {
- mValues[0] = mValues[1] = mValues[2] = mValues[3] = mValues[4] = mValues[5]
- = mValues[6] = mValues[7] = 0;
- mValues[8] = 1;
- } else {
- float tx, sx = dst.width() / src.width();
- float ty, sy = dst.height() / src.height();
- boolean xLarger = false;
-
- if (stf != ScaleToFit.FILL) {
- if (sx > sy) {
- xLarger = true;
- sx = sy;
- } else {
- sy = sx;
- }
- }
-
- tx = dst.left - src.left * sx;
- ty = dst.top - src.top * sy;
- if (stf == ScaleToFit.CENTER || stf == ScaleToFit.END) {
- float diff;
-
- if (xLarger) {
- diff = dst.width() - src.width() * sy;
- } else {
- diff = dst.height() - src.height() * sy;
- }
-
- if (stf == ScaleToFit.CENTER) {
- diff = diff / 2;
- }
-
- if (xLarger) {
- tx += diff;
- } else {
- ty += diff;
- }
- }
-
- mValues[0] = sx;
- mValues[4] = sy;
- mValues[2] = tx;
- mValues[5] = ty;
- mValues[1] = mValues[3] = mValues[6] = mValues[7] = 0;
-
- }
- // shared cleanup
- mValues[8] = 1;
- return true;
- }
-
- @Override
- public boolean setRectToRect(RectF src, RectF dst, _Original_Matrix.ScaleToFit stf) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Set the matrix such that the specified src points would map to the
- * specified dst points. The "points" are represented as an array of floats,
- * order [x0, y0, x1, y1, ...], where each "point" is 2 float values.
- *
- * @param src The array of src [x,y] pairs (points)
- * @param srcIndex Index of the first pair of src values
- * @param dst The array of dst [x,y] pairs (points)
- * @param dstIndex Index of the first pair of dst values
- * @param pointCount The number of pairs/points to be used. Must be [0..4]
- * @return true if the matrix was set to the specified transformation
- */
- @Override
- public boolean setPolyToPoly(float[] src, int srcIndex,
- float[] dst, int dstIndex,
- int pointCount) {
- if (pointCount > 4) {
- throw new IllegalArgumentException();
- }
- checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
- throw new UnsupportedOperationException("STUB NEEDED");
- }
-
- /**
- * If this matrix can be inverted, return true and if inverse is not null,
- * set inverse to be the inverse of this matrix. If this matrix cannot be
- * inverted, ignore inverse and return false.
- */
- public boolean invert(Matrix inverse) {
- if (inverse == null) {
- return false;
- }
-
- try {
- AffineTransform affineTransform = getTransform();
- AffineTransform inverseTransform = affineTransform.createInverse();
- inverse.mValues[0] = (float)inverseTransform.getScaleX();
- inverse.mValues[1] = (float)inverseTransform.getShearX();
- inverse.mValues[2] = (float)inverseTransform.getTranslateX();
- inverse.mValues[3] = (float)inverseTransform.getScaleX();
- inverse.mValues[4] = (float)inverseTransform.getShearY();
- inverse.mValues[5] = (float)inverseTransform.getTranslateY();
-
- return true;
- } catch (NoninvertibleTransformException e) {
- return false;
- }
- }
-
- @Override
- public boolean invert(_Original_Matrix inverse) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Apply this matrix to the array of 2D points specified by src, and write
- * the transformed points into the array of points specified by dst. The
- * two arrays represent their "points" as pairs of floats [x, y].
- *
- * @param dst The array of dst points (x,y pairs)
- * @param dstIndex The index of the first [x,y] pair of dst floats
- * @param src The array of src points (x,y pairs)
- * @param srcIndex The index of the first [x,y] pair of src floats
- * @param pointCount The number of points (x,y pairs) to transform
- */
- @Override
- public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
- int pointCount) {
- checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
-
- for (int i = 0 ; i < pointCount ; i++) {
- // just in case we are doing in place, we better put this in temp vars
- float x = mValues[0] * src[i + srcIndex] +
- mValues[1] * src[i + srcIndex + 1] +
- mValues[2];
- float y = mValues[3] * src[i + srcIndex] +
- mValues[4] * src[i + srcIndex + 1] +
- mValues[5];
-
- dst[i + dstIndex] = x;
- dst[i + dstIndex + 1] = y;
- }
- }
-
- /**
- * Apply this matrix to the array of 2D vectors specified by src, and write
- * the transformed vectors into the array of vectors specified by dst. The
- * two arrays represent their "vectors" as pairs of floats [x, y].
- *
- * @param dst The array of dst vectors (x,y pairs)
- * @param dstIndex The index of the first [x,y] pair of dst floats
- * @param src The array of src vectors (x,y pairs)
- * @param srcIndex The index of the first [x,y] pair of src floats
- * @param vectorCount The number of vectors (x,y pairs) to transform
- */
- @Override
- public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex,
- int vectorCount) {
- checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount);
- throw new UnsupportedOperationException("STUB NEEDED");
- }
-
- /**
- * Apply this matrix to the array of 2D points specified by src, and write
- * the transformed points into the array of points specified by dst. The
- * two arrays represent their "points" as pairs of floats [x, y].
- *
- * @param dst The array of dst points (x,y pairs)
- * @param src The array of src points (x,y pairs)
- */
- @Override
- public void mapPoints(float[] dst, float[] src) {
- if (dst.length != src.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
- mapPoints(dst, 0, src, 0, dst.length >> 1);
- }
-
- /**
- * Apply this matrix to the array of 2D vectors specified by src, and write
- * the transformed vectors into the array of vectors specified by dst. The
- * two arrays represent their "vectors" as pairs of floats [x, y].
- *
- * @param dst The array of dst vectors (x,y pairs)
- * @param src The array of src vectors (x,y pairs)
- */
- @Override
- public void mapVectors(float[] dst, float[] src) {
- if (dst.length != src.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
- mapVectors(dst, 0, src, 0, dst.length >> 1);
- }
-
- /**
- * Apply this matrix to the array of 2D points, and write the transformed
- * points back into the array
- *
- * @param pts The array [x0, y0, x1, y1, ...] of points to transform.
- */
- @Override
- public void mapPoints(float[] pts) {
- mapPoints(pts, 0, pts, 0, pts.length >> 1);
- }
-
- /**
- * Apply this matrix to the array of 2D vectors, and write the transformed
- * vectors back into the array.
- * @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform.
- */
- @Override
- public void mapVectors(float[] vecs) {
- mapVectors(vecs, 0, vecs, 0, vecs.length >> 1);
- }
-
- /**
- * Apply this matrix to the src rectangle, and write the transformed
- * rectangle into dst. This is accomplished by transforming the 4 corners of
- * src, and then setting dst to the bounds of those points.
- *
- * @param dst Where the transformed rectangle is written.
- * @param src The original rectangle to be transformed.
- * @return the result of calling rectStaysRect()
- */
- @Override
- public boolean mapRect(RectF dst, RectF src) {
- if (dst == null || src == null) {
- throw new NullPointerException();
- }
-
- // array with 4 corners
- float[] corners = new float[] {
- src.left, src.top,
- src.right, src.top,
- src.right, src.bottom,
- src.left, src.bottom,
- };
-
- // apply the transform to them.
- mapPoints(corners);
-
- // now put the result in the rect. We take the min/max of Xs and min/max of Ys
- dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
- dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
-
- dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
- dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
-
- return rectStaysRect();
- }
-
- /**
- * Apply this matrix to the rectangle, and write the transformed rectangle
- * back into it. This is accomplished by transforming the 4 corners of rect,
- * and then setting it to the bounds of those points
- *
- * @param rect The rectangle to transform.
- * @return the result of calling rectStaysRect()
- */
- @Override
- public boolean mapRect(RectF rect) {
- return mapRect(rect, rect);
- }
-
- /**
- * Return the mean radius of a circle after it has been mapped by
- * this matrix. NOTE: in perspective this value assumes the circle
- * has its center at the origin.
- */
- @Override
- public float mapRadius(float radius) {
- throw new UnsupportedOperationException("STUB NEEDED");
- }
-
- /** Copy 9 values from the matrix into the array.
- */
- @Override
- public void getValues(float[] values) {
- if (values.length < 9) {
- throw new ArrayIndexOutOfBoundsException();
- }
- System.arraycopy(mValues, 0, values, 0, mValues.length);
- }
-
- /** Copy 9 values from the array into the matrix.
- Depending on the implementation of Matrix, these may be
- transformed into 16.16 integers in the Matrix, such that
- a subsequent call to getValues() will not yield exactly
- the same values.
- */
- @Override
- public void setValues(float[] values) {
- if (values.length < 9) {
- throw new ArrayIndexOutOfBoundsException();
- }
- System.arraycopy(values, 0, mValues, 0, mValues.length);
- }
-
- @SuppressWarnings("unused")
- private final static int kIdentity_Mask = 0;
- private final static int kTranslate_Mask = 0x01; //!< set if the matrix has translation
- private final static int kScale_Mask = 0x02; //!< set if the matrix has X or Y scale
- private final static int kAffine_Mask = 0x04; //!< set if the matrix skews or rotates
- private final static int kPerspective_Mask = 0x08; //!< set if the matrix is in perspective
- private final static int kRectStaysRect_Mask = 0x10;
- @SuppressWarnings("unused")
- private final static int kUnknown_Mask = 0x80;
-
- @SuppressWarnings("unused")
- private final static int kAllMasks = kTranslate_Mask |
- kScale_Mask |
- kAffine_Mask |
- kPerspective_Mask |
- kRectStaysRect_Mask;
-
- // these guys align with the masks, so we can compute a mask from a variable 0/1
- @SuppressWarnings("unused")
- private final static int kTranslate_Shift = 0;
- @SuppressWarnings("unused")
- private final static int kScale_Shift = 1;
- @SuppressWarnings("unused")
- private final static int kAffine_Shift = 2;
- @SuppressWarnings("unused")
- private final static int kPerspective_Shift = 3;
- private final static int kRectStaysRect_Shift = 4;
-
- private int computeTypeMask() {
- int mask = 0;
-
- if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) {
- mask |= kPerspective_Mask;
- }
-
- if (mValues[2] != 0. || mValues[5] != 0.) {
- mask |= kTranslate_Mask;
- }
-
- float m00 = mValues[0];
- float m01 = mValues[1];
- float m10 = mValues[3];
- float m11 = mValues[4];
-
- if (m01 != 0. || m10 != 0.) {
- mask |= kAffine_Mask;
- }
-
- if (m00 != 1. || m11 != 1.) {
- mask |= kScale_Mask;
- }
-
- if ((mask & kPerspective_Mask) == 0) {
- // map non-zero to 1
- int im00 = m00 != 0 ? 1 : 0;
- int im01 = m01 != 0 ? 1 : 0;
- int im10 = m10 != 0 ? 1 : 0;
- int im11 = m11 != 0 ? 1 : 0;
-
- // record if the (p)rimary and (s)econdary diagonals are all 0 or
- // all non-zero (answer is 0 or 1)
- int dp0 = (im00 | im11) ^ 1; // true if both are 0
- int dp1 = im00 & im11; // true if both are 1
- int ds0 = (im01 | im10) ^ 1; // true if both are 0
- int ds1 = im01 & im10; // true if both are 1
-
- // return 1 if primary is 1 and secondary is 0 or
- // primary is 0 and secondary is 1
- mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift;
- }
-
- return mask;
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
new file mode 100644
index 0000000..451edd2
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -0,0 +1,1129 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Matrix.ScaleToFit;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Matrix
+ *
+ * Through the layoutlib_create tool, the original native methods of Matrix have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Matrix class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Matrix_Delegate {
+
+ private final static int MATRIX_SIZE = 9;
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Matrix_Delegate> sManager =
+ new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class);
+
+ // ---- delegate data ----
+ private float mValues[] = new float[MATRIX_SIZE];
+
+ // ---- Public Helper methods ----
+
+ public static Matrix_Delegate getDelegate(int native_instance) {
+ return sManager.getDelegate(native_instance);
+ }
+
+ /**
+ * Returns an {@link AffineTransform} matching the given Matrix.
+ */
+ public static AffineTransform getAffineTransform(Matrix m) {
+ Matrix_Delegate delegate = sManager.getDelegate(m.native_instance);
+ if (delegate == null) {
+ return null;
+ }
+
+ return delegate.getAffineTransform();
+ }
+
+ public static boolean hasPerspective(Matrix m) {
+ Matrix_Delegate delegate = sManager.getDelegate(m.native_instance);
+ if (delegate == null) {
+ return false;
+ }
+
+ return delegate.hasPerspective();
+ }
+
+ /**
+ * Sets the content of the matrix with the content of another matrix.
+ */
+ public void set(Matrix_Delegate matrix) {
+ System.arraycopy(matrix.mValues, 0, mValues, 0, MATRIX_SIZE);
+ }
+
+ /**
+ * Sets the content of the matrix with the content of another matrix represented as an array
+ * of values.
+ */
+ public void set(float[] values) {
+ System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
+ }
+
+ /**
+ * Resets the matrix to be the identity matrix.
+ */
+ public void reset() {
+ reset(mValues);
+ }
+
+ /**
+ * Returns whether or not the matrix is identity.
+ */
+ public boolean isIdentity() {
+ for (int i = 0, k = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++, k++) {
+ if (mValues[k] != ((i==j) ? 1 : 0)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static float[] makeValues(AffineTransform matrix) {
+ float[] values = new float[MATRIX_SIZE];
+ values[0] = (float) matrix.getScaleX();
+ values[1] = (float) matrix.getShearX();
+ values[2] = (float) matrix.getTranslateX();
+ values[3] = (float) matrix.getShearY();
+ values[4] = (float) matrix.getScaleY();
+ values[5] = (float) matrix.getTranslateY();
+ values[6] = 0.f;
+ values[7] = 0.f;
+ values[8] = 1.f;
+
+ return values;
+ }
+
+ public static Matrix_Delegate make(AffineTransform matrix) {
+ return new Matrix_Delegate(makeValues(matrix));
+ }
+
+ public boolean mapRect(RectF dst, RectF src) {
+ // array with 4 corners
+ float[] corners = new float[] {
+ src.left, src.top,
+ src.right, src.top,
+ src.right, src.bottom,
+ src.left, src.bottom,
+ };
+
+ // apply the transform to them.
+ mapPoints(corners);
+
+ // now put the result in the rect. We take the min/max of Xs and min/max of Ys
+ dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
+ dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
+
+ dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
+ dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
+
+
+ return (computeTypeMask() & kRectStaysRect_Mask) != 0;
+ }
+
+
+ /**
+ * Returns an {@link AffineTransform} matching the matrix.
+ */
+ public AffineTransform getAffineTransform() {
+ return getAffineTransform(mValues);
+ }
+
+ public boolean hasPerspective() {
+ return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1);
+ }
+
+
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int native_create(int native_src_or_zero) {
+ // create the delegate
+ Matrix_Delegate newDelegate = new Matrix_Delegate();
+
+ // copy from values if needed.
+ if (native_src_or_zero > 0) {
+ Matrix_Delegate oldDelegate = sManager.getDelegate(native_src_or_zero);
+ if (oldDelegate != null) {
+ System.arraycopy(
+ oldDelegate.mValues, 0,
+ newDelegate.mValues, 0,
+ MATRIX_SIZE);
+ }
+ }
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_isIdentity(int native_object) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ return d.isIdentity();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_rectStaysRect(int native_object) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return true;
+ }
+
+ return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_reset(int native_object) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ reset(d.mValues);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_set(int native_object, int other) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ Matrix_Delegate src = sManager.getDelegate(other);
+ if (src == null) {
+ return;
+ }
+
+ System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setTranslate(int native_object, float dx, float dy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ setTranslate(d.mValues, dx, dy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setScale(int native_object, float sx, float sy,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ d.mValues = getScale(sx, sy, px, py);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setScale(int native_object, float sx, float sy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ d.mValues[0] = sx;
+ d.mValues[1] = 0;
+ d.mValues[2] = 0;
+ d.mValues[3] = 0;
+ d.mValues[4] = sy;
+ d.mValues[5] = 0;
+ d.mValues[6] = 0;
+ d.mValues[7] = 0;
+ d.mValues[8] = 1;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setRotate(int native_object, float degrees, float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ d.mValues = getRotate(degrees, px, py);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setRotate(int native_object, float degrees) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ setRotate(d.mValues, degrees);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ // TODO: do it in one pass
+
+ // translate so that the pivot is in 0,0
+ setTranslate(d.mValues, -px, -py);
+
+ // scale
+ d.postTransform(getRotate(sinValue, cosValue));
+ // translate back the pivot
+ d.postTransform(getTranslate(px, py));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ setRotate(d.mValues, sinValue, cosValue);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setSkew(int native_object, float kx, float ky,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ d.mValues = getSkew(kx, ky, px, py);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setSkew(int native_object, float kx, float ky) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ d.mValues[0] = 1;
+ d.mValues[1] = kx;
+ d.mValues[2] = -0;
+ d.mValues[3] = ky;
+ d.mValues[4] = 1;
+ d.mValues[5] = 0;
+ d.mValues[6] = 0;
+ d.mValues[7] = 0;
+ d.mValues[8] = 1;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_setConcat(int native_object, int a, int b) {
+ if (a == native_object) {
+ return native_preConcat(native_object, b);
+ } else if (b == native_object) {
+ return native_postConcat(native_object, a);
+ }
+
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ Matrix_Delegate a_mtx = sManager.getDelegate(a);
+ if (a_mtx == null) {
+ return false;
+ }
+
+ Matrix_Delegate b_mtx = sManager.getDelegate(b);
+ if (b_mtx == null) {
+ return false;
+ }
+
+ multiply(d.mValues, a_mtx.mValues, b_mtx.mValues);
+
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preTranslate(int native_object, float dx, float dy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getTranslate(dx, dy));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preScale(int native_object, float sx, float sy,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getScale(sx, sy, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preScale(int native_object, float sx, float sy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getScale(sx, sy));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preRotate(int native_object, float degrees,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getRotate(degrees, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preRotate(int native_object, float degrees) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ double rad = Math.toRadians(degrees);
+ float sin = (float)Math.sin(rad);
+ float cos = (float)Math.cos(rad);
+
+ d.preTransform(getRotate(sin, cos));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preSkew(int native_object, float kx, float ky,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getSkew(kx, ky, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preSkew(int native_object, float kx, float ky) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getSkew(kx, ky));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preConcat(int native_object, int other_matrix) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ Matrix_Delegate other = sManager.getDelegate(other_matrix);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(other.mValues);
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postTranslate(int native_object, float dx, float dy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getTranslate(dx, dy));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postScale(int native_object, float sx, float sy,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getScale(sx, sy, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postScale(int native_object, float sx, float sy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getScale(sx, sy));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postRotate(int native_object, float degrees,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getRotate(degrees, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postRotate(int native_object, float degrees) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getRotate(degrees));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postSkew(int native_object, float kx, float ky,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getSkew(kx, ky, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postSkew(int native_object, float kx, float ky) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getSkew(kx, ky));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postConcat(int native_object, int other_matrix) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ Matrix_Delegate other = sManager.getDelegate(other_matrix);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(other.mValues);
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_setRectToRect(int native_object, RectF src,
+ RectF dst, int stf) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ if (src.isEmpty()) {
+ reset(d.mValues);
+ return false;
+ }
+
+ if (dst.isEmpty()) {
+ d.mValues[0] = d.mValues[1] = d.mValues[2] = d.mValues[3] = d.mValues[4] = d.mValues[5]
+ = d.mValues[6] = d.mValues[7] = 0;
+ d.mValues[8] = 1;
+ } else {
+ float tx, sx = dst.width() / src.width();
+ float ty, sy = dst.height() / src.height();
+ boolean xLarger = false;
+
+ if (stf != ScaleToFit.FILL.nativeInt) {
+ if (sx > sy) {
+ xLarger = true;
+ sx = sy;
+ } else {
+ sy = sx;
+ }
+ }
+
+ tx = dst.left - src.left * sx;
+ ty = dst.top - src.top * sy;
+ if (stf == ScaleToFit.CENTER.nativeInt || stf == ScaleToFit.END.nativeInt) {
+ float diff;
+
+ if (xLarger) {
+ diff = dst.width() - src.width() * sy;
+ } else {
+ diff = dst.height() - src.height() * sy;
+ }
+
+ if (stf == ScaleToFit.CENTER.nativeInt) {
+ diff = diff / 2;
+ }
+
+ if (xLarger) {
+ tx += diff;
+ } else {
+ ty += diff;
+ }
+ }
+
+ d.mValues[0] = sx;
+ d.mValues[4] = sy;
+ d.mValues[2] = tx;
+ d.mValues[5] = ty;
+ d.mValues[1] = d.mValues[3] = d.mValues[6] = d.mValues[7] = 0;
+
+ }
+ // shared cleanup
+ d.mValues[8] = 1;
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex,
+ float[] dst, int dstIndex, int pointCount) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Matrix.setPolyToPoly is not supported.",
+ null, null /*data*/);
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_invert(int native_object, int inverse) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ Matrix_Delegate inv_mtx = sManager.getDelegate(inverse);
+ if (inv_mtx == null) {
+ return false;
+ }
+
+ try {
+ AffineTransform affineTransform = d.getAffineTransform();
+ AffineTransform inverseTransform = affineTransform.createInverse();
+ inv_mtx.mValues[0] = (float)inverseTransform.getScaleX();
+ inv_mtx.mValues[1] = (float)inverseTransform.getShearX();
+ inv_mtx.mValues[2] = (float)inverseTransform.getTranslateX();
+ inv_mtx.mValues[3] = (float)inverseTransform.getScaleX();
+ inv_mtx.mValues[4] = (float)inverseTransform.getShearY();
+ inv_mtx.mValues[5] = (float)inverseTransform.getTranslateY();
+
+ return true;
+ } catch (NoninvertibleTransformException e) {
+ return false;
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_mapPoints(int native_object, float[] dst, int dstIndex,
+ float[] src, int srcIndex, int ptCount, boolean isPts) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ if (isPts) {
+ d.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
+ } else {
+ d.mapVectors(dst, dstIndex, src, srcIndex, ptCount);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_mapRect(int native_object, RectF dst, RectF src) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ return d.mapRect(dst, src);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_mapRadius(int native_object, float radius) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return 0.f;
+ }
+
+ float[] src = new float[] { radius, 0.f, 0.f, radius };
+ d.mapVectors(src, 0, src, 0, 2);
+
+ float l1 = getPointLength(src, 0);
+ float l2 = getPointLength(src, 2);
+
+ return (float) Math.sqrt(l1 * l2);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_getValues(int native_object, float[] values) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ System.arraycopy(d.mValues, 0, d.mValues, 0, MATRIX_SIZE);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setValues(int native_object, float[] values) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_equals(int native_a, int native_b) {
+ Matrix_Delegate a = sManager.getDelegate(native_a);
+ if (a == null) {
+ return false;
+ }
+
+ Matrix_Delegate b = sManager.getDelegate(native_b);
+ if (b == null) {
+ return false;
+ }
+
+ for (int i = 0 ; i < MATRIX_SIZE ; i++) {
+ if (a.mValues[i] != b.mValues[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int native_instance) {
+ sManager.removeJavaReferenceFor(native_instance);
+ }
+
+ // ---- Private helper methods ----
+
+ /*package*/ static AffineTransform getAffineTransform(float[] matrix) {
+ // the AffineTransform constructor takes the value in a different order
+ // for a matrix [ 0 1 2 ]
+ // [ 3 4 5 ]
+ // the order is 0, 3, 1, 4, 2, 5...
+ return new AffineTransform(
+ matrix[0], matrix[3], matrix[1],
+ matrix[4], matrix[2], matrix[5]);
+ }
+
+ /**
+ * Reset a matrix to the identity
+ */
+ private static void reset(float[] mtx) {
+ for (int i = 0, k = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++, k++) {
+ mtx[k] = ((i==j) ? 1 : 0);
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private final static int kIdentity_Mask = 0;
+ private final static int kTranslate_Mask = 0x01; //!< set if the matrix has translation
+ private final static int kScale_Mask = 0x02; //!< set if the matrix has X or Y scale
+ private final static int kAffine_Mask = 0x04; //!< set if the matrix skews or rotates
+ private final static int kPerspective_Mask = 0x08; //!< set if the matrix is in perspective
+ private final static int kRectStaysRect_Mask = 0x10;
+ @SuppressWarnings("unused")
+ private final static int kUnknown_Mask = 0x80;
+
+ @SuppressWarnings("unused")
+ private final static int kAllMasks = kTranslate_Mask |
+ kScale_Mask |
+ kAffine_Mask |
+ kPerspective_Mask |
+ kRectStaysRect_Mask;
+
+ // these guys align with the masks, so we can compute a mask from a variable 0/1
+ @SuppressWarnings("unused")
+ private final static int kTranslate_Shift = 0;
+ @SuppressWarnings("unused")
+ private final static int kScale_Shift = 1;
+ @SuppressWarnings("unused")
+ private final static int kAffine_Shift = 2;
+ @SuppressWarnings("unused")
+ private final static int kPerspective_Shift = 3;
+ private final static int kRectStaysRect_Shift = 4;
+
+ private int computeTypeMask() {
+ int mask = 0;
+
+ if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) {
+ mask |= kPerspective_Mask;
+ }
+
+ if (mValues[2] != 0. || mValues[5] != 0.) {
+ mask |= kTranslate_Mask;
+ }
+
+ float m00 = mValues[0];
+ float m01 = mValues[1];
+ float m10 = mValues[3];
+ float m11 = mValues[4];
+
+ if (m01 != 0. || m10 != 0.) {
+ mask |= kAffine_Mask;
+ }
+
+ if (m00 != 1. || m11 != 1.) {
+ mask |= kScale_Mask;
+ }
+
+ if ((mask & kPerspective_Mask) == 0) {
+ // map non-zero to 1
+ int im00 = m00 != 0 ? 1 : 0;
+ int im01 = m01 != 0 ? 1 : 0;
+ int im10 = m10 != 0 ? 1 : 0;
+ int im11 = m11 != 0 ? 1 : 0;
+
+ // record if the (p)rimary and (s)econdary diagonals are all 0 or
+ // all non-zero (answer is 0 or 1)
+ int dp0 = (im00 | im11) ^ 1; // true if both are 0
+ int dp1 = im00 & im11; // true if both are 1
+ int ds0 = (im01 | im10) ^ 1; // true if both are 0
+ int ds1 = im01 & im10; // true if both are 1
+
+ // return 1 if primary is 1 and secondary is 0 or
+ // primary is 0 and secondary is 1
+ mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift;
+ }
+
+ return mask;
+ }
+
+ private Matrix_Delegate() {
+ reset();
+ }
+
+ private Matrix_Delegate(float[] values) {
+ System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
+ }
+
+ /**
+ * Adds the given transformation to the current Matrix
+ * <p/>This in effect does this = this*matrix
+ * @param matrix
+ */
+ private void postTransform(float[] matrix) {
+ float[] tmp = new float[9];
+ multiply(tmp, mValues, matrix);
+ mValues = tmp;
+ }
+
+ /**
+ * Adds the given transformation to the current Matrix
+ * <p/>This in effect does this = matrix*this
+ * @param matrix
+ */
+ private void preTransform(float[] matrix) {
+ float[] tmp = new float[9];
+ multiply(tmp, matrix, mValues);
+ mValues = tmp;
+ }
+
+ /**
+ * Apply this matrix to the array of 2D points specified by src, and write
+ * the transformed points into the array of points specified by dst. The
+ * two arrays represent their "points" as pairs of floats [x, y].
+ *
+ * @param dst The array of dst points (x,y pairs)
+ * @param dstIndex The index of the first [x,y] pair of dst floats
+ * @param src The array of src points (x,y pairs)
+ * @param srcIndex The index of the first [x,y] pair of src floats
+ * @param pointCount The number of points (x,y pairs) to transform
+ */
+
+ private void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
+ int pointCount) {
+ final int count = pointCount * 2;
+
+ float[] tmpDest = dst;
+ boolean inPlace = dst == src;
+ if (inPlace) {
+ tmpDest = new float[dstIndex + count];
+ }
+
+ for (int i = 0 ; i < count ; i += 2) {
+ // just in case we are doing in place, we better put this in temp vars
+ float x = mValues[0] * src[i + srcIndex] +
+ mValues[1] * src[i + srcIndex + 1] +
+ mValues[2];
+ float y = mValues[3] * src[i + srcIndex] +
+ mValues[4] * src[i + srcIndex + 1] +
+ mValues[5];
+
+ tmpDest[i + dstIndex] = x;
+ tmpDest[i + dstIndex + 1] = y;
+ }
+
+ if (inPlace) {
+ System.arraycopy(tmpDest, dstIndex, dst, dstIndex, count);
+ }
+ }
+
+ /**
+ * Apply this matrix to the array of 2D points, and write the transformed
+ * points back into the array
+ *
+ * @param pts The array [x0, y0, x1, y1, ...] of points to transform.
+ */
+
+ private void mapPoints(float[] pts) {
+ mapPoints(pts, 0, pts, 0, pts.length >> 1);
+ }
+
+ private void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount) {
+ if (hasPerspective()) {
+ // transform the (0,0) point
+ float[] origin = new float[] { 0.f, 0.f};
+ mapPoints(origin);
+
+ // translate the vector data as points
+ mapPoints(dst, dstIndex, src, srcIndex, ptCount);
+
+ // then substract the transformed origin.
+ final int count = ptCount * 2;
+ for (int i = 0 ; i < count ; i += 2) {
+ dst[dstIndex + i] = dst[dstIndex + i] - origin[0];
+ dst[dstIndex + i + 1] = dst[dstIndex + i + 1] - origin[1];
+ }
+ } else {
+ // make a copy of the matrix
+ Matrix_Delegate copy = new Matrix_Delegate(mValues);
+
+ // remove the translation
+ setTranslate(copy.mValues, 0, 0);
+
+ // map the content as points.
+ copy.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
+ }
+ }
+
+ private static float getPointLength(float[] src, int index) {
+ return (float) Math.sqrt(src[index] * src[index] + src[index + 1] * src[index + 1]);
+ }
+
+ /**
+ * multiply two matrices and store them in a 3rd.
+ * <p/>This in effect does dest = a*b
+ * dest cannot be the same as a or b.
+ */
+ /*package*/ static void multiply(float dest[], float[] a, float[] b) {
+ // first row
+ dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6];
+ dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7];
+ dest[2] = b[0] * a[2] + b[1] * a[5] + b[2] * a[8];
+
+ // 2nd row
+ dest[3] = b[3] * a[0] + b[4] * a[3] + b[5] * a[6];
+ dest[4] = b[3] * a[1] + b[4] * a[4] + b[5] * a[7];
+ dest[5] = b[3] * a[2] + b[4] * a[5] + b[5] * a[8];
+
+ // 3rd row
+ dest[6] = b[6] * a[0] + b[7] * a[3] + b[8] * a[6];
+ dest[7] = b[6] * a[1] + b[7] * a[4] + b[8] * a[7];
+ dest[8] = b[6] * a[2] + b[7] * a[5] + b[8] * a[8];
+ }
+
+ /**
+ * Returns a matrix that represents a given translate
+ * @param dx
+ * @param dy
+ * @return
+ */
+ /*package*/ static float[] getTranslate(float dx, float dy) {
+ return setTranslate(new float[9], dx, dy);
+ }
+
+ /*package*/ static float[] setTranslate(float[] dest, float dx, float dy) {
+ dest[0] = 1;
+ dest[1] = 0;
+ dest[2] = dx;
+ dest[3] = 0;
+ dest[4] = 1;
+ dest[5] = dy;
+ dest[6] = 0;
+ dest[7] = 0;
+ dest[8] = 1;
+ return dest;
+ }
+
+ /*package*/ static float[] getScale(float sx, float sy) {
+ return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
+ }
+
+ /**
+ * Returns a matrix that represents the given scale info.
+ * @param sx
+ * @param sy
+ * @param px
+ * @param py
+ */
+ /*package*/ static float[] getScale(float sx, float sy, float px, float py) {
+ float[] tmp = new float[9];
+ float[] tmp2 = new float[9];
+
+ // TODO: do it in one pass
+
+ // translate tmp so that the pivot is in 0,0
+ setTranslate(tmp, -px, -py);
+
+ // scale into tmp2
+ multiply(tmp2, tmp, getScale(sx, sy));
+
+ // translate back the pivot back into tmp
+ multiply(tmp, tmp2, getTranslate(px, py));
+
+ return tmp;
+ }
+
+
+ /*package*/ static float[] getRotate(float degrees) {
+ double rad = Math.toRadians(degrees);
+ float sin = (float)Math.sin(rad);
+ float cos = (float)Math.cos(rad);
+
+ return getRotate(sin, cos);
+ }
+
+ /*package*/ static float[] getRotate(float sin, float cos) {
+ return setRotate(new float[9], sin, cos);
+ }
+
+ /*package*/ static float[] setRotate(float[] dest, float degrees) {
+ double rad = Math.toRadians(degrees);
+ float sin = (float)Math.sin(rad);
+ float cos = (float)Math.cos(rad);
+
+ return setRotate(dest, sin, cos);
+ }
+
+ /*package*/ static float[] setRotate(float[] dest, float sin, float cos) {
+ dest[0] = cos;
+ dest[1] = -sin;
+ dest[2] = 0;
+ dest[3] = sin;
+ dest[4] = cos;
+ dest[5] = 0;
+ dest[6] = 0;
+ dest[7] = 0;
+ dest[8] = 1;
+ return dest;
+ }
+
+ /*package*/ static float[] getRotate(float degrees, float px, float py) {
+ float[] tmp = new float[9];
+ float[] tmp2 = new float[9];
+
+ // TODO: do it in one pass
+
+ // translate so that the pivot is in 0,0
+ setTranslate(tmp, -px, -py);
+
+ // rotate into tmp2
+ double rad = Math.toRadians(degrees);
+ float cos = (float)Math.cos(rad);
+ float sin = (float)Math.sin(rad);
+ multiply(tmp2, tmp, getRotate(sin, cos));
+
+ // translate back the pivot back into tmp
+ multiply(tmp, tmp2, getTranslate(px, py));
+
+ return tmp;
+ }
+
+ /*package*/ static float[] getSkew(float kx, float ky) {
+ return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 };
+ }
+
+ /*package*/ static float[] getSkew(float kx, float ky, float px, float py) {
+ float[] tmp = new float[9];
+ float[] tmp2 = new float[9];
+
+ // TODO: do it in one pass
+
+ // translate so that the pivot is in 0,0
+ setTranslate(tmp, -px, -py);
+
+ // skew into tmp2
+ multiply(tmp2, tmp, new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
+ // translate back the pivot back into tmp
+ multiply(tmp, tmp2, getTranslate(px, py));
+
+ return tmp;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
new file mode 100644
index 0000000..5e882ce
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.layoutlib.bridge.impl.GcSnapshot;
+import com.android.ninepatch.NinePatchChunk;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.drawable.NinePatchDrawable;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.ref.SoftReference;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Delegate implementing the native methods of android.graphics.NinePatch
+ *
+ * Through the layoutlib_create tool, the original native methods of NinePatch have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ */
+public final class NinePatch_Delegate {
+
+ /**
+ * Cache map for {@link NinePatchChunk}.
+ * When the chunks are created they are serialized into a byte[], and both are put
+ * in the cache, using a {@link SoftReference} for the chunk. The default Java classes
+ * for {@link NinePatch} and {@link NinePatchDrawable} only reference to the byte[] data, and
+ * provide this for drawing.
+ * Using the cache map allows us to not have to deserialize the byte[] back into a
+ * {@link NinePatchChunk} every time a rendering is done.
+ */
+ private final static Map<byte[], SoftReference<NinePatchChunk>> sChunkCache =
+ new HashMap<byte[], SoftReference<NinePatchChunk>>();
+
+ // ---- Public Helper methods ----
+
+ /**
+ * Serializes the given chunk.
+ *
+ * @return the serialized data for the chunk.
+ */
+ public static byte[] serialize(NinePatchChunk chunk) {
+ // serialize the chunk to get a byte[]
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = null;
+ try {
+ oos = new ObjectOutputStream(baos);
+ oos.writeObject(chunk);
+ } catch (IOException e) {
+ Bridge.getLog().error(null, "Failed to serialize NinePatchChunk.", e, null /*data*/);
+ return null;
+ } finally {
+ if (oos != null) {
+ try {
+ oos.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ // get the array and add it to the cache
+ byte[] array = baos.toByteArray();
+ sChunkCache.put(array, new SoftReference<NinePatchChunk>(chunk));
+ return array;
+ }
+
+ /**
+ * Returns a {@link NinePatchChunk} object for the given serialized representation.
+ *
+ * If the chunk is present in the cache then the object from the cache is returned, otherwise
+ * the array is deserialized into a {@link NinePatchChunk} object.
+ *
+ * @param array the serialized representation of the chunk.
+ * @return the NinePatchChunk or null if deserialization failed.
+ */
+ public static NinePatchChunk getChunk(byte[] array) {
+ SoftReference<NinePatchChunk> chunkRef = sChunkCache.get(array);
+ NinePatchChunk chunk = chunkRef.get();
+ if (chunk == null) {
+ ByteArrayInputStream bais = new ByteArrayInputStream(array);
+ ObjectInputStream ois = null;
+ try {
+ ois = new ObjectInputStream(bais);
+ chunk = (NinePatchChunk) ois.readObject();
+
+ // put back the chunk in the cache
+ if (chunk != null) {
+ sChunkCache.put(array, new SoftReference<NinePatchChunk>(chunk));
+ }
+ } catch (IOException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Failed to deserialize NinePatchChunk content.", e, null /*data*/);
+ return null;
+ } catch (ClassNotFoundException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Failed to deserialize NinePatchChunk class.", e, null /*data*/);
+ return null;
+ } finally {
+ if (ois != null) {
+ try {
+ ois.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ return chunk;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isNinePatchChunk(byte[] chunk) {
+ NinePatchChunk chunkObject = getChunk(chunk);
+ if (chunkObject != null) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void validateNinePatchChunk(int bitmap, byte[] chunk) {
+ // the default JNI implementation only checks that the byte[] has the same
+ // size as the C struct it represent. Since we cannot do the same check (serialization
+ // will return different size depending on content), we do nothing.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
+ byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) {
+ draw(canvas_instance,
+ (int) loc.left, (int) loc.top, (int) loc.width(), (int) loc.height(),
+ bitmap_instance, c, paint_instance_or_null,
+ destDensity, srcDensity);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
+ byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) {
+ draw(canvas_instance,
+ loc.left, loc.top, loc.width(), loc.height(),
+ bitmap_instance, c, paint_instance_or_null,
+ destDensity, srcDensity);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeGetTransparentRegion(int bitmap, byte[] chunk, Rect location) {
+ return 0;
+ }
+
+ // ---- Private Helper methods ----
+
+ private static void draw(int canvas_instance,
+ final int left, final int top, final int right, final int bottom,
+ int bitmap_instance, byte[] c, int paint_instance_or_null,
+ final int destDensity, final int srcDensity) {
+ // get the delegate from the native int.
+ final Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance);
+ if (bitmap_delegate == null) {
+ return;
+ }
+
+ if (c == null) {
+ // not a 9-patch?
+ BufferedImage image = bitmap_delegate.getImage();
+ Canvas_Delegate.native_drawBitmap(canvas_instance, bitmap_instance,
+ new Rect(0, 0, image.getWidth(), image.getHeight()),
+ new Rect(left, top, right, bottom),
+ paint_instance_or_null, destDensity, srcDensity);
+ return;
+ }
+
+ final NinePatchChunk chunkObject = getChunk(c);
+ assert chunkObject != null;
+ if (chunkObject == null) {
+ return;
+ }
+
+ Canvas_Delegate canvas_delegate = Canvas_Delegate.getDelegate(canvas_instance);
+ if (canvas_delegate == null) {
+ return;
+ }
+
+ // this one can be null
+ Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null);
+
+ canvas_delegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ chunkObject.draw(bitmap_delegate.getImage(), graphics,
+ left, top, right - left, bottom - top, destDensity, srcDensity);
+ }
+ }, paint_delegate, true /*compositeOnly*/, false /*forceSrcMode*/);
+
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java
deleted file mode 100644
index d13b5fe..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Paint.java
+++ /dev/null
@@ -1,1211 +0,0 @@
-/*
- * 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 android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.SpannedString;
-import android.text.TextUtils;
-
-import java.awt.BasicStroke;
-import java.awt.Font;
-import java.awt.Toolkit;
-import java.awt.font.FontRenderContext;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A paint implementation overridden by the LayoutLib bridge.
- */
-public class Paint extends _Original_Paint {
-
- private int mColor = 0xFFFFFFFF;
- private float mStrokeWidth = 1.f;
- private float mTextSize = 20;
- private float mScaleX = 1;
- private float mSkewX = 0;
- private Align mAlign = Align.LEFT;
- private Style mStyle = Style.FILL;
- private float mStrokeMiter = 4.0f;
- private Cap mCap = Cap.BUTT;
- private Join mJoin = Join.MITER;
- private int mFlags = 0;
-
- /**
- * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
- */
- public static final class FontInfo {
- Font mFont;
- java.awt.FontMetrics mMetrics;
- }
-
- private List<FontInfo> mFonts;
- private final FontRenderContext mFontContext = new FontRenderContext(
- new AffineTransform(), true, true);
-
- public static final int ANTI_ALIAS_FLAG = _Original_Paint.ANTI_ALIAS_FLAG;
- public static final int FILTER_BITMAP_FLAG = _Original_Paint.FILTER_BITMAP_FLAG;
- public static final int DITHER_FLAG = _Original_Paint.DITHER_FLAG;
- public static final int UNDERLINE_TEXT_FLAG = _Original_Paint.UNDERLINE_TEXT_FLAG;
- public static final int STRIKE_THRU_TEXT_FLAG = _Original_Paint.STRIKE_THRU_TEXT_FLAG;
- public static final int FAKE_BOLD_TEXT_FLAG = _Original_Paint.FAKE_BOLD_TEXT_FLAG;
- public static final int LINEAR_TEXT_FLAG = _Original_Paint.LINEAR_TEXT_FLAG;
- public static final int SUBPIXEL_TEXT_FLAG = _Original_Paint.SUBPIXEL_TEXT_FLAG;
- public static final int DEV_KERN_TEXT_FLAG = _Original_Paint.DEV_KERN_TEXT_FLAG;
-
- public static class FontMetrics extends _Original_Paint.FontMetrics {
- }
-
- public static class FontMetricsInt extends _Original_Paint.FontMetricsInt {
- }
-
- /**
- * The Style specifies if the primitive being drawn is filled,
- * stroked, or both (in the same color). The default is FILL.
- */
- public enum Style {
- /**
- * Geometry and text drawn with this style will be filled, ignoring all
- * stroke-related settings in the paint.
- */
- FILL (0),
- /**
- * Geometry and text drawn with this style will be stroked, respecting
- * the stroke-related fields on the paint.
- */
- STROKE (1),
- /**
- * Geometry and text drawn with this style will be both filled and
- * stroked at the same time, respecting the stroke-related fields on
- * the paint.
- */
- FILL_AND_STROKE (2);
-
- Style(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
- /**
- * The Cap specifies the treatment for the beginning and ending of
- * stroked lines and paths. The default is BUTT.
- */
- public enum Cap {
- /**
- * The stroke ends with the path, and does not project beyond it.
- */
- BUTT (0),
- /**
- * The stroke projects out as a square, with the center at the end
- * of the path.
- */
- ROUND (1),
- /**
- * The stroke projects out as a semicircle, with the center at the
- * end of the path.
- */
- SQUARE (2);
-
- private Cap(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
-
- /** custom for layoutlib */
- public int getJavaCap() {
- switch (this) {
- case BUTT:
- return BasicStroke.CAP_BUTT;
- case ROUND:
- return BasicStroke.CAP_ROUND;
- default:
- case SQUARE:
- return BasicStroke.CAP_SQUARE;
- }
- }
- }
-
- /**
- * The Join specifies the treatment where lines and curve segments
- * join on a stroked path. The default is MITER.
- */
- public enum Join {
- /**
- * The outer edges of a join meet at a sharp angle
- */
- MITER (0),
- /**
- * The outer edges of a join meet in a circular arc.
- */
- ROUND (1),
- /**
- * The outer edges of a join meet with a straight line
- */
- BEVEL (2);
-
- private Join(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
-
- /** custom for layoutlib */
- public int getJavaJoin() {
- switch (this) {
- default:
- case MITER:
- return BasicStroke.JOIN_MITER;
- case ROUND:
- return BasicStroke.JOIN_ROUND;
- case BEVEL:
- return BasicStroke.JOIN_BEVEL;
- }
- }
- }
-
- /**
- * Align specifies how drawText aligns its text relative to the
- * [x,y] coordinates. The default is LEFT.
- */
- public enum Align {
- /**
- * The text is drawn to the right of the x,y origin
- */
- LEFT (0),
- /**
- * The text is drawn centered horizontally on the x,y origin
- */
- CENTER (1),
- /**
- * The text is drawn to the left of the x,y origin
- */
- RIGHT (2);
-
- private Align(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
- public Paint() {
- this(0);
- }
-
- /*
- * Do not remove or com.android.layoutlib.bridge.TestClassReplacement fails.
- */
- @Override
- public void finalize() { }
-
- public Paint(int flags) {
- setFlags(flags | DEFAULT_PAINT_FLAGS);
- initFont();
- }
-
- public Paint(Paint paint) {
- set(paint);
- initFont();
- }
-
- @Override
- public void reset() {
- super.reset();
- }
-
- /**
- * Returns the list of {@link Font} objects. The first item is the main font, the rest
- * are fall backs for characters not present in the main font.
- */
- public List<FontInfo> getFonts() {
- return mFonts;
- }
-
- private void initFont() {
- mTypeface = Typeface.DEFAULT;
- updateFontObject();
- }
-
- /**
- * Update the {@link Font} object from the typeface, text size and scaling
- */
- @SuppressWarnings("deprecation")
- private void updateFontObject() {
- if (mTypeface != null) {
- // Get the fonts from the TypeFace object.
- List<Font> fonts = mTypeface.getFonts();
-
- // create new font objects as well as FontMetrics, based on the current text size
- // and skew info.
- ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
- for (Font font : fonts) {
- FontInfo info = new FontInfo();
- info.mFont = font.deriveFont(mTextSize);
- if (mScaleX != 1.0 || mSkewX != 0) {
- // TODO: support skew
- info.mFont = info.mFont.deriveFont(new AffineTransform(
- mScaleX, mSkewX, 0, 0, 1, 0));
- }
- info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
-
- infoList.add(info);
- }
-
- mFonts = Collections.unmodifiableList(infoList);
- }
- }
-
- //----------------------------------------
-
- public void set(Paint src) {
- if (this != src) {
- mColor = src.mColor;
- mTextSize = src.mTextSize;
- mScaleX = src.mScaleX;
- mSkewX = src.mSkewX;
- mAlign = src.mAlign;
- mStyle = src.mStyle;
- mFlags = src.mFlags;
-
- updateFontObject();
-
- super.set(src);
- }
- }
-
- @Override
- public void setCompatibilityScaling(float factor) {
- super.setCompatibilityScaling(factor);
- }
-
- @Override
- public int getFlags() {
- return mFlags;
- }
-
- @Override
- public void setFlags(int flags) {
- mFlags = flags;
- }
-
- @Override
- public boolean isAntiAlias() {
- return super.isAntiAlias();
- }
-
- @Override
- public boolean isDither() {
- return super.isDither();
- }
-
- @Override
- public boolean isLinearText() {
- return super.isLinearText();
- }
-
- @Override
- public boolean isStrikeThruText() {
- return super.isStrikeThruText();
- }
-
- @Override
- public boolean isUnderlineText() {
- return super.isUnderlineText();
- }
-
- @Override
- public boolean isFakeBoldText() {
- return super.isFakeBoldText();
- }
-
- @Override
- public boolean isSubpixelText() {
- return super.isSubpixelText();
- }
-
- @Override
- public boolean isFilterBitmap() {
- return super.isFilterBitmap();
- }
-
- /**
- * Return the font's recommended interline spacing, given the Paint's
- * settings for typeface, textSize, etc. If metrics is not null, return the
- * fontmetric values in it.
- *
- * @param metrics If this object is not null, its fields are filled with
- * the appropriate values given the paint's text attributes.
- * @return the font's recommended interline spacing.
- */
- public float getFontMetrics(FontMetrics metrics) {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- if (metrics != null) {
- // Android expects negative ascent so we invert the value from Java.
- metrics.top = - javaMetrics.getMaxAscent();
- metrics.ascent = - javaMetrics.getAscent();
- metrics.descent = javaMetrics.getDescent();
- metrics.bottom = javaMetrics.getMaxDescent();
- metrics.leading = javaMetrics.getLeading();
- }
-
- return javaMetrics.getHeight();
- }
-
- return 0;
- }
-
- public int getFontMetricsInt(FontMetricsInt metrics) {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- if (metrics != null) {
- // Android expects negative ascent so we invert the value from Java.
- metrics.top = - javaMetrics.getMaxAscent();
- metrics.ascent = - javaMetrics.getAscent();
- metrics.descent = javaMetrics.getDescent();
- metrics.bottom = javaMetrics.getMaxDescent();
- metrics.leading = javaMetrics.getLeading();
- }
-
- return javaMetrics.getHeight();
- }
-
- return 0;
- }
-
- /**
- * Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics
- */
- public FontMetrics getFontMetrics() {
- FontMetrics fm = new FontMetrics();
- getFontMetrics(fm);
- return fm;
- }
-
- /**
- * Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt
- */
- public FontMetricsInt getFontMetricsInt() {
- FontMetricsInt fm = new FontMetricsInt();
- getFontMetricsInt(fm);
- return fm;
- }
-
-
-
- @Override
- public float getFontMetrics(_Original_Paint.FontMetrics metrics) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- @Override
- public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- @Override
- public Typeface setTypeface(Typeface typeface) {
- if (typeface != null) {
- mTypeface = typeface;
- } else {
- mTypeface = Typeface.DEFAULT;
- }
-
- updateFontObject();
-
- return typeface;
- }
-
- @Override
- public Typeface getTypeface() {
- return super.getTypeface();
- }
-
- @Override
- public int getColor() {
- return mColor;
- }
-
- @Override
- public void setColor(int color) {
- mColor = color;
- }
-
- @Override
- public void setARGB(int a, int r, int g, int b) {
- super.setARGB(a, r, g, b);
- }
-
- @Override
- public void setAlpha(int alpha) {
- mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
- }
-
- @Override
- public int getAlpha() {
- return mColor >>> 24;
- }
-
- /**
- * Set or clear the shader object.
- * <p />
- * Pass null to clear any previous shader.
- * As a convenience, the parameter passed is also returned.
- *
- * @param shader May be null. the new shader to be installed in the paint
- * @return shader
- */
- @Override
- public Shader setShader(Shader shader) {
- return mShader = shader;
- }
-
- @Override
- public Shader getShader() {
- return super.getShader();
- }
-
- /**
- * Set or clear the paint's colorfilter, returning the parameter.
- *
- * @param filter May be null. The new filter to be installed in the paint
- * @return filter
- */
- @Override
- public ColorFilter setColorFilter(ColorFilter filter) {
- mColorFilter = filter;
- return filter;
- }
-
- @Override
- public ColorFilter getColorFilter() {
- return super.getColorFilter();
- }
-
- /**
- * Set or clear the xfermode object.
- * <p />
- * Pass null to clear any previous xfermode.
- * As a convenience, the parameter passed is also returned.
- *
- * @param xfermode May be null. The xfermode to be installed in the paint
- * @return xfermode
- */
- @Override
- public Xfermode setXfermode(Xfermode xfermode) {
- return mXfermode = xfermode;
- }
-
- @Override
- public Xfermode getXfermode() {
- return super.getXfermode();
- }
-
- @Override
- public Rasterizer setRasterizer(Rasterizer rasterizer) {
- mRasterizer = rasterizer;
- return rasterizer;
- }
-
- @Override
- public Rasterizer getRasterizer() {
- return super.getRasterizer();
- }
-
- @Override
- public void setShadowLayer(float radius, float dx, float dy, int color) {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void clearShadowLayer() {
- super.clearShadowLayer();
- }
-
- public void setTextAlign(Align align) {
- mAlign = align;
- }
-
- @Override
- public void setTextAlign(android.graphics._Original_Paint.Align align) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public Align getTextAlign() {
- return mAlign;
- }
-
- public void setStyle(Style style) {
- mStyle = style;
- }
-
- @Override
- public void setStyle(android.graphics._Original_Paint.Style style) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public Style getStyle() {
- return mStyle;
- }
-
- @Override
- public void setDither(boolean dither) {
- mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG;
- }
-
- @Override
- public void setAntiAlias(boolean aa) {
- mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG;
- }
-
- @Override
- public void setFakeBoldText(boolean flag) {
- mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG;
- }
-
- @Override
- public void setLinearText(boolean flag) {
- mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG;
- }
-
- @Override
- public void setSubpixelText(boolean flag) {
- mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG;
- }
-
- @Override
- public void setUnderlineText(boolean flag) {
- mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG;
- }
-
- @Override
- public void setStrikeThruText(boolean flag) {
- mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG;
- }
-
- @Override
- public void setFilterBitmap(boolean flag) {
- mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG;
- }
-
- @Override
- public float getStrokeWidth() {
- return mStrokeWidth;
- }
-
- @Override
- public void setStrokeWidth(float width) {
- mStrokeWidth = width;
- }
-
- @Override
- public float getStrokeMiter() {
- return mStrokeMiter;
- }
-
- @Override
- public void setStrokeMiter(float miter) {
- mStrokeMiter = miter;
- }
-
- @Override
- public void setStrokeCap(android.graphics._Original_Paint.Cap cap) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public void setStrokeCap(Cap cap) {
- mCap = cap;
- }
-
- public Cap getStrokeCap() {
- return mCap;
- }
-
- @Override
- public void setStrokeJoin(android.graphics._Original_Paint.Join join) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public void setStrokeJoin(Join join) {
- mJoin = join;
- }
-
- public Join getStrokeJoin() {
- return mJoin;
- }
-
- @Override
- public boolean getFillPath(Path src, Path dst) {
- return super.getFillPath(src, dst);
- }
-
- @Override
- public PathEffect setPathEffect(PathEffect effect) {
- mPathEffect = effect;
- return effect;
- }
-
- @Override
- public PathEffect getPathEffect() {
- return super.getPathEffect();
- }
-
- @Override
- public MaskFilter setMaskFilter(MaskFilter maskfilter) {
- mMaskFilter = maskfilter;
- return maskfilter;
- }
-
- @Override
- public MaskFilter getMaskFilter() {
- return super.getMaskFilter();
- }
-
- /**
- * Return the paint's text size.
- *
- * @return the paint's text size.
- */
- @Override
- public float getTextSize() {
- return mTextSize;
- }
-
- /**
- * Set the paint's text size. This value must be > 0
- *
- * @param textSize set the paint's text size.
- */
- @Override
- public void setTextSize(float textSize) {
- mTextSize = textSize;
-
- updateFontObject();
- }
-
- /**
- * Return the paint's horizontal scale factor for text. The default value
- * is 1.0.
- *
- * @return the paint's scale factor in X for drawing/measuring text
- */
- @Override
- public float getTextScaleX() {
- return mScaleX;
- }
-
- /**
- * Set the paint's horizontal scale factor for text. The default value
- * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
- * stretch the text narrower.
- *
- * @param scaleX set the paint's scale in X for drawing/measuring text.
- */
- @Override
- public void setTextScaleX(float scaleX) {
- mScaleX = scaleX;
-
- updateFontObject();
- }
-
- /**
- * Return the paint's horizontal skew factor for text. The default value
- * is 0.
- *
- * @return the paint's skew factor in X for drawing text.
- */
- @Override
- public float getTextSkewX() {
- return mSkewX;
- }
-
- /**
- * Set the paint's horizontal skew factor for text. The default value
- * is 0. For approximating oblique text, use values around -0.25.
- *
- * @param skewX set the paint's skew factor in X for drawing text.
- */
- @Override
- public void setTextSkewX(float skewX) {
- mSkewX = skewX;
-
- updateFontObject();
- }
-
- @Override
- public float getFontSpacing() {
- return super.getFontSpacing();
- }
-
- /**
- * Return the distance above (negative) the baseline (ascent) based on the
- * current typeface and text size.
- *
- * @return the distance above (negative) the baseline (ascent) based on the
- * current typeface and text size.
- */
- @Override
- public float ascent() {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- // Android expects negative ascent so we invert the value from Java.
- return - javaMetrics.getAscent();
- }
-
- return 0;
- }
-
- /**
- * Return the distance below (positive) the baseline (descent) based on the
- * current typeface and text size.
- *
- * @return the distance below (positive) the baseline (descent) based on
- * the current typeface and text size.
- */
- @Override
- public float descent() {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- return javaMetrics.getDescent();
- }
-
- return 0;
- }
-
- /**
- * Return the width of the text.
- *
- * @param text The text to measure
- * @param index The index of the first character to start measuring
- * @param count THe number of characters to measure, beginning with start
- * @return The width of the text
- */
- @Override
- public float measureText(char[] text, int index, int count) {
- // WARNING: the logic in this method is similar to Canvas.drawText.
- // Any change to this method should be reflected in Canvas.drawText
- if (mFonts.size() > 0) {
- FontInfo mainFont = mFonts.get(0);
- int i = index;
- int lastIndex = index + count;
- float total = 0f;
- while (i < lastIndex) {
- // always start with the main font.
- int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
- if (upTo == -1) {
- // shortcut to exit
- return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
- } else if (upTo > 0) {
- total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
- i = upTo;
- // don't call continue at this point. Since it is certain the main font
- // cannot display the font a index upTo (now ==i), we move on to the
- // fallback fonts directly.
- }
-
- // no char supported, attempt to read the next char(s) with the
- // fallback font. In this case we only test the first character
- // and then go back to test with the main font.
- // Special test for 2-char characters.
- boolean foundFont = false;
- for (int f = 1 ; f < mFonts.size() ; f++) {
- FontInfo fontInfo = mFonts.get(f);
-
- // need to check that the font can display the character. We test
- // differently if the char is a high surrogate.
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
- upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
- if (upTo == -1) {
- total += fontInfo.mMetrics.charsWidth(text, i, charCount);
- i += charCount;
- foundFont = true;
- break;
-
- }
- }
-
- // in case no font can display the char, measure it with the main font.
- if (foundFont == false) {
- int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
- total += mainFont.mMetrics.charsWidth(text, i, size);
- i += size;
- }
- }
- }
-
- return 0;
- }
-
- /**
- * Return the width of the text.
- *
- * @param text The text to measure
- * @param start The index of the first character to start measuring
- * @param end 1 beyond the index of the last character to measure
- * @return The width of the text
- */
- @Override
- public float measureText(String text, int start, int end) {
- return measureText(text.toCharArray(), start, end - start);
- }
-
- /**
- * Return the width of the text.
- *
- * @param text The text to measure
- * @return The width of the text
- */
- @Override
- public float measureText(String text) {
- return measureText(text.toCharArray(), 0, text.length());
- }
-
- /*
- * re-implement to call SpannableStringBuilder.measureText with a Paint object
- * instead of an _Original_Paint
- */
- @Override
- public float measureText(CharSequence text, int start, int end) {
- if (text instanceof String) {
- return measureText((String)text, start, end);
- }
- if (text instanceof SpannedString ||
- text instanceof SpannableString) {
- return measureText(text.toString(), start, end);
- }
- if (text instanceof SpannableStringBuilder) {
- return ((SpannableStringBuilder)text).measureText(start, end, this);
- }
-
- char[] buf = TemporaryBuffer.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
- float result = measureText(buf, 0, end - start);
- TemporaryBuffer.recycle(buf);
- return result;
- }
-
- /**
- * Measure the text, stopping early if the measured width exceeds maxWidth.
- * Return the number of chars that were measured, and if measuredWidth is
- * not null, return in it the actual width measured.
- *
- * @param text The text to measure
- * @param index The offset into text to begin measuring at
- * @param count The number of maximum number of entries to measure. If count
- * is negative, then the characters before index are measured
- * in reverse order. This allows for measuring the end of
- * string.
- * @param maxWidth The maximum width to accumulate.
- * @param measuredWidth Optional. If not null, returns the actual width
- * measured.
- * @return The number of chars that were measured. Will always be <=
- * abs(count).
- */
- @Override
- public int breakText(char[] text, int index, int count,
- float maxWidth, float[] measuredWidth) {
- int inc = count > 0 ? 1 : -1;
-
- int measureIndex = 0;
- float measureAcc = 0;
- for (int i = index ; i != index + count ; i += inc, measureIndex++) {
- int start, end;
- if (i < index) {
- start = i;
- end = index;
- } else {
- start = index;
- end = i;
- }
-
- // measure from start to end
- float res = measureText(text, start, end - start + 1);
-
- if (measuredWidth != null) {
- measuredWidth[measureIndex] = res;
- }
-
- measureAcc += res;
- if (res > maxWidth) {
- // we should not return this char index, but since it's 0-based and we need
- // to return a count, we simply return measureIndex;
- return measureIndex;
- }
-
- }
-
- return measureIndex;
- }
-
- /**
- * Measure the text, stopping early if the measured width exceeds maxWidth.
- * Return the number of chars that were measured, and if measuredWidth is
- * not null, return in it the actual width measured.
- *
- * @param text The text to measure
- * @param measureForwards If true, measure forwards, starting at index.
- * Otherwise, measure backwards, starting with the
- * last character in the string.
- * @param maxWidth The maximum width to accumulate.
- * @param measuredWidth Optional. If not null, returns the actual width
- * measured.
- * @return The number of chars that were measured. Will always be <=
- * abs(count).
- */
- @Override
- public int breakText(String text, boolean measureForwards,
- float maxWidth, float[] measuredWidth) {
- return breakText(text,
- 0 /* start */, text.length() /* end */,
- measureForwards, maxWidth, measuredWidth);
- }
-
- /**
- * Measure the text, stopping early if the measured width exceeds maxWidth.
- * Return the number of chars that were measured, and if measuredWidth is
- * not null, return in it the actual width measured.
- *
- * @param text The text to measure
- * @param start The offset into text to begin measuring at
- * @param end The end of the text slice to measure.
- * @param measureForwards If true, measure forwards, starting at start.
- * Otherwise, measure backwards, starting with end.
- * @param maxWidth The maximum width to accumulate.
- * @param measuredWidth Optional. If not null, returns the actual width
- * measured.
- * @return The number of chars that were measured. Will always be <=
- * abs(end - start).
- */
- @Override
- public int breakText(CharSequence text, int start, int end, boolean measureForwards,
- float maxWidth, float[] measuredWidth) {
- char[] buf = new char[end - start];
- int result;
-
- TextUtils.getChars(text, start, end, buf, 0);
-
- if (measureForwards) {
- result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
- } else {
- result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
- }
-
- return result;
- }
-
- /**
- * Return the advance widths for the characters in the string.
- *
- * @param text The text to measure
- * @param index The index of the first char to to measure
- * @param count The number of chars starting with index to measure
- * @param widths array to receive the advance widths of the characters.
- * Must be at least a large as count.
- * @return the actual number of widths returned.
- */
- @Override
- public int getTextWidths(char[] text, int index, int count,
- float[] widths) {
- if (mFonts.size() > 0) {
- if ((index | count) < 0 || index + count > text.length
- || count > widths.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // FIXME: handle multi-char characters.
- // Need to figure out if the lengths of the width array takes into account
- // multi-char characters.
- for (int i = 0; i < count; i++) {
- char c = text[i + index];
- boolean found = false;
- for (FontInfo info : mFonts) {
- if (info.mFont.canDisplay(c)) {
- widths[i] = info.mMetrics.charWidth(c);
- found = true;
- break;
- }
- }
-
- if (found == false) {
- // we stop there.
- return i;
- }
- }
-
- return count;
- }
-
- return 0;
- }
-
- /**
- * Return the advance widths for the characters in the string.
- *
- * @param text The text to measure
- * @param start The index of the first char to to measure
- * @param end The end of the text slice to measure
- * @param widths array to receive the advance widths of the characters.
- * Must be at least a large as the text.
- * @return the number of unichars in the specified text.
- */
- @Override
- public int getTextWidths(String text, int start, int end, float[] widths) {
- if ((start | end | (end - start) | (text.length() - end)) < 0) {
- throw new IndexOutOfBoundsException();
- }
- if (end - start > widths.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- return getTextWidths(text.toCharArray(), start, end - start, widths);
- }
-
- /*
- * re-implement to call SpannableStringBuilder.getTextWidths with a Paint object
- * instead of an _Original_Paint
- */
- @Override
- public int getTextWidths(CharSequence text, int start, int end, float[] widths) {
- if (text instanceof String) {
- return getTextWidths((String)text, start, end, widths);
- }
- if (text instanceof SpannedString || text instanceof SpannableString) {
- return getTextWidths(text.toString(), start, end, widths);
- }
- if (text instanceof SpannableStringBuilder) {
- return ((SpannableStringBuilder)text).getTextWidths(start, end, widths, this);
- }
-
- char[] buf = TemporaryBuffer.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
- int result = getTextWidths(buf, 0, end - start, widths);
- TemporaryBuffer.recycle(buf);
- return result;
- }
-
- @Override
- public int getTextWidths(String text, float[] widths) {
- return super.getTextWidths(text, widths);
- }
-
- /**
- * Return the path (outline) for the specified text.
- * Note: just like Canvas.drawText, this will respect the Align setting in
- * the paint.
- *
- * @param text The text to retrieve the path from
- * @param index The index of the first character in text
- * @param count The number of characterss starting with index
- * @param x The x coordinate of the text's origin
- * @param y The y coordinate of the text's origin
- * @param path The path to receive the data describing the text. Must
- * be allocated by the caller.
- */
- @Override
- public void getTextPath(char[] text, int index, int count,
- float x, float y, Path path) {
-
- // TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE
-
- if ((index | count) < 0 || index + count > text.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
-
- throw new UnsupportedOperationException("IMPLEMENT AS NEEDED");
- }
-
- /**
- * Return the path (outline) for the specified text.
- * Note: just like Canvas.drawText, this will respect the Align setting
- * in the paint.
- *
- * @param text The text to retrieve the path from
- * @param start The first character in the text
- * @param end 1 past the last charcter in the text
- * @param x The x coordinate of the text's origin
- * @param y The y coordinate of the text's origin
- * @param path The path to receive the data describing the text. Must
- * be allocated by the caller.
- */
- @Override
- public void getTextPath(String text, int start, int end,
- float x, float y, Path path) {
- if ((start | end | (end - start) | (text.length() - end)) < 0) {
- throw new IndexOutOfBoundsException();
- }
-
- getTextPath(text.toCharArray(), start, end - start, x, y, path);
- }
-
- /**
- * Return in bounds (allocated by the caller) the smallest rectangle that
- * encloses all of the characters, with an implied origin at (0,0).
- *
- * @param text String to measure and return its bounds
- * @param start Index of the first char in the string to measure
- * @param end 1 past the last char in the string measure
- * @param bounds Returns the unioned bounds of all the text. Must be
- * allocated by the caller.
- */
- @Override
- public void getTextBounds(String text, int start, int end, Rect bounds) {
- if ((start | end | (end - start) | (text.length() - end)) < 0) {
- throw new IndexOutOfBoundsException();
- }
- if (bounds == null) {
- throw new NullPointerException("need bounds Rect");
- }
-
- getTextBounds(text.toCharArray(), start, end - start, bounds);
- }
-
- /**
- * Return in bounds (allocated by the caller) the smallest rectangle that
- * encloses all of the characters, with an implied origin at (0,0).
- *
- * @param text Array of chars to measure and return their unioned bounds
- * @param index Index of the first char in the array to measure
- * @param count The number of chars, beginning at index, to measure
- * @param bounds Returns the unioned bounds of all the text. Must be
- * allocated by the caller.
- */
- @Override
- public void getTextBounds(char[] text, int index, int count, Rect bounds) {
- // FIXME
- if (mFonts.size() > 0) {
- if ((index | count) < 0 || index + count > text.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
- if (bounds == null) {
- throw new NullPointerException("need bounds Rect");
- }
-
- FontInfo mainInfo = mFonts.get(0);
-
- Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext);
- bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight());
- }
- }
-
- public static void finalizer(int foo) {
- // pass
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
new file mode 100644
index 0000000..71d346a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PaintFlagsDrawFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of PaintFlagsDrawFilter have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original PaintFlagsDrawFilter class.
+ *
+ * Because this extends {@link DrawFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the DrawFilter classes will be added to the manager owned by
+ * {@link DrawFilter_Delegate}.
+ *
+ * @see DrawFilter_Delegate
+ *
+ */
+public class PaintFlagsDrawFilter_Delegate extends DrawFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Paint Flags Draw Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConstructor(int clearBits, int setBits) {
+ PaintFlagsDrawFilter_Delegate newDelegate = new PaintFlagsDrawFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
new file mode 100644
index 0000000..d4cf1f6
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -0,0 +1,1163 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Paint.FontMetrics;
+import android.graphics.Paint.FontMetricsInt;
+
+import java.awt.BasicStroke;
+import java.awt.Font;
+import java.awt.Shape;
+import java.awt.Stroke;
+import java.awt.Toolkit;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Paint
+ *
+ * Through the layoutlib_create tool, the original native methods of Paint have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Paint class.
+ *
+ * @see DelegateManager
+ *
+ */
+public class Paint_Delegate {
+
+ /**
+ * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
+ */
+ /*package*/ static final class FontInfo {
+ Font mFont;
+ java.awt.FontMetrics mMetrics;
+ }
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Paint_Delegate> sManager =
+ new DelegateManager<Paint_Delegate>(Paint_Delegate.class);
+
+ // ---- delegate helper data ----
+ private List<FontInfo> mFonts;
+ private final FontRenderContext mFontContext = new FontRenderContext(
+ new AffineTransform(), true, true);
+
+ // ---- delegate data ----
+ private int mFlags;
+ private int mColor;
+ private int mStyle;
+ private int mCap;
+ private int mJoin;
+ private int mTextAlign;
+ private Typeface_Delegate mTypeface;
+ private float mStrokeWidth;
+ private float mStrokeMiter;
+ private float mTextSize;
+ private float mTextScaleX;
+ private float mTextSkewX;
+
+ private Xfermode_Delegate mXfermode;
+ private ColorFilter_Delegate mColorFilter;
+ private Shader_Delegate mShader;
+ private PathEffect_Delegate mPathEffect;
+ private MaskFilter_Delegate mMaskFilter;
+ private Rasterizer_Delegate mRasterizer;
+
+ // ---- Public Helper methods ----
+
+ public static Paint_Delegate getDelegate(int native_paint) {
+ return sManager.getDelegate(native_paint);
+ }
+
+ /**
+ * Returns the list of {@link Font} objects. The first item is the main font, the rest
+ * are fall backs for characters not present in the main font.
+ */
+ public List<FontInfo> getFonts() {
+ return mFonts;
+ }
+
+ public boolean isAntiAliased() {
+ return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0;
+ }
+
+ public boolean isFilterBitmap() {
+ return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0;
+ }
+
+ public int getStyle() {
+ return mStyle;
+ }
+
+ public int getColor() {
+ return mColor;
+ }
+
+ public int getAlpha() {
+ return mColor >>> 24;
+ }
+
+ public void setAlpha(int alpha) {
+ mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
+ }
+
+ public int getTextAlign() {
+ return mTextAlign;
+ }
+
+ public float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+
+ /**
+ * returns the value of stroke miter needed by the java api.
+ */
+ public float getJavaStrokeMiter() {
+ float miter = mStrokeMiter * mStrokeWidth;
+ if (miter < 1.f) {
+ miter = 1.f;
+ }
+ return miter;
+ }
+
+ public int getJavaCap() {
+ switch (Paint.sCapArray[mCap]) {
+ case BUTT:
+ return BasicStroke.CAP_BUTT;
+ case ROUND:
+ return BasicStroke.CAP_ROUND;
+ default:
+ case SQUARE:
+ return BasicStroke.CAP_SQUARE;
+ }
+ }
+
+ public int getJavaJoin() {
+ switch (Paint.sJoinArray[mJoin]) {
+ default:
+ case MITER:
+ return BasicStroke.JOIN_MITER;
+ case ROUND:
+ return BasicStroke.JOIN_ROUND;
+ case BEVEL:
+ return BasicStroke.JOIN_BEVEL;
+ }
+ }
+
+ public Stroke getJavaStroke() {
+ if (mPathEffect != null) {
+ if (mPathEffect.isSupported()) {
+ Stroke stroke = mPathEffect.getStroke(this);
+ assert stroke != null;
+ if (stroke != null) {
+ return stroke;
+ }
+ } else {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT,
+ mPathEffect.getSupportMessage(),
+ null, null /*data*/);
+ }
+ }
+
+ // if no custom stroke as been set, set the default one.
+ return new BasicStroke(
+ getStrokeWidth(),
+ getJavaCap(),
+ getJavaJoin(),
+ getJavaStrokeMiter());
+ }
+
+ /**
+ * Returns the {@link Xfermode} delegate or null if none have been set
+ *
+ * @return the delegate or null.
+ */
+ public Xfermode_Delegate getXfermode() {
+ return mXfermode;
+ }
+
+ /**
+ * Returns the {@link ColorFilter} delegate or null if none have been set
+ *
+ * @return the delegate or null.
+ */
+ public ColorFilter_Delegate getColorFilter() {
+ return mColorFilter;
+ }
+
+ /**
+ * Returns the {@link Shader} delegate or null if none have been set
+ *
+ * @return the delegate or null.
+ */
+ public Shader_Delegate getShader() {
+ return mShader;
+ }
+
+ /**
+ * Returns the {@link MaskFilter} delegate or null if none have been set
+ *
+ * @return the delegate or null.
+ */
+ public MaskFilter_Delegate getMaskFilter() {
+ return mMaskFilter;
+ }
+
+ /**
+ * Returns the {@link Rasterizer} delegate or null if none have been set
+ *
+ * @return the delegate or null.
+ */
+ public Rasterizer_Delegate getRasterizer() {
+ return mRasterizer;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int getFlags(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mFlags;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setFlags(Paint thisPaint, int flags) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mFlags = flags;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
+ setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
+ setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
+ setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
+ setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
+ setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
+ setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setDither(Paint thisPaint, boolean dither) {
+ setFlag(thisPaint, Paint.DITHER_FLAG, dither);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
+ setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getColor(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mColor;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setColor(Paint thisPaint, int color) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mColor = color;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getAlpha(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.getAlpha();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setAlpha(Paint thisPaint, int a) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.setAlpha(a);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getStrokeWidth(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 1.f;
+ }
+
+ return delegate.mStrokeWidth;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mStrokeWidth = width;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getStrokeMiter(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 1.f;
+ }
+
+ return delegate.mStrokeMiter;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mStrokeMiter = miter;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setShadowLayer(Paint thisPaint, float radius, float dx, float dy,
+ int color) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.setShadowLayer is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getTextSize(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 1.f;
+ }
+
+ return delegate.mTextSize;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mTextSize = textSize;
+ delegate.updateFontObject();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getTextScaleX(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 1.f;
+ }
+
+ return delegate.mTextScaleX;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mTextScaleX = scaleX;
+ delegate.updateFontObject();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getTextSkewX(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 1.f;
+ }
+
+ return delegate.mTextSkewX;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mTextSkewX = skewX;
+ delegate.updateFontObject();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float ascent(Paint thisPaint) {
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
+ // Android expects negative ascent so we invert the value from Java.
+ return - javaMetrics.getAscent();
+ }
+
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float descent(Paint thisPaint) {
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
+ return javaMetrics.getDescent();
+ }
+
+ return 0;
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.getFontMetrics(metrics);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
+ if (fmi != null) {
+ // Android expects negative ascent so we invert the value from Java.
+ fmi.top = - javaMetrics.getMaxAscent();
+ fmi.ascent = - javaMetrics.getAscent();
+ fmi.descent = javaMetrics.getDescent();
+ fmi.bottom = javaMetrics.getMaxDescent();
+ fmi.leading = javaMetrics.getLeading();
+ }
+
+ return javaMetrics.getHeight();
+ }
+
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
+ int count) {
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.measureText(text, index, count);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
+ return native_measureText(thisPaint, text.toCharArray(), start, end - start);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_measureText(Paint thisPaint, String text) {
+ return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
+ float maxWidth, float[] measuredWidth) {
+
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ int inc = count > 0 ? 1 : -1;
+
+ int measureIndex = 0;
+ float measureAcc = 0;
+ for (int i = index; i != index + count; i += inc, measureIndex++) {
+ int start, end;
+ if (i < index) {
+ start = i;
+ end = index;
+ } else {
+ start = index;
+ end = i;
+ }
+
+ // measure from start to end
+ float res = delegate.measureText(text, start, end - start + 1);
+
+ if (measuredWidth != null) {
+ measuredWidth[measureIndex] = res;
+ }
+
+ measureAcc += res;
+ if (res > maxWidth) {
+ // we should not return this char index, but since it's 0-based
+ // and we need to return a count, we simply return measureIndex;
+ return measureIndex;
+ }
+
+ }
+
+ return measureIndex;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
+ float maxWidth, float[] measuredWidth) {
+ return native_breakText(thisPaint, text.toCharArray(), 0, text.length(), maxWidth,
+ measuredWidth);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_init() {
+ Paint_Delegate newDelegate = new Paint_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_initWithPaint(int paint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(paint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ Paint_Delegate newDelegate = new Paint_Delegate(delegate);
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_reset(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.reset();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_set(int native_dst, int native_src) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
+ if (delegate_dst == null) {
+ return;
+ }
+
+ // get the delegate from the native int.
+ Paint_Delegate delegate_src = sManager.getDelegate(native_src);
+ if (delegate_src == null) {
+ return;
+ }
+
+ delegate_dst.set(delegate_src);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getStyle(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mStyle;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setStyle(int native_object, int style) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mStyle = style;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getStrokeCap(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mCap;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setStrokeCap(int native_object, int cap) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mCap = cap;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getStrokeJoin(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mJoin;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setStrokeJoin(int native_object, int join) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mJoin = join;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
+ Paint_Delegate paint = sManager.getDelegate(native_object);
+ if (paint == null) {
+ return false;
+ }
+
+ Path_Delegate srcPath = Path_Delegate.getDelegate(src);
+ if (srcPath == null) {
+ return true;
+ }
+
+ Path_Delegate dstPath = Path_Delegate.getDelegate(dst);
+ if (dstPath == null) {
+ return true;
+ }
+
+ Stroke stroke = paint.getJavaStroke();
+ Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape());
+
+ dstPath.setJavaShape(strokeShape);
+
+ // FIXME figure out the return value?
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setShader(int native_object, int shader) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return shader;
+ }
+
+ delegate.mShader = Shader_Delegate.getDelegate(shader);
+
+ return shader;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setColorFilter(int native_object, int filter) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return filter;
+ }
+
+ delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);;
+
+ // since none of those are supported, display a fidelity warning right away
+ if (delegate.mColorFilter != null && delegate.mColorFilter.isSupported() == false) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER,
+ delegate.mColorFilter.getSupportMessage(), null, null /*data*/);
+ }
+
+ return filter;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setXfermode(int native_object, int xfermode) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return xfermode;
+ }
+
+ delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode);
+
+ return xfermode;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setPathEffect(int native_object, int effect) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return effect;
+ }
+
+ delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect);
+
+ return effect;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return maskfilter;
+ }
+
+ delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter);
+
+ // since none of those are supported, display a fidelity warning right away
+ if (delegate.mMaskFilter != null && delegate.mMaskFilter.isSupported() == false) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
+ delegate.mMaskFilter.getSupportMessage(), null, null /*data*/);
+ }
+
+ return maskfilter;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setTypeface(int native_object, int typeface) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ delegate.mTypeface = Typeface_Delegate.getDelegate(typeface);
+ delegate.updateFontObject();
+ return typeface;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return rasterizer;
+ }
+
+ delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer);
+
+ // since none of those are supported, display a fidelity warning right away
+ if (delegate.mRasterizer != null && delegate.mRasterizer.isSupported() == false) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER,
+ delegate.mRasterizer.getSupportMessage(), null, null /*data*/);
+ }
+
+ return rasterizer;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getTextAlign(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mTextAlign;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setTextAlign(int native_object, int align) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mTextAlign = align;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_paint);
+ if (delegate == null) {
+ return 0.f;
+ }
+
+ return delegate.getFontMetrics(metrics);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
+ int count, float[] widths) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ // FIXME: handle multi-char characters (see measureText)
+ float totalAdvance = 0;
+ for (int i = 0; i < count; i++) {
+ char c = text[i + index];
+ boolean found = false;
+ for (FontInfo info : delegate.mFonts) {
+ if (info.mFont.canDisplay(c)) {
+ float adv = info.mMetrics.charWidth(c);
+ totalAdvance += adv;
+ if (widths != null) {
+ widths[i] = adv;
+ }
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ // no advance for this char.
+ if (widths != null) {
+ widths[i] = 0.f;
+ }
+ }
+ }
+
+ return (int) totalAdvance;
+ }
+
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getTextWidths(int native_object, String text, int start,
+ int end, float[] widths) {
+ return native_getTextWidths(native_object, text.toCharArray(), start, end - start, widths);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_getTextPath(int native_object,
+ char[] text, int index, int count, float x, float y, int path) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextPath is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_getTextPath(int native_object,
+ String text, int start, int end, float x, float y, int path) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextPath is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
+ int end, Rect bounds) {
+ nativeGetCharArrayBounds(nativePaint, text.toCharArray(), start, end - start, bounds);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
+ int count, Rect bounds) {
+
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ // FIXME should test if the main font can display all those characters.
+ // See MeasureText
+ if (delegate.mFonts.size() > 0) {
+ FontInfo mainInfo = delegate.mFonts.get(0);
+
+ Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count,
+ delegate.mFontContext);
+ bounds.set(0, 0, (int) rect.getWidth(), (int) rect.getHeight());
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int nativePaint) {
+ sManager.removeJavaReferenceFor(nativePaint);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ /*package*/ Paint_Delegate() {
+ reset();
+ }
+
+ private Paint_Delegate(Paint_Delegate paint) {
+ set(paint);
+ }
+
+ private void set(Paint_Delegate paint) {
+ mFlags = paint.mFlags;
+ mColor = paint.mColor;
+ mStyle = paint.mStyle;
+ mCap = paint.mCap;
+ mJoin = paint.mJoin;
+ mTextAlign = paint.mTextAlign;
+ mTypeface = paint.mTypeface;
+ mStrokeWidth = paint.mStrokeWidth;
+ mStrokeMiter = paint.mStrokeMiter;
+ mTextSize = paint.mTextSize;
+ mTextScaleX = paint.mTextScaleX;
+ mTextSkewX = paint.mTextSkewX;
+ mXfermode = paint.mXfermode;
+ mColorFilter = paint.mColorFilter;
+ mShader = paint.mShader;
+ mPathEffect = paint.mPathEffect;
+ mMaskFilter = paint.mMaskFilter;
+ mRasterizer = paint.mRasterizer;
+ updateFontObject();
+ }
+
+ private void reset() {
+ mFlags = Paint.DEFAULT_PAINT_FLAGS;
+ mColor = 0xFF000000;
+ mStyle = Paint.Style.FILL.nativeInt;
+ mCap = Paint.Cap.BUTT.nativeInt;
+ mJoin = Paint.Join.MITER.nativeInt;
+ mTextAlign = 0;
+ mTypeface = Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance);
+ mStrokeWidth = 1.f;
+ mStrokeMiter = 4.f;
+ mTextSize = 20.f;
+ mTextScaleX = 1.f;
+ mTextSkewX = 0.f;
+ mXfermode = null;
+ mColorFilter = null;
+ mShader = null;
+ mPathEffect = null;
+ mMaskFilter = null;
+ mRasterizer = null;
+ updateFontObject();
+ }
+
+ /**
+ * Update the {@link Font} object from the typeface, text size and scaling
+ */
+ @SuppressWarnings("deprecation")
+ private void updateFontObject() {
+ if (mTypeface != null) {
+ // Get the fonts from the TypeFace object.
+ List<Font> fonts = mTypeface.getFonts();
+
+ // create new font objects as well as FontMetrics, based on the current text size
+ // and skew info.
+ ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
+ for (Font font : fonts) {
+ FontInfo info = new FontInfo();
+ info.mFont = font.deriveFont(mTextSize);
+ if (mTextScaleX != 1.0 || mTextSkewX != 0) {
+ // TODO: support skew
+ info.mFont = info.mFont.deriveFont(new AffineTransform(
+ mTextScaleX, mTextSkewX, 0, 0, 1, 0));
+ }
+ info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
+
+ infoList.add(info);
+ }
+
+ mFonts = Collections.unmodifiableList(infoList);
+ }
+ }
+
+ /*package*/ float measureText(char[] text, int index, int count) {
+
+ // WARNING: the logic in this method is similar to Canvas_Delegate.native_drawText
+ // Any change to this method should be reflected there as well
+
+ if (mFonts.size() > 0) {
+ FontInfo mainFont = mFonts.get(0);
+ int i = index;
+ int lastIndex = index + count;
+ float total = 0f;
+ while (i < lastIndex) {
+ // always start with the main font.
+ int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+ if (upTo == -1) {
+ // shortcut to exit
+ return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
+ } else if (upTo > 0) {
+ total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+ i = upTo;
+ // don't call continue at this point. Since it is certain the main font
+ // cannot display the font a index upTo (now ==i), we move on to the
+ // fallback fonts directly.
+ }
+
+ // no char supported, attempt to read the next char(s) with the
+ // fallback font. In this case we only test the first character
+ // and then go back to test with the main font.
+ // Special test for 2-char characters.
+ boolean foundFont = false;
+ for (int f = 1 ; f < mFonts.size() ; f++) {
+ FontInfo fontInfo = mFonts.get(f);
+
+ // need to check that the font can display the character. We test
+ // differently if the char is a high surrogate.
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+ if (upTo == -1) {
+ total += fontInfo.mMetrics.charsWidth(text, i, charCount);
+ i += charCount;
+ foundFont = true;
+ break;
+
+ }
+ }
+
+ // in case no font can display the char, measure it with the main font.
+ if (foundFont == false) {
+ int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ total += mainFont.mMetrics.charsWidth(text, i, size);
+ i += size;
+ }
+ }
+
+ return total;
+ }
+
+ return 0;
+ }
+
+ private float getFontMetrics(FontMetrics metrics) {
+ if (mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
+ if (metrics != null) {
+ // Android expects negative ascent so we invert the value from Java.
+ metrics.top = - javaMetrics.getMaxAscent();
+ metrics.ascent = - javaMetrics.getAscent();
+ metrics.descent = javaMetrics.getDescent();
+ metrics.bottom = javaMetrics.getMaxDescent();
+ metrics.leading = javaMetrics.getLeading();
+ }
+
+ return javaMetrics.getHeight();
+ }
+
+ return 0;
+ }
+
+
+
+ private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ if (flagValue) {
+ delegate.mFlags |= flagMask;
+ } else {
+ delegate.mFlags &= ~flagMask;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path.java b/tools/layoutlib/bridge/src/android/graphics/Path.java
deleted file mode 100644
index 12d2cde..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Path.java
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
- * 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 android.graphics;
-
-import java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Rectangle2D;
-
-/**
- * The Path class encapsulates compound (multiple contour) geometric paths
- * consisting of straight line segments, quadratic curves, and cubic curves.
- * It can be drawn with canvas.drawPath(path, paint), either filled or stroked
- * (based on the paint's Style), or it can be used for clipping or to draw
- * text on a path.
- */
-public class Path {
-
- private FillType mFillType = FillType.WINDING;
- private GeneralPath mPath = new GeneralPath();
-
- private float mLastX = 0;
- private float mLastY = 0;
-
- //---------- Custom methods ----------
-
- public Shape getAwtShape() {
- return mPath;
- }
-
- //----------
-
- /**
- * Create an empty path
- */
- public Path() {
- }
-
- /**
- * Create a new path, copying the contents from the src path.
- *
- * @param src The path to copy from when initializing the new path
- */
- public Path(Path src) {
- mPath.append(src.mPath, false /* connect */);
- }
-
- /**
- * Clear any lines and curves from the path, making it empty.
- * This does NOT change the fill-type setting.
- */
- public void reset() {
- mPath = new GeneralPath();
- }
-
- /**
- * Rewinds the path: clears any lines and curves from the path but
- * keeps the internal data structure for faster reuse.
- */
- public void rewind() {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /** Replace the contents of this with the contents of src.
- */
- public void set(Path src) {
- mPath.append(src.mPath, false /* connect */);
- }
-
- /** Enum for the ways a path may be filled
- */
- public enum FillType {
- // these must match the values in SkPath.h
- WINDING (GeneralPath.WIND_NON_ZERO, false),
- EVEN_ODD (GeneralPath.WIND_EVEN_ODD, false),
- INVERSE_WINDING (GeneralPath.WIND_NON_ZERO, true),
- INVERSE_EVEN_ODD(GeneralPath.WIND_EVEN_ODD, true);
-
- FillType(int rule, boolean inverse) {
- this.rule = rule;
- this.inverse = inverse;
- }
-
- final int rule;
- final boolean inverse;
- }
-
- /**
- * Return the path's fill type. This defines how "inside" is
- * computed. The default value is WINDING.
- *
- * @return the path's fill type
- */
- public FillType getFillType() {
- return mFillType;
- }
-
- /**
- * Set the path's fill type. This defines how "inside" is computed.
- *
- * @param ft The new fill type for this path
- */
- public void setFillType(FillType ft) {
- mFillType = ft;
- mPath.setWindingRule(ft.rule);
- }
-
- /**
- * Returns true if the filltype is one of the INVERSE variants
- *
- * @return true if the filltype is one of the INVERSE variants
- */
- public boolean isInverseFillType() {
- return mFillType.inverse;
- }
-
- /**
- * Toggles the INVERSE state of the filltype
- */
- public void toggleInverseFillType() {
- switch (mFillType) {
- case WINDING:
- mFillType = FillType.INVERSE_WINDING;
- break;
- case EVEN_ODD:
- mFillType = FillType.INVERSE_EVEN_ODD;
- break;
- case INVERSE_WINDING:
- mFillType = FillType.WINDING;
- break;
- case INVERSE_EVEN_ODD:
- mFillType = FillType.EVEN_ODD;
- break;
- }
- }
-
- /**
- * Returns true if the path is empty (contains no lines or curves)
- *
- * @return true if the path is empty (contains no lines or curves)
- */
- public boolean isEmpty() {
- return mPath.getCurrentPoint() == null;
- }
-
- /**
- * Returns true if the path specifies a rectangle. If so, and if rect is
- * not null, set rect to the bounds of the path. If the path does not
- * specify a rectangle, return false and ignore rect.
- *
- * @param rect If not null, returns the bounds of the path if it specifies
- * a rectangle
- * @return true if the path specifies a rectangle
- */
- public boolean isRect(RectF rect) {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Compute the bounds of the path, and write the answer into bounds. If the
- * path contains 0 or 1 points, the bounds is set to (0,0,0,0)
- *
- * @param bounds Returns the computed bounds of the path
- * @param exact If true, return the exact (but slower) bounds, else return
- * just the bounds of all control points
- */
- public void computeBounds(RectF bounds, boolean exact) {
- Rectangle2D rect = mPath.getBounds2D();
- bounds.left = (float)rect.getMinX();
- bounds.right = (float)rect.getMaxX();
- bounds.top = (float)rect.getMinY();
- bounds.bottom = (float)rect.getMaxY();
- }
-
- /**
- * Hint to the path to prepare for adding more points. This can allow the
- * path to more efficiently allocate its storage.
- *
- * @param extraPtCount The number of extra points that may be added to this
- * path
- */
- public void incReserve(int extraPtCount) {
- // pass
- }
-
- /**
- * Set the beginning of the next contour to the point (x,y).
- *
- * @param x The x-coordinate of the start of a new contour
- * @param y The y-coordinate of the start of a new contour
- */
- public void moveTo(float x, float y) {
- mPath.moveTo(mLastX = x, mLastY = y);
- }
-
- /**
- * Set the beginning of the next contour relative to the last point on the
- * previous contour. If there is no previous contour, this is treated the
- * same as moveTo().
- *
- * @param dx The amount to add to the x-coordinate of the end of the
- * previous contour, to specify the start of a new contour
- * @param dy The amount to add to the y-coordinate of the end of the
- * previous contour, to specify the start of a new contour
- */
- public void rMoveTo(float dx, float dy) {
- dx += mLastX;
- dy += mLastY;
- mPath.moveTo(mLastX = dx, mLastY = dy);
- }
-
- /**
- * Add a line from the last point to the specified point (x,y).
- * If no moveTo() call has been made for this contour, the first point is
- * automatically set to (0,0).
- *
- * @param x The x-coordinate of the end of a line
- * @param y The y-coordinate of the end of a line
- */
- public void lineTo(float x, float y) {
- mPath.lineTo(mLastX = x, mLastY = y);
- }
-
- /**
- * Same as lineTo, but the coordinates are considered relative to the last
- * point on this contour. If there is no previous point, then a moveTo(0,0)
- * is inserted automatically.
- *
- * @param dx The amount to add to the x-coordinate of the previous point on
- * this contour, to specify a line
- * @param dy The amount to add to the y-coordinate of the previous point on
- * this contour, to specify a line
- */
- public void rLineTo(float dx, float dy) {
- if (isEmpty()) {
- mPath.moveTo(mLastX = 0, mLastY = 0);
- }
- dx += mLastX;
- dy += mLastY;
- mPath.lineTo(mLastX = dx, mLastY = dy);
- }
-
- /**
- * Add a quadratic bezier from the last point, approaching control point
- * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
- * this contour, the first point is automatically set to (0,0).
- *
- * @param x1 The x-coordinate of the control point on a quadratic curve
- * @param y1 The y-coordinate of the control point on a quadratic curve
- * @param x2 The x-coordinate of the end point on a quadratic curve
- * @param y2 The y-coordinate of the end point on a quadratic curve
- */
- public void quadTo(float x1, float y1, float x2, float y2) {
- mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2);
- }
-
- /**
- * Same as quadTo, but the coordinates are considered relative to the last
- * point on this contour. If there is no previous point, then a moveTo(0,0)
- * is inserted automatically.
- *
- * @param dx1 The amount to add to the x-coordinate of the last point on
- * this contour, for the control point of a quadratic curve
- * @param dy1 The amount to add to the y-coordinate of the last point on
- * this contour, for the control point of a quadratic curve
- * @param dx2 The amount to add to the x-coordinate of the last point on
- * this contour, for the end point of a quadratic curve
- * @param dy2 The amount to add to the y-coordinate of the last point on
- * this contour, for the end point of a quadratic curve
- */
- public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
- if (isEmpty()) {
- mPath.moveTo(mLastX = 0, mLastY = 0);
- }
- dx1 += mLastX;
- dy1 += mLastY;
- dx2 += mLastX;
- dy2 += mLastY;
- mPath.quadTo(dx1, dy1, mLastX = dx2, mLastY = dy2);
- }
-
- /**
- * Add a cubic bezier from the last point, approaching control points
- * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
- * made for this contour, the first point is automatically set to (0,0).
- *
- * @param x1 The x-coordinate of the 1st control point on a cubic curve
- * @param y1 The y-coordinate of the 1st control point on a cubic curve
- * @param x2 The x-coordinate of the 2nd control point on a cubic curve
- * @param y2 The y-coordinate of the 2nd control point on a cubic curve
- * @param x3 The x-coordinate of the end point on a cubic curve
- * @param y3 The y-coordinate of the end point on a cubic curve
- */
- public void cubicTo(float x1, float y1, float x2, float y2,
- float x3, float y3) {
- mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3);
- }
-
- /**
- * Same as cubicTo, but the coordinates are considered relative to the
- * current point on this contour. If there is no previous point, then a
- * moveTo(0,0) is inserted automatically.
- */
- public void rCubicTo(float dx1, float dy1, float dx2, float dy2,
- float dx3, float dy3) {
- if (isEmpty()) {
- mPath.moveTo(mLastX = 0, mLastY = 0);
- }
- dx1 += mLastX;
- dy1 += mLastY;
- dx2 += mLastX;
- dy2 += mLastY;
- dx3 += mLastX;
- dy3 += mLastY;
- mPath.curveTo(dx1, dy1, dx2, dy2, mLastX = dx3, mLastY = dy3);
- }
-
- /**
- * Append the specified arc to the path as a new contour. If the start of
- * the path is different from the path's current last point, then an
- * automatic lineTo() is added to connect the current contour to the
- * start of the arc. However, if the path is empty, then we call moveTo()
- * with the first point of the arc. The sweep angle is tread mod 360.
- *
- * @param oval The bounds of oval defining shape and size of the arc
- * @param startAngle Starting angle (in degrees) where the arc begins
- * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated
- * mod 360.
- * @param forceMoveTo If true, always begin a new contour with the arc
- */
- public void arcTo(RectF oval, float startAngle, float sweepAngle,
- boolean forceMoveTo) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Append the specified arc to the path as a new contour. If the start of
- * the path is different from the path's current last point, then an
- * automatic lineTo() is added to connect the current contour to the
- * start of the arc. However, if the path is empty, then we call moveTo()
- * with the first point of the arc.
- *
- * @param oval The bounds of oval defining shape and size of the arc
- * @param startAngle Starting angle (in degrees) where the arc begins
- * @param sweepAngle Sweep angle (in degrees) measured clockwise
- */
- public void arcTo(RectF oval, float startAngle, float sweepAngle) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Close the current contour. If the current point is not equal to the
- * first point of the contour, a line segment is automatically added.
- */
- public void close() {
- mPath.closePath();
- }
-
- /**
- * Specifies how closed shapes (e.g. rects, ovals) are oriented when they
- * are added to a path.
- */
- public enum Direction {
- /** clockwise */
- CW (0), // must match enum in SkPath.h
- /** counter-clockwise */
- CCW (1); // must match enum in SkPath.h
-
- Direction(int ni) {
- nativeInt = ni;
- }
- final int nativeInt;
- }
-
- /**
- * Add a closed rectangle contour to the path
- *
- * @param rect The rectangle to add as a closed contour to the path
- * @param dir The direction to wind the rectangle's contour
- */
- public void addRect(RectF rect, Direction dir) {
- if (rect == null) {
- throw new NullPointerException("need rect parameter");
- }
-
- addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
- }
-
- /**
- * Add a closed rectangle contour to the path
- *
- * @param left The left side of a rectangle to add to the path
- * @param top The top of a rectangle to add to the path
- * @param right The right side of a rectangle to add to the path
- * @param bottom The bottom of a rectangle to add to the path
- * @param dir The direction to wind the rectangle's contour
- */
- public void addRect(float left, float top, float right, float bottom,
- Direction dir) {
- moveTo(left, top);
-
- switch (dir) {
- case CW:
- lineTo(right, top);
- lineTo(right, bottom);
- lineTo(left, bottom);
- break;
- case CCW:
- lineTo(left, bottom);
- lineTo(right, bottom);
- lineTo(right, top);
- break;
- }
-
- close();
- }
-
- /**
- * Add a closed oval contour to the path
- *
- * @param oval The bounds of the oval to add as a closed contour to the path
- * @param dir The direction to wind the oval's contour
- */
- public void addOval(RectF oval, Direction dir) {
- if (oval == null) {
- throw new NullPointerException("need oval parameter");
- }
-
- // FIXME Need to support direction
- Ellipse2D ovalShape = new Ellipse2D.Float(oval.left, oval.top, oval.width(), oval.height());
-
- mPath.append(ovalShape, false /* connect */);
- }
-
- /**
- * Add a closed circle contour to the path
- *
- * @param x The x-coordinate of the center of a circle to add to the path
- * @param y The y-coordinate of the center of a circle to add to the path
- * @param radius The radius of a circle to add to the path
- * @param dir The direction to wind the circle's contour
- */
- public void addCircle(float x, float y, float radius, Direction dir) {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Add the specified arc to the path as a new contour.
- *
- * @param oval The bounds of oval defining the shape and size of the arc
- * @param startAngle Starting angle (in degrees) where the arc begins
- * @param sweepAngle Sweep angle (in degrees) measured clockwise
- */
- public void addArc(RectF oval, float startAngle, float sweepAngle) {
- if (oval == null) {
- throw new NullPointerException("need oval parameter");
- }
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Add a closed round-rectangle contour to the path
- *
- * @param rect The bounds of a round-rectangle to add to the path
- * @param rx The x-radius of the rounded corners on the round-rectangle
- * @param ry The y-radius of the rounded corners on the round-rectangle
- * @param dir The direction to wind the round-rectangle's contour
- */
- public void addRoundRect(RectF rect, float rx, float ry, Direction dir) {
- if (rect == null) {
- throw new NullPointerException("need rect parameter");
- }
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Add a closed round-rectangle contour to the path. Each corner receives
- * two radius values [X, Y]. The corners are ordered top-left, top-right,
- * bottom-right, bottom-left
- *
- * @param rect The bounds of a round-rectangle to add to the path
- * @param radii Array of 8 values, 4 pairs of [X,Y] radii
- * @param dir The direction to wind the round-rectangle's contour
- */
- public void addRoundRect(RectF rect, float[] radii, Direction dir) {
- if (rect == null) {
- throw new NullPointerException("need rect parameter");
- }
- if (radii.length < 8) {
- throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
- }
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Add a copy of src to the path, offset by (dx,dy)
- *
- * @param src The path to add as a new contour
- * @param dx The amount to translate the path in X as it is added
- */
- public void addPath(Path src, float dx, float dy) {
- PathIterator iterator = src.mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
- mPath.append(iterator, false /* connect */);
- }
-
- /**
- * Add a copy of src to the path
- *
- * @param src The path that is appended to the current path
- */
- public void addPath(Path src) {
- addPath(src, 0, 0);
- }
-
- /**
- * Add a copy of src to the path, transformed by matrix
- *
- * @param src The path to add as a new contour
- */
- public void addPath(Path src, Matrix matrix) {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Offset the path by (dx,dy), returning true on success
- *
- * @param dx The amount in the X direction to offset the entire path
- * @param dy The amount in the Y direction to offset the entire path
- * @param dst The translated path is written here. If this is null, then
- * the original path is modified.
- */
- public void offset(float dx, float dy, Path dst) {
- GeneralPath newPath = new GeneralPath();
-
- PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
-
- newPath.append(iterator, false /* connect */);
-
- if (dst != null) {
- dst.mPath = newPath;
- } else {
- mPath = newPath;
- }
- }
-
- /**
- * Offset the path by (dx,dy), returning true on success
- *
- * @param dx The amount in the X direction to offset the entire path
- * @param dy The amount in the Y direction to offset the entire path
- */
- public void offset(float dx, float dy) {
- offset(dx, dy, null /* dst */);
- }
-
- /**
- * Sets the last point of the path.
- *
- * @param dx The new X coordinate for the last point
- * @param dy The new Y coordinate for the last point
- */
- public void setLastPoint(float dx, float dy) {
- mLastX = dx;
- mLastY = dy;
- }
-
- /**
- * Transform the points in this path by matrix, and write the answer
- * into dst. If dst is null, then the the original path is modified.
- *
- * @param matrix The matrix to apply to the path
- * @param dst The transformed path is written here. If dst is null,
- * then the the original path is modified
- */
- public void transform(Matrix matrix, Path dst) {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Transform the points in this path by matrix.
- *
- * @param matrix The matrix to apply to the path
- */
- public void transform(Matrix matrix) {
- transform(matrix, null /* dst */);
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
new file mode 100644
index 0000000..c448f0e
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PathDashPathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of PathDashPathEffect have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original PathDashPathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public class PathDashPathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Path Dash Path Effects are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int native_path, float advance, float phase,
+ int native_style) {
+ PathDashPathEffect_Delegate newDelegate = new PathDashPathEffect_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
new file mode 100644
index 0000000..bd2b6de
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of PathEffect have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original PathEffect class.
+ *
+ * This also serve as a base class for all PathEffect delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class PathEffect_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<PathEffect_Delegate> sManager =
+ new DelegateManager<PathEffect_Delegate>(PathEffect_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static PathEffect_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ public abstract Stroke getStroke(Paint_Delegate paint);
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int native_patheffect) {
+ sManager.removeJavaReferenceFor(native_patheffect);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
new file mode 100644
index 0000000..64f19d3
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -0,0 +1,815 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Path.Direction;
+import android.graphics.Path.FillType;
+
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Area;
+import java.awt.geom.Ellipse2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.geom.RoundRectangle2D;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Path
+ *
+ * Through the layoutlib_create tool, the original native methods of Path have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Path class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Path_Delegate {
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Path_Delegate> sManager =
+ new DelegateManager<Path_Delegate>(Path_Delegate.class);
+
+ // ---- delegate data ----
+ private FillType mFillType = FillType.WINDING;
+ private GeneralPath mPath = new GeneralPath();
+
+ private float mLastX = 0;
+ private float mLastY = 0;
+
+ // ---- Public Helper methods ----
+
+ public static Path_Delegate getDelegate(int nPath) {
+ return sManager.getDelegate(nPath);
+ }
+
+ public Shape getJavaShape() {
+ return mPath;
+ }
+
+ public void setJavaShape(Shape shape) {
+ mPath.reset();
+ mPath.append(shape, false /*connect*/);
+ }
+
+ public void reset() {
+ mPath.reset();
+ }
+
+ public void setPathIterator(PathIterator iterator) {
+ mPath.reset();
+ mPath.append(iterator, false /*connect*/);
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int init1() {
+ // create the delegate
+ Path_Delegate newDelegate = new Path_Delegate();
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int init2(int nPath) {
+ // create the delegate
+ Path_Delegate newDelegate = new Path_Delegate();
+
+ // get the delegate to copy, which could be null if nPath is 0
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate != null) {
+ newDelegate.set(pathDelegate);
+ }
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_reset(int nPath) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.mPath.reset();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rewind(int nPath) {
+ // call out to reset since there's nothing to optimize in
+ // terms of data structs.
+ native_reset(nPath);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_set(int native_dst, int native_src) {
+ Path_Delegate pathDstDelegate = sManager.getDelegate(native_dst);
+ if (pathDstDelegate == null) {
+ return;
+ }
+
+ Path_Delegate pathSrcDelegate = sManager.getDelegate(native_src);
+ if (pathSrcDelegate == null) {
+ return;
+ }
+
+ pathDstDelegate.set(pathSrcDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getFillType(int nPath) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return 0;
+ }
+
+ return pathDelegate.mFillType.nativeInt;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setFillType(int nPath, int ft) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.mFillType = Path.sFillTypeArray[ft];
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_isEmpty(int nPath) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return true;
+ }
+
+ return pathDelegate.isEmpty();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_isRect(int nPath, RectF rect) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return false;
+ }
+
+ // create an Area that can test if the path is a rect
+ Area area = new Area(pathDelegate.mPath);
+ if (area.isRectangular()) {
+ if (rect != null) {
+ pathDelegate.fillBounds(rect);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_computeBounds(int nPath, RectF bounds) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.fillBounds(bounds);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_incReserve(int nPath, int extraPtCount) {
+ // since we use a java2D path, there's no way to pre-allocate new points,
+ // so we do nothing.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_moveTo(int nPath, float x, float y) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.moveTo(x, y);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rMoveTo(int nPath, float dx, float dy) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.rMoveTo(dx, dy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_lineTo(int nPath, float x, float y) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.lineTo(x, y);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rLineTo(int nPath, float dx, float dy) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.rLineTo(dx, dy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_quadTo(int nPath, float x1, float y1, float x2, float y2) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.quadTo(x1, y1, x2, y2);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rQuadTo(int nPath, float dx1, float dy1, float dx2, float dy2) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.rQuadTo(dx1, dy1, dx2, dy2);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_cubicTo(int nPath, float x1, float y1,
+ float x2, float y2, float x3, float y3) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.cubicTo(x1, y1, x2, y2, x3, y3);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rCubicTo(int nPath, float x1, float y1,
+ float x2, float y2, float x3, float y3) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.rCubicTo(x1, y1, x2, y2, x3, y3);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_arcTo(int nPath, RectF oval,
+ float startAngle, float sweepAngle, boolean forceMoveTo) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_close(int nPath) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.close();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addRect(int nPath, RectF rect, int dir) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addRect(int nPath,
+ float left, float top, float right, float bottom, int dir) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.addRect(left, top, right, bottom, dir);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addOval(int nPath, RectF oval, int dir) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.mPath.append(new Ellipse2D.Float(
+ oval.left, oval.top, oval.width(), oval.height()), false);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addCircle(int nPath, float x, float y, float radius, int dir) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ // because x/y is the center of the circle, need to offset this by the radius
+ pathDelegate.mPath.append(new Ellipse2D.Float(
+ x - radius, y - radius, radius * 2, radius * 2), false);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addArc(int nPath, RectF oval,
+ float startAngle, float sweepAngle) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ // because x/y is the center of the circle, need to offset this by the radius
+ pathDelegate.mPath.append(new Arc2D.Float(
+ oval.left, oval.top, oval.width(), oval.height(),
+ -startAngle, -sweepAngle, Arc2D.OPEN), false);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addRoundRect(
+ int nPath, RectF rect, float rx, float ry, int dir) {
+
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.mPath.append(new RoundRectangle2D.Float(
+ rect.left, rect.top, rect.width(), rect.height(), rx * 2, ry * 2), false);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addRoundRect(int nPath, RectF rect, float[] radii, int dir) {
+ // Java2D doesn't support different rounded corners in each corner, so just use the
+ // first value.
+ native_addRoundRect(nPath, rect, radii[0], radii[1], dir);
+
+ // there can be a case where this API is used but with similar values for all corners, so
+ // in that case we don't warn.
+ // we only care if 2 corners are different so just compare to the next one.
+ for (int i = 0 ; i < 3 ; i++) {
+ if (radii[i * 2] != radii[(i + 1) * 2] || radii[i * 2 + 1] != radii[(i + 1) * 2 + 1]) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Different corner sizes are not supported in Path.addRoundRect.",
+ null, null /*data*/);
+ break;
+ }
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addPath(int nPath, int src, float dx, float dy) {
+ addPath(nPath, src, AffineTransform.getTranslateInstance(dx, dy));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addPath(int nPath, int src) {
+ addPath(nPath, src, null /*transform*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addPath(int nPath, int src, int matrix) {
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ addPath(nPath, src, matrixDelegate.getAffineTransform());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_offset(int nPath, float dx, float dy, int dst_path) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ // could be null if the int is 0;
+ Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
+
+ pathDelegate.offset(dx, dy, dstDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_offset(int nPath, float dx, float dy) {
+ native_offset(nPath, dx, dy, 0);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setLastPoint(int nPath, float dx, float dy) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.mLastX = dx;
+ pathDelegate.mLastY = dy;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_transform(int nPath, int matrix,
+ int dst_path) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ // this can be null if dst_path is 0
+ Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
+
+ pathDelegate.transform(matrixDelegate, dstDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_transform(int nPath, int matrix) {
+ native_transform(nPath, matrix, 0);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int nPath) {
+ sManager.removeJavaReferenceFor(nPath);
+ }
+
+
+ // ---- Private helper methods ----
+
+ private void set(Path_Delegate delegate) {
+ mPath.reset();
+ setFillType(delegate.mFillType);
+ mPath.append(delegate.mPath, false /*connect*/);
+ }
+
+ private void setFillType(FillType fillType) {
+ mFillType = fillType;
+ mPath.setWindingRule(getWindingRule(fillType));
+ }
+
+ /**
+ * Returns the Java2D winding rules matching a given Android {@link FillType}.
+ * @param type the android fill type
+ * @return the matching java2d winding rule.
+ */
+ private static int getWindingRule(FillType type) {
+ switch (type) {
+ case WINDING:
+ case INVERSE_WINDING:
+ return GeneralPath.WIND_NON_ZERO;
+ case EVEN_ODD:
+ case INVERSE_EVEN_ODD:
+ return GeneralPath.WIND_EVEN_ODD;
+ }
+
+ assert false;
+ throw new IllegalArgumentException();
+ }
+
+ private static Direction getDirection(int direction) {
+ for (Direction d : Direction.values()) {
+ if (direction == d.nativeInt) {
+ return d;
+ }
+ }
+
+ assert false;
+ return null;
+ }
+
+ private static void addPath(int destPath, int srcPath, AffineTransform transform) {
+ Path_Delegate destPathDelegate = sManager.getDelegate(destPath);
+ if (destPathDelegate == null) {
+ return;
+ }
+
+ Path_Delegate srcPathDelegate = sManager.getDelegate(srcPath);
+ if (srcPathDelegate == null) {
+ return;
+ }
+
+ if (transform != null) {
+ destPathDelegate.mPath.append(
+ srcPathDelegate.mPath.getPathIterator(transform), false);
+ } else {
+ destPathDelegate.mPath.append(srcPathDelegate.mPath, false);
+ }
+ }
+
+
+ /**
+ * Returns whether the path is empty.
+ * @return true if the path is empty.
+ */
+ private boolean isEmpty() {
+ return mPath.getCurrentPoint() == null;
+ }
+
+ /**
+ * Fills the given {@link RectF} with the path bounds.
+ * @param bounds the RectF to be filled.
+ */
+ private void fillBounds(RectF bounds) {
+ Rectangle2D rect = mPath.getBounds2D();
+ bounds.left = (float)rect.getMinX();
+ bounds.right = (float)rect.getMaxX();
+ bounds.top = (float)rect.getMinY();
+ bounds.bottom = (float)rect.getMaxY();
+ }
+
+ /**
+ * Set the beginning of the next contour to the point (x,y).
+ *
+ * @param x The x-coordinate of the start of a new contour
+ * @param y The y-coordinate of the start of a new contour
+ */
+ private void moveTo(float x, float y) {
+ mPath.moveTo(mLastX = x, mLastY = y);
+ }
+
+ /**
+ * Set the beginning of the next contour relative to the last point on the
+ * previous contour. If there is no previous contour, this is treated the
+ * same as moveTo().
+ *
+ * @param dx The amount to add to the x-coordinate of the end of the
+ * previous contour, to specify the start of a new contour
+ * @param dy The amount to add to the y-coordinate of the end of the
+ * previous contour, to specify the start of a new contour
+ */
+ private void rMoveTo(float dx, float dy) {
+ dx += mLastX;
+ dy += mLastY;
+ mPath.moveTo(mLastX = dx, mLastY = dy);
+ }
+
+ /**
+ * Add a line from the last point to the specified point (x,y).
+ * If no moveTo() call has been made for this contour, the first point is
+ * automatically set to (0,0).
+ *
+ * @param x The x-coordinate of the end of a line
+ * @param y The y-coordinate of the end of a line
+ */
+ private void lineTo(float x, float y) {
+ mPath.lineTo(mLastX = x, mLastY = y);
+ }
+
+ /**
+ * Same as lineTo, but the coordinates are considered relative to the last
+ * point on this contour. If there is no previous point, then a moveTo(0,0)
+ * is inserted automatically.
+ *
+ * @param dx The amount to add to the x-coordinate of the previous point on
+ * this contour, to specify a line
+ * @param dy The amount to add to the y-coordinate of the previous point on
+ * this contour, to specify a line
+ */
+ private void rLineTo(float dx, float dy) {
+ if (isEmpty()) {
+ mPath.moveTo(mLastX = 0, mLastY = 0);
+ }
+ dx += mLastX;
+ dy += mLastY;
+ mPath.lineTo(mLastX = dx, mLastY = dy);
+ }
+
+ /**
+ * Add a quadratic bezier from the last point, approaching control point
+ * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
+ * this contour, the first point is automatically set to (0,0).
+ *
+ * @param x1 The x-coordinate of the control point on a quadratic curve
+ * @param y1 The y-coordinate of the control point on a quadratic curve
+ * @param x2 The x-coordinate of the end point on a quadratic curve
+ * @param y2 The y-coordinate of the end point on a quadratic curve
+ */
+ private void quadTo(float x1, float y1, float x2, float y2) {
+ mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2);
+ }
+
+ /**
+ * Same as quadTo, but the coordinates are considered relative to the last
+ * point on this contour. If there is no previous point, then a moveTo(0,0)
+ * is inserted automatically.
+ *
+ * @param dx1 The amount to add to the x-coordinate of the last point on
+ * this contour, for the control point of a quadratic curve
+ * @param dy1 The amount to add to the y-coordinate of the last point on
+ * this contour, for the control point of a quadratic curve
+ * @param dx2 The amount to add to the x-coordinate of the last point on
+ * this contour, for the end point of a quadratic curve
+ * @param dy2 The amount to add to the y-coordinate of the last point on
+ * this contour, for the end point of a quadratic curve
+ */
+ private void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
+ if (isEmpty()) {
+ mPath.moveTo(mLastX = 0, mLastY = 0);
+ }
+ dx1 += mLastX;
+ dy1 += mLastY;
+ dx2 += mLastX;
+ dy2 += mLastY;
+ mPath.quadTo(dx1, dy1, mLastX = dx2, mLastY = dy2);
+ }
+
+ /**
+ * Add a cubic bezier from the last point, approaching control points
+ * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
+ * made for this contour, the first point is automatically set to (0,0).
+ *
+ * @param x1 The x-coordinate of the 1st control point on a cubic curve
+ * @param y1 The y-coordinate of the 1st control point on a cubic curve
+ * @param x2 The x-coordinate of the 2nd control point on a cubic curve
+ * @param y2 The y-coordinate of the 2nd control point on a cubic curve
+ * @param x3 The x-coordinate of the end point on a cubic curve
+ * @param y3 The y-coordinate of the end point on a cubic curve
+ */
+ private void cubicTo(float x1, float y1, float x2, float y2,
+ float x3, float y3) {
+ mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3);
+ }
+
+ /**
+ * Same as cubicTo, but the coordinates are considered relative to the
+ * current point on this contour. If there is no previous point, then a
+ * moveTo(0,0) is inserted automatically.
+ */
+ private void rCubicTo(float dx1, float dy1, float dx2, float dy2,
+ float dx3, float dy3) {
+ if (isEmpty()) {
+ mPath.moveTo(mLastX = 0, mLastY = 0);
+ }
+ dx1 += mLastX;
+ dy1 += mLastY;
+ dx2 += mLastX;
+ dy2 += mLastY;
+ dx3 += mLastX;
+ dy3 += mLastY;
+ mPath.curveTo(dx1, dy1, dx2, dy2, mLastX = dx3, mLastY = dy3);
+ }
+
+ /**
+ * Append the specified arc to the path as a new contour. If the start of
+ * the path is different from the path's current last point, then an
+ * automatic lineTo() is added to connect the current contour to the
+ * start of the arc. However, if the path is empty, then we call moveTo()
+ * with the first point of the arc. The sweep angle is tread mod 360.
+ *
+ * @param oval The bounds of oval defining shape and size of the arc
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated
+ * mod 360.
+ * @param forceMoveTo If true, always begin a new contour with the arc
+ */
+ private void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) {
+ Arc2D arc = new Arc2D.Float(oval.left, oval.top, oval.width(), oval.height(), -startAngle,
+ -sweepAngle, Arc2D.OPEN);
+ mPath.append(arc, true /*connect*/);
+
+ resetLastPointFromPath();
+ }
+
+ /**
+ * Close the current contour. If the current point is not equal to the
+ * first point of the contour, a line segment is automatically added.
+ */
+ private void close() {
+ mPath.closePath();
+ }
+
+ private void resetLastPointFromPath() {
+ Point2D last = mPath.getCurrentPoint();
+ mLastX = (float) last.getX();
+ mLastY = (float) last.getY();
+ }
+
+ /**
+ * Add a closed rectangle contour to the path
+ *
+ * @param left The left side of a rectangle to add to the path
+ * @param top The top of a rectangle to add to the path
+ * @param right The right side of a rectangle to add to the path
+ * @param bottom The bottom of a rectangle to add to the path
+ * @param dir The direction to wind the rectangle's contour
+ */
+ private void addRect(float left, float top, float right, float bottom,
+ int dir) {
+ moveTo(left, top);
+
+ Direction direction = getDirection(dir);
+
+ switch (direction) {
+ case CW:
+ lineTo(right, top);
+ lineTo(right, bottom);
+ lineTo(left, bottom);
+ break;
+ case CCW:
+ lineTo(left, bottom);
+ lineTo(right, bottom);
+ lineTo(right, top);
+ break;
+ }
+
+ close();
+
+ resetLastPointFromPath();
+ }
+
+ /**
+ * Offset the path by (dx,dy), returning true on success
+ *
+ * @param dx The amount in the X direction to offset the entire path
+ * @param dy The amount in the Y direction to offset the entire path
+ * @param dst The translated path is written here. If this is null, then
+ * the original path is modified.
+ */
+ public void offset(float dx, float dy, Path_Delegate dst) {
+ GeneralPath newPath = new GeneralPath();
+
+ PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
+
+ newPath.append(iterator, false /*connect*/);
+
+ if (dst != null) {
+ dst.mPath = newPath;
+ } else {
+ mPath = newPath;
+ }
+ }
+
+ /**
+ * Transform the points in this path by matrix, and write the answer
+ * into dst. If dst is null, then the the original path is modified.
+ *
+ * @param matrix The matrix to apply to the path
+ * @param dst The transformed path is written here. If dst is null,
+ * then the the original path is modified
+ */
+ public void transform(Matrix_Delegate matrix, Path_Delegate dst) {
+ if (matrix.hasPerspective()) {
+ assert false;
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
+ "android.graphics.Path#transform() only " +
+ "supports affine transformations.", null, null /*data*/);
+ }
+
+ GeneralPath newPath = new GeneralPath();
+
+ PathIterator iterator = mPath.getPathIterator(matrix.getAffineTransform());
+
+ newPath.append(iterator, false /*connect*/);
+
+ if (dst != null) {
+ dst.mPath = newPath;
+ } else {
+ mPath = newPath;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
new file mode 100644
index 0000000..4ab044b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Composite;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PixelXorXfermode
+ *
+ * Through the layoutlib_create tool, the original native methods of PixelXorXfermode have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original PixelXorXfermode class.
+ *
+ * Because this extends {@link Xfermode_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
+ * {@link Xfermode_Delegate}.
+ *
+ * @see Xfermode_Delegate
+ */
+public class PixelXorXfermode_Delegate extends Xfermode_Delegate {
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Composite getComposite(int alpha) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Pixel XOR Xfermodes are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int opColor) {
+ PixelXorXfermode_Delegate newDelegate = new PixelXorXfermode_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
new file mode 100644
index 0000000..65c65a1
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PorterDuffColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of PorterDuffColorFilter have
+ * been replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original PorterDuffColorFilter class.
+ *
+ * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link ColorFilter_Delegate}.
+ *
+ * @see ColorFilter_Delegate
+ *
+ */
+public class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "PorterDuff Color Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode) {
+ PorterDuffColorFilter_Delegate newDelegate = new PorterDuffColorFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
new file mode 100644
index 0000000..4301c1a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.AlphaComposite;
+import java.awt.Composite;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PorterDuffXfermode
+ *
+ * Through the layoutlib_create tool, the original native methods of PorterDuffXfermode have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original PorterDuffXfermode class.
+ *
+ * Because this extends {@link Xfermode_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
+ * {@link Xfermode_Delegate}.
+ *
+ */
+public class PorterDuffXfermode_Delegate extends Xfermode_Delegate {
+
+ // ---- delegate data ----
+
+ private final int mMode;
+
+ // ---- Public Helper methods ----
+
+ public PorterDuff.Mode getMode() {
+ return getPorterDuffMode(mMode);
+ }
+
+ @Override
+ public Composite getComposite(int alpha) {
+ return getComposite(getPorterDuffMode(mMode), alpha);
+ }
+
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ // no message since isSupported returns true;
+ return null;
+ }
+
+ public static PorterDuff.Mode getPorterDuffMode(int mode) {
+ for (PorterDuff.Mode m : PorterDuff.Mode.values()) {
+ if (m.nativeInt == mode) {
+ return m;
+ }
+ }
+
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ String.format("Unknown PorterDuff.Mode: %d", mode), null /*data*/);
+ assert false;
+ return PorterDuff.Mode.SRC_OVER;
+ }
+
+ public static Composite getComposite(PorterDuff.Mode mode, int alpha) {
+ float falpha = alpha != 0xFF ? (float)alpha / 255.f : 1.f;
+ switch (mode) {
+ case CLEAR:
+ return AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha);
+ case DARKEN:
+ break;
+ case DST:
+ return AlphaComposite.getInstance(AlphaComposite.DST, falpha);
+ case DST_ATOP:
+ return AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha);
+ case DST_IN:
+ return AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha);
+ case DST_OUT:
+ return AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha);
+ case DST_OVER:
+ return AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha);
+ case LIGHTEN:
+ break;
+ case MULTIPLY:
+ break;
+ case SCREEN:
+ break;
+ case SRC:
+ return AlphaComposite.getInstance(AlphaComposite.SRC, falpha);
+ case SRC_ATOP:
+ return AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha);
+ case SRC_IN:
+ return AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha);
+ case SRC_OUT:
+ return AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha);
+ case SRC_OVER:
+ return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha);
+ case XOR:
+ return AlphaComposite.getInstance(AlphaComposite.XOR, falpha);
+ }
+
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN,
+ String.format("Unsupported PorterDuff Mode: %s", mode.name()),
+ null, null /*data*/);
+
+ return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha);
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreateXfermode(int mode) {
+ PorterDuffXfermode_Delegate newDelegate = new PorterDuffXfermode_Delegate(mode);
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private PorterDuffXfermode_Delegate(int mode) {
+ mMode = mode;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient.java
deleted file mode 100644
index 4409a80..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * 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;
-
-public class RadialGradient extends GradientShader {
-
- private RadialGradientPaint mPaint;
-
- /**
- * Create a shader that draws a radial gradient given the center and radius.
- *
- * @param x The x-coordinate of the center of the radius
- * @param y The y-coordinate of the center of the radius
- * @param radius Must be positive. The radius of the circle for this
- * gradient
- * @param colors The colors to be distributed between the center and edge of
- * the circle
- * @param positions May be NULL. The relative position of each corresponding
- * color in the colors array. If this is NULL, the the colors are
- * distributed evenly between the center and edge of the circle.
- * @param tile The Shader tiling mode
- */
- public RadialGradient(float x, float y, float radius, int colors[], float positions[],
- TileMode tile) {
- super(colors, positions);
- if (radius <= 0) {
- throw new IllegalArgumentException("radius must be > 0");
- }
-
- mPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
- }
-
- /**
- * Create a shader that draws a radial gradient given the center and radius.
- *
- * @param x The x-coordinate of the center of the radius
- * @param y The y-coordinate of the center of the radius
- * @param radius Must be positive. The radius of the circle for this
- * gradient
- * @param color0 The color at the center of the circle.
- * @param color1 The color at the edge of the circle.
- * @param tile The Shader tiling mode
- */
- public RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile) {
- this(x, y, radius, new int[] { color0, color1 }, null /* positions */, tile);
- }
-
- @Override
- java.awt.Paint getJavaPaint() {
- return mPaint;
- }
-
- private static class RadialGradientPaint extends GradientPaint {
-
- private final float mX;
- private final float mY;
- private final float mRadius;
-
- public RadialGradientPaint(float x, float y, float radius, int[] colors, float[] positions, TileMode mode) {
- super(colors, positions, mode);
- mX = x;
- mY = y;
- mRadius = radius;
- }
-
- public java.awt.PaintContext createContext(
- java.awt.image.ColorModel colorModel,
- java.awt.Rectangle deviceBounds,
- java.awt.geom.Rectangle2D userBounds,
- java.awt.geom.AffineTransform xform,
- java.awt.RenderingHints hints) {
- precomputeGradientColors();
- return new RadialGradientPaintContext(colorModel);
- }
-
- private class RadialGradientPaintContext implements java.awt.PaintContext {
-
- private final java.awt.image.ColorModel mColorModel;
-
- public RadialGradientPaintContext(java.awt.image.ColorModel colorModel) {
- mColorModel = colorModel;
- }
-
- public void dispose() {
- }
-
- public java.awt.image.ColorModel getColorModel() {
- return mColorModel;
- }
-
- public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
- java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
- java.awt.image.BufferedImage.TYPE_INT_ARGB);
-
- int[] data = new int[w*h];
-
- // compute distance from each point to the center, and figure out the distance from
- // it.
- int index = 0;
- for (int iy = 0 ; iy < h ; iy++) {
- for (int ix = 0 ; ix < w ; ix++) {
- float _x = x + ix - mX;
- float _y = y + iy - mY;
- float distance = (float) Math.sqrt(_x * _x + _y * _y);
-
- data[index++] = getGradientColor(distance / mRadius);
- }
- }
-
- image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
-
- return image.getRaster();
- }
-
- }
- }
-
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
new file mode 100644
index 0000000..bdc0ab1
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Shader.TileMode;
+
+/**
+ * Delegate implementing the native methods of android.graphics.RadialGradient
+ *
+ * Through the layoutlib_create tool, the original native methods of RadialGradient have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original RadialGradient class.
+ *
+ * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
+ *
+ * @see Shader_Delegate
+ *
+ */
+public class RadialGradient_Delegate extends Gradient_Delegate {
+
+ // ---- delegate data ----
+ private java.awt.Paint mJavaPaint;
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public java.awt.Paint getJavaPaint() {
+ return mJavaPaint;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate1(float x, float y, float radius,
+ int colors[], float positions[], int tileMode) {
+ RadialGradient_Delegate newDelegate = new RadialGradient_Delegate(x, y, radius,
+ colors, positions, Shader_Delegate.getTileMode(tileMode));
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate2(float x, float y, float radius,
+ int color0, int color1, int tileMode) {
+ return nativeCreate1(x, y, radius, new int[] { color0, color1 }, null /*positions*/,
+ tileMode);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ /**
+ * Create a shader that draws a radial gradient given the center and radius.
+ *
+ * @param x The x-coordinate of the center of the radius
+ * @param y The y-coordinate of the center of the radius
+ * @param radius Must be positive. The radius of the circle for this
+ * gradient
+ * @param colors The colors to be distributed between the center and edge of
+ * the circle
+ * @param positions May be NULL. The relative position of each corresponding
+ * color in the colors array. If this is NULL, the the colors are
+ * distributed evenly between the center and edge of the circle.
+ * @param tile The Shader tiling mode
+ */
+ private RadialGradient_Delegate(float x, float y, float radius, int colors[], float positions[],
+ TileMode tile) {
+ super(colors, positions);
+ mJavaPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
+ }
+
+ private class RadialGradientPaint extends GradientPaint {
+
+ private final float mX;
+ private final float mY;
+ private final float mRadius;
+
+ public RadialGradientPaint(float x, float y, float radius,
+ int[] colors, float[] positions, TileMode mode) {
+ super(colors, positions, mode);
+ mX = x;
+ mY = y;
+ mRadius = radius;
+ }
+
+ public java.awt.PaintContext createContext(
+ java.awt.image.ColorModel colorModel,
+ java.awt.Rectangle deviceBounds,
+ java.awt.geom.Rectangle2D userBounds,
+ java.awt.geom.AffineTransform xform,
+ java.awt.RenderingHints hints) {
+ precomputeGradientColors();
+
+ java.awt.geom.AffineTransform canvasMatrix;
+ try {
+ canvasMatrix = xform.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in RadialGradient", e, null /*data*/);
+ canvasMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
+ try {
+ localMatrix = localMatrix.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in RadialGradient", e, null /*data*/);
+ localMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ return new RadialGradientPaintContext(canvasMatrix, localMatrix, colorModel);
+ }
+
+ private class RadialGradientPaintContext implements java.awt.PaintContext {
+
+ private final java.awt.geom.AffineTransform mCanvasMatrix;
+ private final java.awt.geom.AffineTransform mLocalMatrix;
+ private final java.awt.image.ColorModel mColorModel;
+
+ public RadialGradientPaintContext(
+ java.awt.geom.AffineTransform canvasMatrix,
+ java.awt.geom.AffineTransform localMatrix,
+ java.awt.image.ColorModel colorModel) {
+ mCanvasMatrix = canvasMatrix;
+ mLocalMatrix = localMatrix;
+ mColorModel = colorModel;
+ }
+
+ public void dispose() {
+ }
+
+ public java.awt.image.ColorModel getColorModel() {
+ return mColorModel;
+ }
+
+ public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
+ java.awt.image.BufferedImage.TYPE_INT_ARGB);
+
+ int[] data = new int[w*h];
+
+ // compute distance from each point to the center, and figure out the distance from
+ // it.
+ int index = 0;
+ float[] pt1 = new float[2];
+ float[] pt2 = new float[2];
+ for (int iy = 0 ; iy < h ; iy++) {
+ for (int ix = 0 ; ix < w ; ix++) {
+ // handle the canvas transform
+ pt1[0] = x + ix;
+ pt1[1] = y + iy;
+ mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ // handle the local matrix
+ pt1[0] = pt2[0] - mX;
+ pt1[1] = pt2[1] - mY;
+ mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ float _x = pt2[0];
+ float _y = pt2[1];
+ float distance = (float) Math.sqrt(_x * _x + _y * _y);
+
+ data[index++] = getGradientColor(distance / mRadius);
+ }
+ }
+
+ image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
+
+ return image.getRaster();
+ }
+
+ }
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
new file mode 100644
index 0000000..2812b6b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Rasterizer
+ *
+ * Through the layoutlib_create tool, the original native methods of Rasterizer have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Rasterizer class.
+ *
+ * This also serve as a base class for all Rasterizer delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class Rasterizer_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<Rasterizer_Delegate> sManager =
+ new DelegateManager<Rasterizer_Delegate>(Rasterizer_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static Rasterizer_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int native_instance) {
+ sManager.removeJavaReferenceFor(native_instance);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
new file mode 100644
index 0000000..b0ee5c2
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
@@ -0,0 +1,474 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.os.Parcel;
+
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Region
+ *
+ * Through the layoutlib_create tool, the original native methods of Region have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Region class.
+ *
+ * This also serve as a base class for all Region delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public class Region_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<Region_Delegate> sManager =
+ new DelegateManager<Region_Delegate>(Region_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+ private Area mArea = new Area();
+
+ // ---- Public Helper methods ----
+
+ public static Region_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ public Area getJavaArea() {
+ return mArea;
+ }
+
+ /**
+ * Combines two {@link Shape} into another one (actually an {@link Area}), according
+ * to the given {@link Region.Op}.
+ *
+ * If the Op is not one that combines two shapes, then this return null
+ *
+ * @param shape1 the firt shape to combine which can be null if there's no original clip.
+ * @param shape2 the 2nd shape to combine
+ * @param regionOp the operande for the combine
+ * @return a new area or null.
+ */
+ public static Area combineShapes(Shape shape1, Shape shape2, int regionOp) {
+ if (regionOp == Region.Op.DIFFERENCE.nativeInt) {
+ // if shape1 is null (empty), then the result is null.
+ if (shape1 == null) {
+ return null;
+ }
+
+ // result is always a new area.
+ Area result = new Area(shape1);
+ result.subtract(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
+ return result;
+
+ } else if (regionOp == Region.Op.INTERSECT.nativeInt) {
+ // if shape1 is null, then the result is simply shape2.
+ if (shape1 == null) {
+ return new Area(shape2);
+ }
+
+ // result is always a new area.
+ Area result = new Area(shape1);
+ result.intersect(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
+ return result;
+
+ } else if (regionOp == Region.Op.UNION.nativeInt) {
+ // if shape1 is null, then the result is simply shape2.
+ if (shape1 == null) {
+ return new Area(shape2);
+ }
+
+ // result is always a new area.
+ Area result = new Area(shape1);
+ result.add(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
+ return result;
+
+ } else if (regionOp == Region.Op.XOR.nativeInt) {
+ // if shape1 is null, then the result is simply shape2
+ if (shape1 == null) {
+ return new Area(shape2);
+ }
+
+ // result is always a new area.
+ Area result = new Area(shape1);
+ result.exclusiveOr(shape2 instanceof Area ? (Area) shape2 : new Area(shape2));
+ return result;
+
+ } else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) {
+ // result is always a new area.
+ Area result = new Area(shape2);
+
+ if (shape1 != null) {
+ result.subtract(shape1 instanceof Area ? (Area) shape1 : new Area(shape1));
+ }
+
+ return result;
+ }
+
+ return null;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isEmpty(Region thisRegion) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return true;
+ }
+
+ return regionDelegate.mArea.isEmpty();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isRect(Region thisRegion) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return true;
+ }
+
+ return regionDelegate.mArea.isRectangular();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isComplex(Region thisRegion) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return true;
+ }
+
+ return regionDelegate.mArea.isSingular() == false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean contains(Region thisRegion, int x, int y) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return false;
+ }
+
+ return regionDelegate.mArea.contains(x, y);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean quickContains(Region thisRegion,
+ int left, int top, int right, int bottom) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return false;
+ }
+
+ return regionDelegate.mArea.isRectangular() &&
+ regionDelegate.mArea.contains(left, top, right - left, bottom - top);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean quickReject(Region thisRegion,
+ int left, int top, int right, int bottom) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return false;
+ }
+
+ return regionDelegate.mArea.isEmpty() ||
+ regionDelegate.mArea.intersects(left, top, right - left, bottom - top) == false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean quickReject(Region thisRegion, Region rgn) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return false;
+ }
+
+ Region_Delegate targetRegionDelegate = sManager.getDelegate(rgn.mNativeRegion);
+ if (targetRegionDelegate == null) {
+ return false;
+ }
+
+ return regionDelegate.mArea.isEmpty() ||
+ regionDelegate.mArea.getBounds().intersects(
+ targetRegionDelegate.mArea.getBounds()) == false;
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void translate(Region thisRegion, int dx, int dy, Region dst) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return;
+ }
+
+ Region_Delegate targetRegionDelegate = sManager.getDelegate(dst.mNativeRegion);
+ if (targetRegionDelegate == null) {
+ return;
+ }
+
+ if (regionDelegate.mArea.isEmpty()) {
+ targetRegionDelegate.mArea = new Area();
+ } else {
+ targetRegionDelegate.mArea = new Area(regionDelegate.mArea);
+ AffineTransform mtx = new AffineTransform();
+ mtx.translate(dx, dy);
+ targetRegionDelegate.mArea.transform(mtx);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void scale(Region thisRegion, float scale, Region dst) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return;
+ }
+
+ Region_Delegate targetRegionDelegate = sManager.getDelegate(dst.mNativeRegion);
+ if (targetRegionDelegate == null) {
+ return;
+ }
+
+ if (regionDelegate.mArea.isEmpty()) {
+ targetRegionDelegate.mArea = new Area();
+ } else {
+ targetRegionDelegate.mArea = new Area(regionDelegate.mArea);
+ AffineTransform mtx = new AffineTransform();
+ mtx.scale(scale, scale);
+ targetRegionDelegate.mArea.transform(mtx);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConstructor() {
+ Region_Delegate newDelegate = new Region_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int native_region) {
+ sManager.removeJavaReferenceFor(native_region);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeSetRegion(int native_dst, int native_src) {
+ Region_Delegate dstRegion = sManager.getDelegate(native_dst);
+ if (dstRegion == null) {
+ return true;
+ }
+
+ Region_Delegate srcRegion = sManager.getDelegate(native_src);
+ if (srcRegion == null) {
+ return true;
+ }
+
+ dstRegion.mArea.reset();
+ dstRegion.mArea.add(srcRegion.mArea);
+
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeSetRect(int native_dst,
+ int left, int top, int right, int bottom) {
+ Region_Delegate dstRegion = sManager.getDelegate(native_dst);
+ if (dstRegion == null) {
+ return true;
+ }
+
+ dstRegion.mArea = new Area(new Rectangle2D.Float(left, top, right - left, bottom - top));
+ return dstRegion.mArea.getBounds().isEmpty() == false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeSetPath(int native_dst, int native_path, int native_clip) {
+ Region_Delegate dstRegion = sManager.getDelegate(native_dst);
+ if (dstRegion == null) {
+ return true;
+ }
+
+ Path_Delegate path = Path_Delegate.getDelegate(native_path);
+ if (path == null) {
+ return true;
+ }
+
+ dstRegion.mArea = new Area(path.getJavaShape());
+
+ Region_Delegate clip = sManager.getDelegate(native_clip);
+ if (clip != null) {
+ dstRegion.mArea.subtract(clip.getJavaArea());
+ }
+
+ return dstRegion.mArea.getBounds().isEmpty() == false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeGetBounds(int native_region, Rect rect) {
+ Region_Delegate region = sManager.getDelegate(native_region);
+ if (region == null) {
+ return true;
+ }
+
+ Rectangle bounds = region.mArea.getBounds();
+ if (bounds.isEmpty()) {
+ rect.left = rect.top = rect.right = rect.bottom = 0;
+ return false;
+ }
+
+ rect.left = bounds.x;
+ rect.top = bounds.y;
+ rect.right = bounds.x + bounds.width;
+ rect.bottom = bounds.y + bounds.height;
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeGetBoundaryPath(int native_region, int native_path) {
+ Region_Delegate region = sManager.getDelegate(native_region);
+ if (region == null) {
+ return false;
+ }
+
+ Path_Delegate path = Path_Delegate.getDelegate(native_path);
+ if (path == null) {
+ return false;
+ }
+
+ if (region.mArea.isEmpty()) {
+ path.reset();
+ return false;
+ }
+
+ path.setPathIterator(region.mArea.getPathIterator(new AffineTransform()));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeOp(int native_dst,
+ int left, int top, int right, int bottom, int op) {
+ Region_Delegate region = sManager.getDelegate(native_dst);
+ if (region == null) {
+ return false;
+ }
+
+ region.mArea = combineShapes(region.mArea,
+ new Rectangle2D.Float(left, top, right - left, bottom - top), op);
+
+ assert region.mArea != null;
+ if (region.mArea != null) {
+ region.mArea = new Area();
+ }
+
+ return region.mArea.getBounds().isEmpty() == false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeOp(int native_dst, Rect rect, int native_region, int op) {
+ Region_Delegate region = sManager.getDelegate(native_dst);
+ if (region == null) {
+ return false;
+ }
+
+ region.mArea = combineShapes(region.mArea,
+ new Rectangle2D.Float(rect.left, rect.top, rect.width(), rect.height()), op);
+
+ assert region.mArea != null;
+ if (region.mArea != null) {
+ region.mArea = new Area();
+ }
+
+ return region.mArea.getBounds().isEmpty() == false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeOp(int native_dst,
+ int native_region1, int native_region2, int op) {
+ Region_Delegate dstRegion = sManager.getDelegate(native_dst);
+ if (dstRegion == null) {
+ return true;
+ }
+
+ Region_Delegate region1 = sManager.getDelegate(native_region1);
+ if (region1 == null) {
+ return false;
+ }
+
+ Region_Delegate region2 = sManager.getDelegate(native_region2);
+ if (region2 == null) {
+ return false;
+ }
+
+ dstRegion.mArea = combineShapes(region1.mArea, region2.mArea, op);
+
+ assert dstRegion.mArea != null;
+ if (dstRegion.mArea != null) {
+ dstRegion.mArea = new Area();
+ }
+
+ return dstRegion.mArea.getBounds().isEmpty() == false;
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreateFromParcel(Parcel p) {
+ // This is only called by Region.CREATOR (Parcelable.Creator<Region>), which is only
+ // used during aidl call so really this should not be called.
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "AIDL is not suppored, and therefore Regions cannot be created from parcels.",
+ null /*data*/);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeWriteToParcel(int native_region,
+ Parcel p) {
+ // This is only called when sending a region through aidl, so really this should not
+ // be called.
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "AIDL is not suppored, and therefore Regions cannot be written to parcels.",
+ null /*data*/);
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeEquals(int native_r1, int native_r2) {
+ Region_Delegate region1 = sManager.getDelegate(native_r1);
+ if (region1 == null) {
+ return false;
+ }
+
+ Region_Delegate region2 = sManager.getDelegate(native_r2);
+ if (region2 == null) {
+ return false;
+ }
+
+ return region1.mArea.equals(region2.mArea);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader.java b/tools/layoutlib/bridge/src/android/graphics/Shader.java
deleted file mode 100644
index 0cc5940..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Shader.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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;
-
-
-
-/**
- * Shader is the based class for objects that return horizontal spans of colors
- * during drawing. A subclass of Shader is installed in a Paint calling
- * paint.setShader(shader). After that any object (other than a bitmap) that is
- * drawn with that paint will get its color(s) from the shader.
- */
-public abstract class Shader {
-
- private final Matrix mMatrix = new Matrix();
-
- public enum TileMode {
- /**
- * replicate the edge color if the shader draws outside of its
- * original bounds
- */
- CLAMP (0),
- /**
- * repeat the shader's image horizontally and vertically
- */
- REPEAT (1),
- /**
- * repeat the shader's image horizontally and vertically, alternating
- * mirror images so that adjacent images always seam
- */
- MIRROR (2);
-
- TileMode(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
- /**
- * Return true if the shader has a non-identity local matrix.
- * @param localM If not null, it is set to the shader's local matrix.
- * @return true if the shader has a non-identity local matrix
- */
- public boolean getLocalMatrix(Matrix localM) {
- if (localM != null) {
- localM.set(mMatrix);
- }
-
- return !mMatrix.isIdentity();
- }
-
- /**
- * Set the shader's local matrix. Passing null will reset the shader's
- * matrix to identity
- * @param localM The shader's new local matrix, or null to specify identity
- */
- public void setLocalMatrix(Matrix localM) {
- if (localM != null) {
- mMatrix.set(localM);
- } else {
- mMatrix.reset();
- }
- }
-
- /**
- * Returns a java.awt.Paint object matching this shader.
- */
- abstract java.awt.Paint getJavaPaint();
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
new file mode 100644
index 0000000..472fc80
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Shader.TileMode;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Shader
+ *
+ * Through the layoutlib_create tool, the original native methods of Shader have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Shader class.
+ *
+ * This also serve as a base class for all Shader delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class Shader_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<Shader_Delegate> sManager =
+ new DelegateManager<Shader_Delegate>(Shader_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+ private Matrix_Delegate mLocalMatrix = null;
+
+ // ---- Public Helper methods ----
+
+ public static Shader_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ /**
+ * Returns the {@link TileMode} matching the given int.
+ * @param tileMode the tile mode int value
+ * @return the TileMode enum.
+ */
+ public static TileMode getTileMode(int tileMode) {
+ for (TileMode tm : TileMode.values()) {
+ if (tm.nativeInt == tileMode) {
+ return tm;
+ }
+ }
+
+ assert false;
+ return TileMode.CLAMP;
+ }
+
+ public abstract java.awt.Paint getJavaPaint();
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+ public boolean isValid() {
+ if (mLocalMatrix != null && mLocalMatrix.getAffineTransform().getDeterminant() == 0) {
+ return false;
+ }
+
+ return true;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int native_shader) {
+ sManager.removeJavaReferenceFor(native_shader);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeGetLocalMatrix(int native_shader, int matrix_instance) {
+ // get the delegate from the native int.
+ Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
+ if (shaderDelegate == null) {
+ return false;
+ }
+
+ // get the (optional) out matrix.
+ Matrix_Delegate outMatrixDelegate = Matrix_Delegate.getDelegate(matrix_instance);
+
+ if (shaderDelegate.mLocalMatrix == null || shaderDelegate.mLocalMatrix.isIdentity()) {
+ if (outMatrixDelegate != null) {
+ outMatrixDelegate.reset();
+ }
+ return false;
+ }
+
+ if (outMatrixDelegate != null) {
+ outMatrixDelegate.set(shaderDelegate.mLocalMatrix);
+ }
+
+ return true;
+ }
+
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetLocalMatrix(int native_shader, int matrix_instance) {
+ // get the delegate from the native int.
+ Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
+ if (shaderDelegate == null) {
+ return;
+ }
+
+ shaderDelegate.mLocalMatrix = Matrix_Delegate.getDelegate(matrix_instance);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ protected java.awt.geom.AffineTransform getLocalMatrix() {
+ if (mLocalMatrix != null) {
+ return mLocalMatrix.getAffineTransform();
+ }
+
+ return new java.awt.geom.AffineTransform();
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java
new file mode 100644
index 0000000..410df0c
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.SumPathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of SumPathEffect have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original SumPathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public class SumPathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Sum Path Effects are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int first, int second) {
+ SumPathEffect_Delegate newDelegate = new SumPathEffect_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
index 87036ed..f70f9cf 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,9 +16,53 @@
package android.graphics;
-public class SweepGradient extends GradientShader {
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
- private SweepGradientPaint mPaint;
+/**
+ * Delegate implementing the native methods of android.graphics.SweepGradient
+ *
+ * Through the layoutlib_create tool, the original native methods of SweepGradient have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original SweepGradient class.
+ *
+ * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
+ *
+ * @see Shader_Delegate
+ *
+ */
+public class SweepGradient_Delegate extends Gradient_Delegate {
+
+ // ---- delegate data ----
+ private java.awt.Paint mJavaPaint;
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public java.awt.Paint getJavaPaint() {
+ return mJavaPaint;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate1(float x, float y, int colors[], float positions[]) {
+ SweepGradient_Delegate newDelegate = new SweepGradient_Delegate(x, y, colors, positions);
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate2(float x, float y, int color0, int color1) {
+ return nativeCreate1(x, y, new int[] { color0, color1 }, null /*positions*/);
+ }
+
+ // ---- Private delegate/helper methods ----
/**
* A subclass of Shader that draws a sweep gradient around a center point.
@@ -34,36 +78,19 @@ public class SweepGradient extends GradientShader {
* If positions is NULL, then the colors are automatically
* spaced evenly.
*/
- public SweepGradient(float cx, float cy,
+ private SweepGradient_Delegate(float cx, float cy,
int colors[], float positions[]) {
super(colors, positions);
-
- mPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
+ mJavaPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
}
- /**
- * A subclass of Shader that draws a sweep gradient around a center point.
- *
- * @param cx The x-coordinate of the center
- * @param cy The y-coordinate of the center
- * @param color0 The color to use at the start of the sweep
- * @param color1 The color to use at the end of the sweep
- */
- public SweepGradient(float cx, float cy, int color0, int color1) {
- this(cx, cy, new int[] { color0, color1}, null /*positions*/);
- }
-
- @Override
- java.awt.Paint getJavaPaint() {
- return mPaint;
- }
-
- private static class SweepGradientPaint extends GradientPaint {
+ private class SweepGradientPaint extends GradientPaint {
private final float mCx;
private final float mCy;
- public SweepGradientPaint(float cx, float cy, int[] colors, float[] positions) {
+ public SweepGradientPaint(float cx, float cy, int[] colors,
+ float[] positions) {
super(colors, positions, null /*tileMode*/);
mCx = cx;
mCy = cy;
@@ -76,14 +103,40 @@ public class SweepGradient extends GradientShader {
java.awt.geom.AffineTransform xform,
java.awt.RenderingHints hints) {
precomputeGradientColors();
- return new SweepGradientPaintContext(colorModel);
+
+ java.awt.geom.AffineTransform canvasMatrix;
+ try {
+ canvasMatrix = xform.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in SweepGradient", e, null /*data*/);
+ canvasMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
+ try {
+ localMatrix = localMatrix.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in SweepGradient", e, null /*data*/);
+ localMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ return new SweepGradientPaintContext(canvasMatrix, localMatrix, colorModel);
}
private class SweepGradientPaintContext implements java.awt.PaintContext {
+ private final java.awt.geom.AffineTransform mCanvasMatrix;
+ private final java.awt.geom.AffineTransform mLocalMatrix;
private final java.awt.image.ColorModel mColorModel;
- public SweepGradientPaintContext(java.awt.image.ColorModel colorModel) {
+ public SweepGradientPaintContext(
+ java.awt.geom.AffineTransform canvasMatrix,
+ java.awt.geom.AffineTransform localMatrix,
+ java.awt.image.ColorModel colorModel) {
+ mCanvasMatrix = canvasMatrix;
+ mLocalMatrix = localMatrix;
mColorModel = colorModel;
}
@@ -103,10 +156,23 @@ public class SweepGradient extends GradientShader {
// compute angle from each point to the center, and figure out the distance from
// it.
int index = 0;
+ float[] pt1 = new float[2];
+ float[] pt2 = new float[2];
for (int iy = 0 ; iy < h ; iy++) {
for (int ix = 0 ; ix < w ; ix++) {
- float dx = x + ix - mCx;
- float dy = y + iy - mCy;
+ // handle the canvas transform
+ pt1[0] = x + ix;
+ pt1[1] = y + iy;
+ mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ // handle the local matrix
+ pt1[0] = pt2[0] - mCx;
+ pt1[1] = pt2[1] - mCy;
+ mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ float dx = pt2[0];
+ float dy = pt2[1];
+
float angle;
if (dx == 0) {
angle = (float) (dy < 0 ? 3 * Math.PI / 2 : Math.PI / 2);
@@ -135,6 +201,4 @@ public class SweepGradient extends GradientShader {
}
}
-
}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface.java b/tools/layoutlib/bridge/src/android/graphics/Typeface.java
deleted file mode 100644
index af3adb5..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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 com.android.layoutlib.bridge.FontLoader;
-
-import android.content.res.AssetManager;
-
-import java.awt.Font;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Re-implementation of Typeface over java.awt
- */
-public class Typeface {
- private static final String DEFAULT_FAMILY = "sans-serif";
- private static final int[] styleBuffer = new int[1];
-
- /** The default NORMAL typeface object */
- public static Typeface DEFAULT;
- /**
- * The default BOLD typeface object. Note: this may be not actually be
- * bold, depending on what fonts are installed. Call getStyle() to know
- * for sure.
- */
- public static Typeface DEFAULT_BOLD;
- /** The NORMAL style of the default sans serif typeface. */
- public static Typeface SANS_SERIF;
- /** The NORMAL style of the default serif typeface. */
- public static Typeface SERIF;
- /** The NORMAL style of the default monospace typeface. */
- public static Typeface MONOSPACE;
-
- private static Typeface[] sDefaults;
- private static FontLoader mFontLoader;
-
- private final int mStyle;
- private final List<Font> mFonts;
- private final String mFamily;
-
- // Style
- public static final int NORMAL = _Original_Typeface.NORMAL;
- public static final int BOLD = _Original_Typeface.BOLD;
- public static final int ITALIC = _Original_Typeface.ITALIC;
- public static final int BOLD_ITALIC = _Original_Typeface.BOLD_ITALIC;
-
- /**
- * Returns the underlying {@link Font} objects. The first item in the list is the real
- * font. Any other items are fallback fonts for characters not found in the first one.
- */
- public List<Font> getFonts() {
- return mFonts;
- }
-
- /** Returns the typeface's intrinsic style attributes */
- public int getStyle() {
- return mStyle;
- }
-
- /** Returns true if getStyle() has the BOLD bit set. */
- public final boolean isBold() {
- return (getStyle() & BOLD) != 0;
- }
-
- /** Returns true if getStyle() has the ITALIC bit set. */
- public final boolean isItalic() {
- return (getStyle() & ITALIC) != 0;
- }
-
- /**
- * Create a typeface object given a family name, and option style information.
- * If null is passed for the name, then the "default" font will be chosen.
- * The resulting typeface object can be queried (getStyle()) to discover what
- * its "real" style characteristics are.
- *
- * @param familyName May be null. The name of the font family.
- * @param style The style (normal, bold, italic) of the typeface.
- * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
- * @return The best matching typeface.
- */
- public static Typeface create(String familyName, int style) {
- styleBuffer[0] = style;
- Font font = mFontLoader.getFont(familyName, styleBuffer);
- if (font != null) {
- ArrayList<Font> list = new ArrayList<Font>();
- list.add(font);
- list.addAll(mFontLoader.getFallBackFonts());
- return new Typeface(familyName, styleBuffer[0], list);
- }
-
- return null;
- }
-
- /**
- * Create a typeface object that best matches the specified existing
- * typeface and the specified Style. Use this call if you want to pick a new
- * style from the same family of an existing typeface object. If family is
- * null, this selects from the default font's family.
- *
- * @param family May be null. The name of the existing type face.
- * @param style The style (normal, bold, italic) of the typeface.
- * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
- * @return The best matching typeface.
- */
- public static Typeface create(Typeface family, int style) {
- styleBuffer[0] = style;
- Font font = mFontLoader.getFont(family.mFamily, styleBuffer);
- if (font != null) {
- ArrayList<Font> list = new ArrayList<Font>();
- list.add(font);
- list.addAll(mFontLoader.getFallBackFonts());
- return new Typeface(family.mFamily, styleBuffer[0], list);
- }
-
- return null;
- }
-
- /**
- * Returns one of the default typeface objects, based on the specified style
- *
- * @return the default typeface that corresponds to the style
- */
- public static Typeface defaultFromStyle(int style) {
- return sDefaults[style];
- }
-
- /**
- * Create a new typeface from the specified font data.
- * @param mgr The application's asset manager
- * @param path The file name of the font data in the assets directory
- * @return The new typeface.
- */
- public static Typeface createFromAsset(AssetManager mgr, String path) {
- return null;
- //return new Typeface(nativeCreateFromAsset(mgr, path));
- }
-
- // don't allow clients to call this directly
- private Typeface(String family, int style, List<Font> fonts) {
- mFamily = family;
- mFonts = Collections.unmodifiableList(fonts);
- mStyle = style;
- }
-
- public static void init(FontLoader fontLoader) {
- mFontLoader = fontLoader;
-
- DEFAULT = create(DEFAULT_FAMILY, NORMAL);
- DEFAULT_BOLD = create(DEFAULT_FAMILY, BOLD);
- SANS_SERIF = create("sans-serif", NORMAL);
- SERIF = create("serif", NORMAL);
- MONOSPACE = create("monospace", NORMAL);
- sDefaults = new Typeface[] {
- DEFAULT,
- DEFAULT_BOLD,
- create(DEFAULT_FAMILY, ITALIC),
- create(DEFAULT_FAMILY, BOLD_ITALIC),
- };
-
- /*
- 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);
-
- sDefaults = new Typeface[] {
- DEFAULT,
- DEFAULT_BOLD,
- create((String)null, Typeface.ITALIC),
- create((String)null, Typeface.BOLD_ITALIC),
- };*/
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
new file mode 100644
index 0000000..0f084f7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.layoutlib.bridge.impl.FontLoader;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.res.AssetManager;
+
+import java.awt.Font;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Typeface
+ *
+ * Through the layoutlib_create tool, the original native methods of Typeface have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Typeface class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Typeface_Delegate {
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Typeface_Delegate> sManager =
+ new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class);
+
+ // ---- delegate helper data ----
+ private static final String DEFAULT_FAMILY = "sans-serif";
+ private static final int[] STYLE_BUFFER = new int[1];
+
+ private static FontLoader sFontLoader;
+ private static final List<Typeface_Delegate> sPostInitDelegate =
+ new ArrayList<Typeface_Delegate>();
+
+ // ---- delegate data ----
+
+ private final String mFamily;
+ private int mStyle;
+ private List<Font> mFonts;
+
+
+ // ---- Public Helper methods ----
+
+ public static synchronized void init(FontLoader fontLoader) {
+ sFontLoader = fontLoader;
+
+ for (Typeface_Delegate delegate : sPostInitDelegate) {
+ delegate.init();
+ }
+ sPostInitDelegate.clear();
+ }
+
+ public static Typeface_Delegate getDelegate(int nativeTypeface) {
+ return sManager.getDelegate(nativeTypeface);
+ }
+
+ public static List<Font> getFonts(Typeface typeface) {
+ return getFonts(typeface.native_instance);
+ }
+
+ public static List<Font> getFonts(int native_int) {
+ Typeface_Delegate delegate = sManager.getDelegate(native_int);
+ if (delegate == null) {
+ return null;
+ }
+
+ return delegate.getFonts();
+ }
+
+ public List<Font> getFonts() {
+ return mFonts;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static synchronized int nativeCreate(String familyName, int style) {
+ if (familyName == null) {
+ familyName = DEFAULT_FAMILY;
+ }
+
+ Typeface_Delegate newDelegate = new Typeface_Delegate(familyName, style);
+ if (sFontLoader != null) {
+ newDelegate.init();
+ } else {
+ // font loader has not been initialized yet, add the delegate to a list of delegates
+ // to init when the font loader is initialized.
+ // There won't be any rendering before this happens anyway.
+ sPostInitDelegate.add(newDelegate);
+ }
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static synchronized int nativeCreateFromTypeface(int native_instance, int style) {
+ Typeface_Delegate delegate = sManager.getDelegate(native_instance);
+ if (delegate == null) {
+ return 0;
+ }
+
+ Typeface_Delegate newDelegate = new Typeface_Delegate(delegate.mFamily, style);
+ if (sFontLoader != null) {
+ newDelegate.init();
+ } else {
+ // font loader has not been initialized yet, add the delegate to a list of delegates
+ // to init when the font loader is initialized.
+ // There won't be any rendering before this happens anyway.
+ sPostInitDelegate.add(newDelegate);
+ }
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static synchronized int nativeCreateFromAsset(AssetManager mgr, String path) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Typeface.createFromAsset() is not supported.", null /*throwable*/, null /*data*/);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static synchronized int nativeCreateFromFile(String path) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Typeface.createFromFile() is not supported.", null /*throwable*/, null /*data*/);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeUnref(int native_instance) {
+ sManager.removeJavaReferenceFor(native_instance);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeGetStyle(int native_instance) {
+ Typeface_Delegate delegate = sManager.getDelegate(native_instance);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mStyle;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setGammaForText(float blackGamma, float whiteGamma) {
+ // This is for device testing only: pass
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private Typeface_Delegate(String family, int style) {
+ mFamily = family;
+ mStyle = style;
+ }
+
+ private void init() {
+ STYLE_BUFFER[0] = mStyle;
+ Font font = sFontLoader.getFont(mFamily, STYLE_BUFFER);
+ if (font != null) {
+ List<Font> list = new ArrayList<Font>();
+ list.add(font);
+ list.addAll(sFontLoader.getFallBackFonts());
+ mFonts = Collections.unmodifiableList(list);
+ mStyle = STYLE_BUFFER[0];
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
new file mode 100644
index 0000000..962d69c
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Composite;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Xfermode
+ *
+ * Through the layoutlib_create tool, the original native methods of Xfermode have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * This class behaves like the original native implementation, but in Java, keeping previously
+ * native data into its own objects and mapping them to int that are sent back and forth between
+ * it and the original Xfermode class.
+ *
+ * This also serve as a base class for all Xfermode delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class Xfermode_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<Xfermode_Delegate> sManager =
+ new DelegateManager<Xfermode_Delegate>(Xfermode_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static Xfermode_Delegate getDelegate(int native_instance) {
+ return sManager.getDelegate(native_instance);
+ }
+
+ public abstract Composite getComposite(int alpha);
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int native_instance) {
+ sManager.removeJavaReferenceFor(native_instance);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+}
diff --git a/tools/layoutlib/bridge/src/android/os/Build_Delegate.java b/tools/layoutlib/bridge/src/android/os/Build_Delegate.java
new file mode 100644
index 0000000..ff82a5e
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/os/Build_Delegate.java
@@ -0,0 +1,48 @@
+/*
+ * 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.os;
+
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.util.Map;
+
+/**
+ * Delegate implementing the native methods of android.os.Build
+ *
+ * Through the layoutlib_create tool, the original native methods of Build have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ */
+public class Build_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static String getString(String property) {
+ Map<String, String> properties = Bridge.getPlatformProperties();
+ String value = properties.get(property);
+ if (value != null) {
+ return value;
+ }
+
+ return Build.UNKNOWN;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java b/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java
new file mode 100644
index 0000000..2152c8a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+
+/**
+ * Delegate overriding selected methods of android.os.Handler
+ *
+ * Through the layoutlib_create tool, selected methods of Handler have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ *
+ */
+public class Handler_Delegate {
+
+ // -------- Delegate methods
+
+ @LayoutlibDelegate
+ /*package*/ static boolean sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
+ // get the callback
+ IHandlerCallback callback = sCallbacks.get();
+ if (callback != null) {
+ callback.sendMessageAtTime(handler, msg, uptimeMillis);
+ }
+ return true;
+ }
+
+ // -------- Delegate implementation
+
+ public interface IHandlerCallback {
+ void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis);
+ }
+
+ private final static ThreadLocal<IHandlerCallback> sCallbacks =
+ new ThreadLocal<IHandlerCallback>();
+
+ public static void setCallback(IHandlerCallback callback) {
+ sCallbacks.set(callback);
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
new file mode 100644
index 0000000..63711a7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.os;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.os.SystemClock
+ *
+ * Through the layoutlib_create tool, the original native methods of SystemClock have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ */
+public class SystemClock_Delegate {
+ private static long sBootTime = System.currentTimeMillis();
+
+ @LayoutlibDelegate
+ /*package*/ static boolean setCurrentTimeMillis(long millis) {
+ return true;
+ }
+
+ /**
+ * Returns milliseconds since boot, not counting time spent in deep sleep.
+ * <b>Note:</b> This value may get reset occasionally (before it would
+ * otherwise wrap around).
+ *
+ * @return milliseconds of non-sleep uptime since boot.
+ */
+ @LayoutlibDelegate
+ /*package*/ static long uptimeMillis() {
+ return System.currentTimeMillis() - sBootTime;
+ }
+
+ /**
+ * Returns milliseconds since boot, including time spent in sleep.
+ *
+ * @return elapsed milliseconds since boot.
+ */
+ @LayoutlibDelegate
+ /*package*/ static long elapsedRealtime() {
+ return System.currentTimeMillis() - sBootTime;
+ }
+
+ /**
+ * Returns milliseconds running in the current thread.
+ *
+ * @return elapsed milliseconds in the thread
+ */
+ @LayoutlibDelegate
+ /*package*/ static long currentThreadTimeMillis() {
+ return System.currentTimeMillis();
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/util/FloatMath.java b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
index aae44f2..1df78c2 100644
--- a/tools/layoutlib/bridge/src/android/util/FloatMath.java
+++ b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
@@ -16,20 +16,23 @@
package android.util;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
/**
- * Reimplements _Original_FloatMath with the standard libraries.
- *
- * Math routines similar to those found in {@link java.lang.Math}. Performs
- * computations on {@code float} values directly without incurring the overhead
- * of conversions to and from {@code double}.
+ * Delegate implementing the native methods of android.util.FloatMath
+ *
+ * Through the layoutlib_create tool, the original native methods of FloatMath have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
*
- * <p>On one platform, {@code FloatMath.sqrt(100)} executes in one third of the
- * time required by {@code java.lang.Math.sqrt(100)}.</p>
*/
-public class FloatMath {
+/*package*/ final class FloatMath_Delegate {
/** Prevents instantiation. */
- private FloatMath() {}
+ private FloatMath_Delegate() {}
/**
* Returns the float conversion of the most positive (i.e. closest to
@@ -38,7 +41,8 @@ public class FloatMath {
* @param value to be converted
* @return the floor of value
*/
- public static float floor(float value) {
+ @LayoutlibDelegate
+ /*package*/ static float floor(float value) {
return (float)Math.floor(value);
}
@@ -49,7 +53,8 @@ public class FloatMath {
* @param value to be converted
* @return the ceiling of value
*/
- public static float ceil(float value) {
+ @LayoutlibDelegate
+ /*package*/ static float ceil(float value) {
return (float)Math.ceil(value);
}
@@ -59,7 +64,8 @@ public class FloatMath {
* @param angle to compute the cosine of, in radians
* @return the sine of angle
*/
- public static float sin(float angle) {
+ @LayoutlibDelegate
+ /*package*/ static float sin(float angle) {
return (float)Math.sin(angle);
}
@@ -69,7 +75,8 @@ public class FloatMath {
* @param angle to compute the cosine of, in radians
* @return the cosine of angle
*/
- public static float cos(float angle) {
+ @LayoutlibDelegate
+ /*package*/ static float cos(float angle) {
return (float)Math.cos(angle);
}
@@ -80,7 +87,8 @@ public class FloatMath {
* @param value to compute sqrt of
* @return the square root of value
*/
- public static float sqrt(float value) {
+ @LayoutlibDelegate
+ /*package*/ static float sqrt(float value) {
return (float)Math.sqrt(value);
}
}
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
new file mode 100644
index 0000000..d5266a5
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import com.android.layoutlib.bridge.android.BridgeInflater;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.res.TypedArray;
+import android.content.res.XmlResourceParser;
+import android.util.AttributeSet;
+import android.util.Xml;
+
+import java.io.IOException;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link LayoutInflater}
+ *
+ * Through the layoutlib_create tool, the original methods of LayoutInflater have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Generally we don't want to copy-paste a huge method like that just for one small features,
+ * but because this is done after this platform is final and the next version (Honeycomb) has a
+ * better mechanism (or slightly less copy-paste), maintenance of this duplicated code is not
+ * a problem.
+ *
+ */
+public class LayoutInflater_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static void parseInclude(LayoutInflater thisInflater,
+ XmlPullParser parser, View parent, AttributeSet attrs)
+ throws XmlPullParserException, IOException {
+
+ int type;
+
+ if (parent instanceof ViewGroup) {
+ final int layout = attrs.getAttributeResourceValue(null, "layout", 0);
+ if (layout == 0) {
+ final String value = attrs.getAttributeValue(null, "layout");
+ if (value == null) {
+ throw new InflateException("You must specifiy a layout in the"
+ + " include tag: <include layout=\"@layout/layoutID\" />");
+ } else {
+ throw new InflateException("You must specifiy a valid layout "
+ + "reference. The layout ID " + value + " is not valid.");
+ }
+ } else {
+ final XmlResourceParser childParser =
+ thisInflater.getContext().getResources().getLayout(layout);
+
+ try {
+ final AttributeSet childAttrs = Xml.asAttributeSet(childParser);
+
+ while ((type = childParser.next()) != XmlPullParser.START_TAG &&
+ type != XmlPullParser.END_DOCUMENT) {
+ // Empty.
+ }
+
+ if (type != XmlPullParser.START_TAG) {
+ throw new InflateException(childParser.getPositionDescription() +
+ ": No start tag found!");
+ }
+
+ final String childName = childParser.getName();
+
+ if (LayoutInflater.TAG_MERGE.equals(childName)) {
+ // ---- START MODIFICATIONS ----
+ if (thisInflater instanceof BridgeInflater) {
+ ((BridgeInflater) thisInflater).setIsInMerge(true);
+ }
+ // ---- END MODIFICATIONS ----
+
+ // Inflate all children.
+ thisInflater.rInflate(childParser, parent, childAttrs);
+
+ // ---- START MODIFICATIONS ----
+ if (thisInflater instanceof BridgeInflater) {
+ ((BridgeInflater) thisInflater).setIsInMerge(false);
+ }
+ // ---- END MODIFICATIONS ----
+ } else {
+ final View view = thisInflater.createViewFromTag(childName, childAttrs);
+ final ViewGroup group = (ViewGroup) parent;
+
+ // We try to load the layout params set in the <include /> tag. If
+ // they don't exist, we will rely on the layout params set in the
+ // included XML file.
+ // During a layoutparams generation, a runtime exception is thrown
+ // if either layout_width or layout_height is missing. We catch
+ // this exception and set localParams accordingly: true means we
+ // successfully loaded layout params from the <include /> tag,
+ // false means we need to rely on the included layout params.
+ ViewGroup.LayoutParams params = null;
+ try {
+ params = group.generateLayoutParams(attrs);
+ } catch (RuntimeException e) {
+ params = group.generateLayoutParams(childAttrs);
+ } finally {
+ if (params != null) {
+ view.setLayoutParams(params);
+ }
+ }
+
+ // Inflate all children.
+ thisInflater.rInflate(childParser, view, childAttrs);
+
+ // Attempt to override the included layout's android:id with the
+ // one set on the <include /> tag itself.
+ TypedArray a = thisInflater.mContext.obtainStyledAttributes(attrs,
+ com.android.internal.R.styleable.View, 0, 0);
+ int id = a.getResourceId(com.android.internal.R.styleable.View_id, View.NO_ID);
+ // While we're at it, let's try to override android:visibility.
+ int visibility = a.getInt(com.android.internal.R.styleable.View_visibility, -1);
+ a.recycle();
+
+ if (id != View.NO_ID) {
+ view.setId(id);
+ }
+
+ switch (visibility) {
+ case 0:
+ view.setVisibility(View.VISIBLE);
+ break;
+ case 1:
+ view.setVisibility(View.INVISIBLE);
+ break;
+ case 2:
+ view.setVisibility(View.GONE);
+ break;
+ }
+
+ group.addView(view);
+ }
+ } finally {
+ childParser.close();
+ }
+ }
+ } else {
+ throw new InflateException("<include /> can only be used inside of a ViewGroup");
+ }
+
+ final int currentDepth = parser.getDepth();
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > currentDepth) && type != XmlPullParser.END_DOCUMENT) {
+ // Empty
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode.java b/tools/layoutlib/bridge/src/android/view/View_Delegate.java
index 974ae49..8215f7c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode.java
+++ b/tools/layoutlib/bridge/src/android/view/View_Delegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * Copyright (C) 2010 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -14,27 +14,21 @@
* limitations under the License.
*/
-package android.graphics;
+package android.view;
-import android.graphics.PorterDuff.Mode;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-public class PorterDuffXfermode extends Xfermode {
- private final Mode mMode;
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link View}
+ *
+ * Through the layoutlib_create tool, the original methods of View have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class View_Delegate {
- /**
- * Create an xfermode that uses the specified porter-duff mode.
- *
- * @param mode The porter-duff mode that is applied
- */
- public PorterDuffXfermode(PorterDuff.Mode mode) {
- mMode = mode;
- }
-
- //---------- Custom Methods
-
- public PorterDuff.Mode getMode() {
- return mMode;
+ @LayoutlibDelegate
+ /*package*/ static boolean isInEditMode(View thisView) {
+ return true;
}
-
- //----------
}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/util/XmlUtils_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/util/XmlUtils_Delegate.java
new file mode 100644
index 0000000..bf998b8
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/internal/util/XmlUtils_Delegate.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.util;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link XmlUtils}
+ *
+ * Through the layoutlib_create tool, the original methods of XmlUtils have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class XmlUtils_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static final int convertValueToInt(CharSequence charSeq, int defaultValue) {
+ if (null == charSeq)
+ return defaultValue;
+
+ String nm = charSeq.toString();
+
+ // This code is copied from the original implementation. The issue is that
+ // The Dalvik libraries are able to handle Integer.parse("XXXXXXXX", 16) where XXXXXXX
+ // is > 80000000 but the Java VM cannot.
+
+ int sign = 1;
+ int index = 0;
+ int len = nm.length();
+ int base = 10;
+
+ if ('-' == nm.charAt(0)) {
+ sign = -1;
+ index++;
+ }
+
+ if ('0' == nm.charAt(index)) {
+ // Quick check for a zero by itself
+ if (index == (len - 1))
+ return 0;
+
+ char c = nm.charAt(index + 1);
+
+ if ('x' == c || 'X' == c) {
+ index += 2;
+ base = 16;
+ } else {
+ index++;
+ base = 8;
+ }
+ }
+ else if ('#' == nm.charAt(index)) {
+ index++;
+ base = 16;
+ }
+
+ return ((int)Long.parseLong(nm.substring(index), base)) * sign;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index f91f601..b1a7824 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -16,68 +16,47 @@
package com.android.layoutlib.bridge;
-import com.android.internal.util.XmlUtils;
-import com.android.layoutlib.api.ILayoutBridge;
-import com.android.layoutlib.api.ILayoutLog;
-import com.android.layoutlib.api.ILayoutResult;
-import com.android.layoutlib.api.IProjectCallback;
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IStyleResourceValue;
-import com.android.layoutlib.api.IXmlPullParser;
-import com.android.layoutlib.api.ILayoutResult.ILayoutViewInfo;
-import com.android.layoutlib.bridge.LayoutResult.LayoutViewInfo;
-import com.android.ninepatch.NinePatch;
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
+import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
+
+import com.android.ide.common.rendering.api.Capability;
+import com.android.ide.common.rendering.api.DrawableParams;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderSession;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.layoutlib.bridge.android.BridgeAssetManager;
+import com.android.layoutlib.bridge.impl.FontLoader;
+import com.android.layoutlib.bridge.impl.RenderDrawable;
+import com.android.layoutlib.bridge.impl.RenderSessionImpl;
+import com.android.ninepatch.NinePatchChunk;
+import com.android.resources.ResourceType;
import com.android.tools.layoutlib.create.MethodAdapter;
import com.android.tools.layoutlib.create.OverrideMethod;
+import com.android.util.Pair;
-import android.content.res.Configuration;
import android.graphics.Bitmap;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.graphics.Region;
import android.graphics.Typeface;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.IBinder;
+import android.graphics.Typeface_Delegate;
import android.os.Looper;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-import android.view.BridgeInflater;
-import android.view.InputChannel;
-import android.view.IWindow;
-import android.view.IWindowSession;
-import android.view.KeyEvent;
-import android.view.MotionEvent;
-import android.view.Surface;
-import android.view.SurfaceView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.View.AttachInfo;
-import android.view.View.MeasureSpec;
-import android.view.WindowManager.LayoutParams;
-import android.widget.FrameLayout;
-import android.widget.TabHost;
-import android.widget.TabWidget;
+import java.io.File;
import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
-import java.util.Collection;
+import java.util.Arrays;
+import java.util.EnumMap;
+import java.util.EnumSet;
import java.util.HashMap;
import java.util.Map;
+import java.util.concurrent.locks.ReentrantLock;
/**
* Main entry point of the LayoutLib Bridge.
* <p/>To use this bridge, simply instantiate an object of type {@link Bridge} and call
- * {@link #computeLayout(IXmlPullParser, Object, int, int, String, boolean, Map, Map, IProjectCallback, ILayoutLog)}.
+ * {@link #createScene(SceneParams)}
*/
-public final class Bridge implements ILayoutBridge {
-
- private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
- private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
+public final class Bridge extends com.android.ide.common.rendering.api.Bridge {
public static class StaticMethodNotImplementedException extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -88,84 +67,137 @@ public final class Bridge implements ILayoutBridge {
}
/**
- * Maps from id to resource name/type. This is for android.R only.
+ * Lock to ensure only one rendering/inflating happens at a time.
+ * This is due to some singleton in the Android framework.
*/
- private final static Map<Integer, String[]> sRMap = new HashMap<Integer, String[]>();
+ private final static ReentrantLock sLock = new ReentrantLock();
+
+ /**
+ * Maps from id to resource type/name. This is for android.R only.
+ */
+ private final static Map<Integer, Pair<ResourceType, String>> sRMap =
+ new HashMap<Integer, Pair<ResourceType, String>>();
+
/**
* Same as sRMap except for int[] instead of int resources. This is for android.R only.
*/
- private final static Map<int[], String> sRArrayMap = new HashMap<int[], String>();
+ private final static Map<IntArray, String> sRArrayMap = new HashMap<IntArray, String>();
/**
* Reverse map compared to sRMap, resource type -> (resource name -> id).
* This is for android.R only.
*/
- private final static Map<String, Map<String, Integer>> sRFullMap =
- new HashMap<String, Map<String,Integer>>();
+ private final static Map<ResourceType, Map<String, Integer>> sRFullMap =
+ new EnumMap<ResourceType, Map<String,Integer>>(ResourceType.class);
private final static Map<Object, Map<String, SoftReference<Bitmap>>> sProjectBitmapCache =
new HashMap<Object, Map<String, SoftReference<Bitmap>>>();
- private final static Map<Object, Map<String, SoftReference<NinePatch>>> sProject9PatchCache =
- new HashMap<Object, Map<String, SoftReference<NinePatch>>>();
+ private final static Map<Object, Map<String, SoftReference<NinePatchChunk>>> sProject9PatchCache =
+ new HashMap<Object, Map<String, SoftReference<NinePatchChunk>>>();
private final static Map<String, SoftReference<Bitmap>> sFrameworkBitmapCache =
new HashMap<String, SoftReference<Bitmap>>();
- private final static Map<String, SoftReference<NinePatch>> sFramework9PatchCache =
- new HashMap<String, SoftReference<NinePatch>>();
+ private final static Map<String, SoftReference<NinePatchChunk>> sFramework9PatchCache =
+ new HashMap<String, SoftReference<NinePatchChunk>>();
private static Map<String, Map<String, Integer>> sEnumValueMap;
+ private static Map<String, String> sPlatformProperties;
/**
- * A default logger than prints to stdout/stderr.
+ * int[] wrapper to use as keys in maps.
*/
- private final static ILayoutLog sDefaultLogger = new ILayoutLog() {
- public void error(String message) {
- System.err.println(message);
+ private final static class IntArray {
+ private int[] mArray;
+
+ private IntArray() {
+ // do nothing
}
- public void error(Throwable t) {
- String message = t.getMessage();
- if (message == null) {
- message = t.getClass().getName();
- }
+ private IntArray(int[] a) {
+ mArray = a;
+ }
+
+ private void set(int[] a) {
+ mArray = a;
+ }
+
+ @Override
+ public int hashCode() {
+ return Arrays.hashCode(mArray);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) return true;
+ if (obj == null) return false;
+ if (getClass() != obj.getClass()) return false;
+
+ IntArray other = (IntArray) obj;
+ if (!Arrays.equals(mArray, other.mArray)) return false;
+ return true;
+ }
+ }
+ /** Instance of IntArrayWrapper to be reused in {@link #resolveResourceId(int[])}. */
+ private final static IntArray sIntArrayWrapper = new IntArray();
+
+ /**
+ * A default log than prints to stdout/stderr.
+ */
+ private final static LayoutLog sDefaultLog = new LayoutLog() {
+ @Override
+ public void error(String tag, String message, Object data) {
System.err.println(message);
}
- public void warning(String message) {
+ @Override
+ public void error(String tag, String message, Throwable throwable, Object data) {
+ System.err.println(message);
+ }
+
+ @Override
+ public void warning(String tag, String message, Object data) {
System.out.println(message);
}
};
/**
- * Logger defined during a compute layout operation.
- * <p/>
- * This logger is generally set to {@link #sDefaultLogger} except during rendering
- * operations when it might be set to a specific provided logger.
- * <p/>
- * To change this value, use a block synchronized on {@link #sDefaultLogger}.
+ * Current log.
*/
- private static ILayoutLog sLogger = sDefaultLogger;
+ private static LayoutLog sCurrentLog = sDefaultLog;
- /*
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutBridge#getApiLevel()
- */
+ private EnumSet<Capability> mCapabilities;
+
+ @Override
public int getApiLevel() {
- return API_CURRENT;
+ return com.android.ide.common.rendering.api.Bridge.API_CURRENT;
}
- /*
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutLibBridge#init(java.lang.String, java.util.Map)
- */
- public boolean init(
- String fontOsLocation, Map<String, Map<String, Integer>> enumValueMap) {
-
- return sinit(fontOsLocation, enumValueMap);
+ @Override
+ public EnumSet<Capability> getCapabilities() {
+ return mCapabilities;
}
- private static synchronized boolean sinit(String fontOsLocation,
- Map<String, Map<String, Integer>> enumValueMap) {
+ @Override
+ public boolean init(Map<String,String> platformProperties,
+ File fontLocation,
+ Map<String, Map<String, Integer>> enumValueMap,
+ LayoutLog log) {
+ sPlatformProperties = platformProperties;
+ sEnumValueMap = enumValueMap;
+
+ // don't use EnumSet.allOf(), because the bridge doesn't come with its specific version
+ // of layoutlib_api. It is provided by the client which could have a more recent version
+ // with newer, unsupported capabilities.
+ mCapabilities = EnumSet.of(
+ Capability.UNBOUND_RENDERING,
+ Capability.CUSTOM_BACKGROUND_COLOR,
+ Capability.RENDER,
+ //Capability.LAYOUT_ONLY, // disable to run on ADT 10.0 which doesn't include this.
+ Capability.EMBEDDED_LAYOUT,
+ Capability.VIEW_MANIPULATION);
+
+
+ BridgeAssetManager.initSystem();
// When DEBUG_LAYOUT is set and is not 0 or false, setup a default listener
// on static (native) methods which prints the signature on the console and
@@ -182,12 +214,8 @@ public final class Bridge implements ILayoutBridge {
OverrideMethod.setDefaultListener(new MethodAdapter() {
@Override
public void onInvokeV(String signature, boolean isNative, Object caller) {
- if (sLogger != null) {
- synchronized (sDefaultLogger) {
- sLogger.error("Missing Stub: " + signature +
- (isNative ? " (native)" : ""));
- }
- }
+ sDefaultLog.error(null, "Missing Stub: " + signature +
+ (isNative ? " (native)" : ""), null /*data*/);
if (debug.equalsIgnoreCase("throw")) {
// Throwing this exception doesn't seem that useful. It breaks
@@ -200,293 +228,138 @@ public final class Bridge implements ILayoutBridge {
});
}
- // Override View.isInEditMode to return true.
- //
- // This allows custom views that are drawn in the Graphical Layout Editor to adapt their
- // rendering for preview. Most important this let custom views know that they can't expect
- // the rest of their activities to be alive.
- OverrideMethod.setMethodListener("android.view.View#isInEditMode()Z",
- new MethodAdapter() {
- @Override
- public int onInvokeI(String signature, boolean isNative, Object caller) {
- return 1;
- }
- }
- );
-
// load the fonts.
- FontLoader fontLoader = FontLoader.create(fontOsLocation);
+ FontLoader fontLoader = FontLoader.create(fontLocation.getAbsolutePath());
if (fontLoader != null) {
- Typeface.init(fontLoader);
+ Typeface_Delegate.init(fontLoader);
} else {
return false;
}
- sEnumValueMap = enumValueMap;
-
// now parse com.android.internal.R (and only this one as android.R is a subset of
// the internal version), and put the content in the maps.
try {
- // WARNING: this only works because the class is already loaded, and therefore
- // the objects returned by Field.get() are the same as the ones used by
- // the code accessing the R class.
- // int[] does not implement equals/hashCode, and if the parsing used a different class
- // loader for the R class, this would NOT work.
Class<?> r = com.android.internal.R.class;
for (Class<?> inner : r.getDeclaredClasses()) {
- String resType = inner.getSimpleName();
-
- Map<String, Integer> fullMap = new HashMap<String, Integer>();
- sRFullMap.put(resType, fullMap);
-
- for (Field f : inner.getDeclaredFields()) {
- // only process static final fields. Since the final attribute may have
- // been altered by layoutlib_create, we only check static
- int modifiers = f.getModifiers();
- if (Modifier.isStatic(modifiers)) {
- Class<?> type = f.getType();
- if (type.isArray() && type.getComponentType() == int.class) {
- // if the object is an int[] we put it in sRArrayMap
- sRArrayMap.put((int[]) f.get(null), f.getName());
- } else if (type == int.class) {
- Integer value = (Integer) f.get(null);
- sRMap.put(value, new String[] { f.getName(), resType });
- fullMap.put(f.getName(), value);
- } else {
- assert false;
+ String resTypeName = inner.getSimpleName();
+ ResourceType resType = ResourceType.getEnum(resTypeName);
+ if (resType != null) {
+ Map<String, Integer> fullMap = new HashMap<String, Integer>();
+ sRFullMap.put(resType, fullMap);
+
+ for (Field f : inner.getDeclaredFields()) {
+ // only process static final fields. Since the final attribute may have
+ // been altered by layoutlib_create, we only check static
+ int modifiers = f.getModifiers();
+ if (Modifier.isStatic(modifiers)) {
+ Class<?> type = f.getType();
+ if (type.isArray() && type.getComponentType() == int.class) {
+ // if the object is an int[] we put it in sRArrayMap using an IntArray
+ // wrapper that properly implements equals and hashcode for the array
+ // objects, as required by the map contract.
+ sRArrayMap.put(new IntArray((int[]) f.get(null)), f.getName());
+ } else if (type == int.class) {
+ Integer value = (Integer) f.get(null);
+ sRMap.put(value, Pair.of(resType, f.getName()));
+ fullMap.put(f.getName(), value);
+ } else {
+ assert false;
+ }
}
}
}
}
- } catch (IllegalArgumentException e) {
- // FIXME: log/return the error (there's no logger object at this point!)
- e.printStackTrace();
- return false;
- } catch (IllegalAccessException e) {
- e.printStackTrace();
+ } catch (Throwable throwable) {
+ if (log != null) {
+ log.error(LayoutLog.TAG_BROKEN,
+ "Failed to load com.android.internal.R from the layout library jar",
+ throwable);
+ }
return false;
}
return true;
}
- /*
- * For compatilibty purposes, we implement the old deprecated version of computeLayout.
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
- */
- @Deprecated
- public ILayoutResult computeLayout(IXmlPullParser layoutDescription,
- Object projectKey,
- int screenWidth, int screenHeight, String themeName,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback customViewLoader, ILayoutLog logger) {
- boolean isProjectTheme = false;
- if (themeName.charAt(0) == '*') {
- themeName = themeName.substring(1);
- isProjectTheme = true;
- }
-
- return computeLayout(layoutDescription, projectKey,
- screenWidth, screenHeight, DisplayMetrics.DENSITY_DEFAULT,
- DisplayMetrics.DENSITY_DEFAULT, DisplayMetrics.DENSITY_DEFAULT,
- themeName, isProjectTheme,
- projectResources, frameworkResources, customViewLoader, logger);
- }
+ @Override
+ public boolean dispose() {
+ BridgeAssetManager.clearSystem();
- /*
- * For compatilibty purposes, we implement the old deprecated version of computeLayout.
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
- */
- @Deprecated
- public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
- int screenWidth, int screenHeight, String themeName, boolean isProjectTheme,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback customViewLoader, ILayoutLog logger) {
- return computeLayout(layoutDescription, projectKey,
- screenWidth, screenHeight, DisplayMetrics.DENSITY_DEFAULT,
- DisplayMetrics.DENSITY_DEFAULT, DisplayMetrics.DENSITY_DEFAULT,
- themeName, isProjectTheme,
- projectResources, frameworkResources, customViewLoader, logger);
- }
+ // dispose of the default typeface.
+ Typeface.sDefaults = null;
- /*
- * For compatilibty purposes, we implement the old deprecated version of computeLayout.
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
- */
- public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
- int screenWidth, int screenHeight, int density, float xdpi, float ydpi,
- String themeName, boolean isProjectTheme,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback customViewLoader, ILayoutLog logger) {
- return computeLayout(layoutDescription, projectKey,
- screenWidth, screenHeight, false /* renderFullSize */,
- density, xdpi, ydpi, themeName, isProjectTheme,
- projectResources, frameworkResources, customViewLoader, logger);
+ return true;
}
- /*
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutBridge#computeLayout(com.android.layoutlib.api.IXmlPullParser, java.lang.Object, int, int, boolean, int, float, float, java.lang.String, boolean, java.util.Map, java.util.Map, com.android.layoutlib.api.IProjectCallback, com.android.layoutlib.api.ILayoutLog)
+ /**
+ * Starts a layout session by inflating and rendering it. The method returns a
+ * {@link RenderSession} on which further actions can be taken.
+ *
+ * @param params the {@link SessionParams} object with all the information necessary to create
+ * the scene.
+ * @return a new {@link RenderSession} object that contains the result of the layout.
+ * @since 5
*/
- public ILayoutResult computeLayout(IXmlPullParser layoutDescription, Object projectKey,
- int screenWidth, int screenHeight, boolean renderFullSize,
- int density, float xdpi, float ydpi,
- String themeName, boolean isProjectTheme,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- IProjectCallback customViewLoader, ILayoutLog logger) {
- if (logger == null) {
- logger = sDefaultLogger;
- }
-
- synchronized (sDefaultLogger) {
- sLogger = logger;
- }
-
- // find the current theme and compute the style inheritance map
- Map<IStyleResourceValue, IStyleResourceValue> styleParentMap =
- new HashMap<IStyleResourceValue, IStyleResourceValue>();
-
- IStyleResourceValue currentTheme = computeStyleMaps(themeName, isProjectTheme,
- projectResources.get(BridgeConstants.RES_STYLE),
- frameworkResources.get(BridgeConstants.RES_STYLE), styleParentMap);
-
- BridgeContext context = null;
+ @Override
+ public RenderSession createSession(SessionParams params) {
try {
- // setup the display Metrics.
- DisplayMetrics metrics = new DisplayMetrics();
- metrics.densityDpi = density;
- metrics.density = density / (float) DisplayMetrics.DENSITY_DEFAULT;
- metrics.scaledDensity = metrics.density;
- metrics.widthPixels = screenWidth;
- metrics.heightPixels = screenHeight;
- metrics.xdpi = xdpi;
- metrics.ydpi = ydpi;
-
- context = new BridgeContext(projectKey, metrics, currentTheme, projectResources,
- frameworkResources, styleParentMap, customViewLoader, logger);
- BridgeInflater inflater = new BridgeInflater(context, customViewLoader);
- context.setBridgeInflater(inflater);
-
- IResourceValue windowBackground = null;
- int screenOffset = 0;
- if (currentTheme != null) {
- windowBackground = context.findItemInStyle(currentTheme, "windowBackground");
- windowBackground = context.resolveResValue(windowBackground);
-
- screenOffset = getScreenOffset(frameworkResources, currentTheme, context);
- }
-
- // we need to make sure the Looper has been initialized for this thread.
- // this is required for View that creates Handler objects.
- if (Looper.myLooper() == null) {
- Looper.prepare();
+ Result lastResult = SUCCESS.createResult();
+ RenderSessionImpl scene = new RenderSessionImpl(params);
+ try {
+ prepareThread();
+ lastResult = scene.init(params.getTimeout());
+ if (lastResult.isSuccess()) {
+ lastResult = scene.inflate();
+ if (lastResult.isSuccess()) {
+ lastResult = scene.render(true /*freshRender*/);
+ }
+ }
+ } finally {
+ scene.release();
+ cleanupThread();
}
- BridgeXmlBlockParser parser = new BridgeXmlBlockParser(layoutDescription,
- context, false /* platformResourceFlag */);
-
- ViewGroup root = new FrameLayout(context);
-
- View view = inflater.inflate(parser, root);
-
- // post-inflate process. For now this supports TabHost/TabWidget
- postInflateProcess(view, customViewLoader);
-
- // set the AttachInfo on the root view.
- AttachInfo info = new AttachInfo(new WindowSession(), new Window(),
- new Handler(), null);
- info.mHasWindowFocus = true;
- info.mWindowVisibility = View.VISIBLE;
- info.mInTouchMode = false; // this is so that we can display selections.
- root.dispatchAttachedToWindow(info, 0);
-
- // get the background drawable
- if (windowBackground != null) {
- Drawable d = ResourceHelper.getDrawable(windowBackground,
- context, true /* isFramework */);
- root.setBackgroundDrawable(d);
+ return new BridgeRenderSession(scene, lastResult);
+ } catch (Throwable t) {
+ // get the real cause of the exception.
+ Throwable t2 = t;
+ while (t2.getCause() != null) {
+ t2 = t.getCause();
}
+ return new BridgeRenderSession(null,
+ ERROR_UNKNOWN.createResult(t2.getMessage(), t));
+ }
+ }
- // measure the views
- int w_spec, h_spec;
-
- if (renderFullSize) {
- // measure the full size needed by the layout.
- w_spec = MeasureSpec.makeMeasureSpec(screenWidth,
- MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
- h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
- MeasureSpec.UNSPECIFIED); // this lets us know the actual needed size
- view.measure(w_spec, h_spec);
-
- int neededWidth = root.getChildAt(0).getMeasuredWidth();
- if (neededWidth > screenWidth) {
- screenWidth = neededWidth;
- }
-
- int neededHeight = root.getChildAt(0).getMeasuredHeight();
- if (neededHeight > screenHeight - screenOffset) {
- screenHeight = neededHeight + screenOffset;
+ @Override
+ public Result renderDrawable(DrawableParams params) {
+ try {
+ Result lastResult = SUCCESS.createResult();
+ RenderDrawable action = new RenderDrawable(params);
+ try {
+ prepareThread();
+ lastResult = action.init(params.getTimeout());
+ if (lastResult.isSuccess()) {
+ lastResult = action.render();
}
+ } finally {
+ action.release();
+ cleanupThread();
}
- // remeasure with only the size we need
- // This must always be done before the call to layout
- w_spec = MeasureSpec.makeMeasureSpec(screenWidth, MeasureSpec.EXACTLY);
- h_spec = MeasureSpec.makeMeasureSpec(screenHeight - screenOffset,
- MeasureSpec.EXACTLY);
- view.measure(w_spec, h_spec);
-
- // now do the layout.
- view.layout(0, screenOffset, screenWidth, screenHeight);
-
- // draw the views
- Canvas canvas = new Canvas(screenWidth, screenHeight - screenOffset, logger);
-
- root.draw(canvas);
- canvas.dispose();
-
- return new LayoutResult(visit(((ViewGroup)view).getChildAt(0), context),
- canvas.getImage());
- } catch (PostInflateException e) {
- return new LayoutResult(ILayoutResult.ERROR, "Error during post inflation process:\n"
- + e.getMessage());
- } catch (Throwable e) {
+ return lastResult;
+ } catch (Throwable t) {
// get the real cause of the exception.
- Throwable t = e;
- while (t.getCause() != null) {
- t = t.getCause();
- }
-
- // log it
- logger.error(t);
-
- // then return with an ERROR status and the message from the real exception
- return new LayoutResult(ILayoutResult.ERROR,
- t.getClass().getSimpleName() + ": " + t.getMessage());
- } finally {
- // Make sure to remove static references, otherwise we could not unload the lib
- BridgeResources.clearSystem();
- BridgeAssetManager.clearSystem();
-
- // Remove the global logger
- synchronized (sDefaultLogger) {
- sLogger = sDefaultLogger;
+ Throwable t2 = t;
+ while (t2.getCause() != null) {
+ t2 = t.getCause();
}
+ return ERROR_UNKNOWN.createResult(t2.getMessage(), t);
}
}
- /*
- * (non-Javadoc)
- * @see com.android.layoutlib.api.ILayoutLibBridge#clearCaches(java.lang.Object)
- */
+ @Override
public void clearCaches(Object projectKey) {
if (projectKey != null) {
sProjectBitmapCache.remove(projectKey);
@@ -495,390 +368,104 @@ public final class Bridge implements ILayoutBridge {
}
/**
- * Returns details of a framework resource from its integer value.
- * @param value the integer value
- * @return an array of 2 strings containing the resource name and type, or null if the id
- * does not match any resource.
+ * Returns the lock for the bridge
*/
- public static String[] resolveResourceValue(int value) {
- return sRMap.get(value);
-
+ public static ReentrantLock getLock() {
+ return sLock;
}
/**
- * Returns the name of a framework resource whose value is an int array.
- * @param array
+ * Prepares the current thread for rendering.
+ *
+ * Note that while this can be called several time, the first call to {@link #cleanupThread()}
+ * will do the clean-up, and make the thread unable to do further scene actions.
*/
- public static String resolveResourceValue(int[] array) {
- return sRArrayMap.get(array);
+ public static void prepareThread() {
+ // we need to make sure the Looper has been initialized for this thread.
+ // this is required for View that creates Handler objects.
+ if (Looper.myLooper() == null) {
+ Looper.prepare();
+ }
}
/**
- * Returns the integer id of a framework resource, from a given resource type and resource name.
- * @param type the type of the resource
- * @param name the name of the resource.
- * @return an {@link Integer} containing the resource id, or null if no resource were found.
+ * Cleans up thread-specific data. After this, the thread cannot be used for scene actions.
+ * <p>
+ * Note that it doesn't matter how many times {@link #prepareThread()} was called, a single
+ * call to this will prevent the thread from doing further scene actions
*/
- public static Integer getResourceValue(String type, String name) {
- Map<String, Integer> map = sRFullMap.get(type);
- if (map != null) {
- return map.get(name);
- }
-
- return null;
+ public static void cleanupThread() {
+ // clean up the looper
+ Looper.sThreadLocal.remove();
}
- static Map<String, Integer> getEnumValues(String attributeName) {
- if (sEnumValueMap != null) {
- return sEnumValueMap.get(attributeName);
- }
-
- return null;
+ public static LayoutLog getLog() {
+ return sCurrentLog;
}
- /**
- * Visits a View and its children and generate a {@link ILayoutViewInfo} containing the
- * bounds of all the views.
- * @param view the root View
- * @param context the context.
- */
- private ILayoutViewInfo visit(View view, BridgeContext context) {
- if (view == null) {
- return null;
+ public static void setLog(LayoutLog log) {
+ // check only the thread currently owning the lock can do this.
+ if (sLock.isHeldByCurrentThread() == false) {
+ throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
}
- LayoutViewInfo result = new LayoutViewInfo(view.getClass().getName(),
- context.getViewKey(view),
- view.getLeft(), view.getTop(), view.getRight(), view.getBottom());
-
- if (view instanceof ViewGroup) {
- ViewGroup group = ((ViewGroup) view);
- int n = group.getChildCount();
- ILayoutViewInfo[] children = new ILayoutViewInfo[n];
- for (int i = 0; i < group.getChildCount(); i++) {
- children[i] = visit(group.getChildAt(i), context);
- }
- result.setChildren(children);
+ if (log != null) {
+ sCurrentLog = log;
+ } else {
+ sCurrentLog = sDefaultLog;
}
-
- return result;
}
/**
- * Compute style information from the given list of style for the project and framework.
- * @param themeName the name of the current theme. In order to differentiate project and
- * platform themes sharing the same name, all project themes must be prepended with
- * a '*' character.
- * @param isProjectTheme Is this a project theme
- * @param inProjectStyleMap the project style map
- * @param inFrameworkStyleMap the framework style map
- * @param outInheritanceMap the map of style inheritance. This is filled by the method
- * @return the {@link IStyleResourceValue} matching <var>themeName</var>
+ * Returns details of a framework resource from its integer value.
+ * @param value the integer value
+ * @return a Pair containing the resource type and name, or null if the id
+ * does not match any resource.
*/
- private IStyleResourceValue computeStyleMaps(
- String themeName, boolean isProjectTheme, Map<String,
- IResourceValue> inProjectStyleMap, Map<String, IResourceValue> inFrameworkStyleMap,
- Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) {
-
- if (inProjectStyleMap != null && inFrameworkStyleMap != null) {
- // first, get the theme
- IResourceValue theme = null;
-
- // project theme names have been prepended with a *
- if (isProjectTheme) {
- theme = inProjectStyleMap.get(themeName);
- } else {
- theme = inFrameworkStyleMap.get(themeName);
- }
-
- if (theme instanceof IStyleResourceValue) {
- // compute the inheritance map for both the project and framework styles
- computeStyleInheritance(inProjectStyleMap.values(), inProjectStyleMap,
- inFrameworkStyleMap, outInheritanceMap);
-
- // Compute the style inheritance for the framework styles/themes.
- // Since, for those, the style parent values do not contain 'android:'
- // we want to force looking in the framework style only to avoid using
- // similarly named styles from the project.
- // To do this, we pass null in lieu of the project style map.
- computeStyleInheritance(inFrameworkStyleMap.values(), null /*inProjectStyleMap */,
- inFrameworkStyleMap, outInheritanceMap);
-
- return (IStyleResourceValue)theme;
- }
- }
-
- return null;
+ public static Pair<ResourceType, String> resolveResourceId(int value) {
+ return sRMap.get(value);
}
/**
- * Compute the parent style for all the styles in a given list.
- * @param styles the styles for which we compute the parent.
- * @param inProjectStyleMap the map of project styles.
- * @param inFrameworkStyleMap the map of framework styles.
- * @param outInheritanceMap the map of style inheritance. This is filled by the method.
+ * Returns the name of a framework resource whose value is an int array.
+ * @param array
*/
- private void computeStyleInheritance(Collection<IResourceValue> styles,
- Map<String, IResourceValue> inProjectStyleMap,
- Map<String, IResourceValue> inFrameworkStyleMap,
- Map<IStyleResourceValue, IStyleResourceValue> outInheritanceMap) {
- for (IResourceValue value : styles) {
- if (value instanceof IStyleResourceValue) {
- IStyleResourceValue style = (IStyleResourceValue)value;
- IStyleResourceValue parentStyle = null;
-
- // first look for a specified parent.
- String parentName = style.getParentStyle();
-
- // no specified parent? try to infer it from the name of the style.
- if (parentName == null) {
- parentName = getParentName(value.getName());
- }
-
- if (parentName != null) {
- parentStyle = getStyle(parentName, inProjectStyleMap, inFrameworkStyleMap);
-
- if (parentStyle != null) {
- outInheritanceMap.put(style, parentStyle);
- }
- }
- }
- }
+ public static String resolveResourceId(int[] array) {
+ sIntArrayWrapper.set(array);
+ return sRArrayMap.get(sIntArrayWrapper);
}
/**
- * Searches for and returns the {@link IStyleResourceValue} from a given name.
- * <p/>The format of the name can be:
- * <ul>
- * <li>[android:]&lt;name&gt;</li>
- * <li>[android:]style/&lt;name&gt;</li>
- * <li>@[android:]style/&lt;name&gt;</li>
- * </ul>
- * @param parentName the name of the style.
- * @param inProjectStyleMap the project style map. Can be <code>null</code>
- * @param inFrameworkStyleMap the framework style map.
- * @return The matching {@link IStyleResourceValue} object or <code>null</code> if not found.
+ * Returns the integer id of a framework resource, from a given resource type and resource name.
+ * @param type the type of the resource
+ * @param name the name of the resource.
+ * @return an {@link Integer} containing the resource id, or null if no resource were found.
*/
- private IStyleResourceValue getStyle(String parentName,
- Map<String, IResourceValue> inProjectStyleMap,
- Map<String, IResourceValue> inFrameworkStyleMap) {
- boolean frameworkOnly = false;
-
- String name = parentName;
-
- // remove the useless @ if it's there
- if (name.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
- name = name.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
- }
-
- // check for framework identifier.
- if (name.startsWith(BridgeConstants.PREFIX_ANDROID)) {
- frameworkOnly = true;
- name = name.substring(BridgeConstants.PREFIX_ANDROID.length());
- }
-
- // at this point we could have the format <type>/<name>. we want only the name as long as
- // the type is style.
- if (name.startsWith(BridgeConstants.REFERENCE_STYLE)) {
- name = name.substring(BridgeConstants.REFERENCE_STYLE.length());
- } else if (name.indexOf('/') != -1) {
- return null;
- }
-
- IResourceValue parent = null;
-
- // if allowed, search in the project resources.
- if (frameworkOnly == false && inProjectStyleMap != null) {
- parent = inProjectStyleMap.get(name);
- }
-
- // if not found, then look in the framework resources.
- if (parent == null) {
- parent = inFrameworkStyleMap.get(name);
- }
-
- // make sure the result is the proper class type and return it.
- if (parent instanceof IStyleResourceValue) {
- return (IStyleResourceValue)parent;
+ public static Integer getResourceId(ResourceType type, String name) {
+ Map<String, Integer> map = sRFullMap.get(type);
+ if (map != null) {
+ return map.get(name);
}
- sLogger.error(String.format("Unable to resolve parent style name: %s", parentName));
-
return null;
}
/**
- * Computes the name of the parent style, or <code>null</code> if the style is a root style.
+ * Returns the list of possible enums for a given attribute name.
*/
- private String getParentName(String styleName) {
- int index = styleName.lastIndexOf('.');
- if (index != -1) {
- return styleName.substring(0, index);
+ public static Map<String, Integer> getEnumValues(String attributeName) {
+ if (sEnumValueMap != null) {
+ return sEnumValueMap.get(attributeName);
}
return null;
}
/**
- * Returns the top screen offset. This depends on whether the current theme defines the user
- * of the title and status bars.
- * @param frameworkResources The framework resources
- * @param currentTheme The current theme
- * @param context The context
- * @return the pixel height offset
- */
- private int getScreenOffset(Map<String, Map<String, IResourceValue>> frameworkResources,
- IStyleResourceValue currentTheme, BridgeContext context) {
- int offset = 0;
-
- // get the title bar flag from the current theme.
- IResourceValue value = context.findItemInStyle(currentTheme, "windowNoTitle");
-
- // because it may reference something else, we resolve it.
- value = context.resolveResValue(value);
-
- // if there's a value and it's true (default is false)
- if (value == null || value.getValue() == null ||
- XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
- // default size of the window title bar
- int defaultOffset = DEFAULT_TITLE_BAR_HEIGHT;
-
- // get value from the theme.
- value = context.findItemInStyle(currentTheme, "windowTitleSize");
-
- // resolve it
- value = context.resolveResValue(value);
-
- if (value != null) {
- // get the numerical value, if available
- TypedValue typedValue = ResourceHelper.getValue(value.getValue());
- if (typedValue != null) {
- // compute the pixel value based on the display metrics
- defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
- }
- }
-
- offset += defaultOffset;
- }
-
- // get the fullscreen flag from the current theme.
- value = context.findItemInStyle(currentTheme, "windowFullscreen");
-
- // because it may reference something else, we resolve it.
- value = context.resolveResValue(value);
-
- if (value == null || value.getValue() == null ||
- XmlUtils.convertValueToBoolean(value.getValue(), false /* defValue */) == false) {
-
- // default value
- int defaultOffset = DEFAULT_STATUS_BAR_HEIGHT;
-
- // get the real value, first the list of Dimensions from the framework map
- Map<String, IResourceValue> dimens = frameworkResources.get(BridgeConstants.RES_DIMEN);
-
- // now get the value
- value = dimens.get("status_bar_height");
- if (value != null) {
- TypedValue typedValue = ResourceHelper.getValue(value.getValue());
- if (typedValue != null) {
- // compute the pixel value based on the display metrics
- defaultOffset = (int)typedValue.getDimension(context.getResources().mMetrics);
- }
- }
-
- // add the computed offset.
- offset += defaultOffset;
- }
-
- return offset;
- }
-
- /**
- * Post process on a view hierachy that was just inflated.
- * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
- * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
- * based on the content of the {@link FrameLayout}.
- * @param view the root view to process.
- * @param projectCallback callback to the project.
+ * Returns the platform build properties.
*/
- private void postInflateProcess(View view, IProjectCallback projectCallback)
- throws PostInflateException {
- if (view instanceof TabHost) {
- setupTabHost((TabHost)view, projectCallback);
- } else if (view instanceof ViewGroup) {
- ViewGroup group = (ViewGroup)view;
- final int count = group.getChildCount();
- for (int c = 0 ; c < count ; c++) {
- View child = group.getChildAt(c);
- postInflateProcess(child, projectCallback);
- }
- }
- }
-
- /**
- * Sets up a {@link TabHost} object.
- * @param tabHost the TabHost to setup.
- * @param projectCallback The project callback object to access the project R class.
- * @throws PostInflateException
- */
- private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
- throws PostInflateException {
- // look for the TabWidget, and the FrameLayout. They have their own specific names
- View v = tabHost.findViewById(android.R.id.tabs);
-
- if (v == null) {
- throw new PostInflateException(
- "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
- }
-
- if ((v instanceof TabWidget) == false) {
- throw new PostInflateException(String.format(
- "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
- "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
- }
-
- v = tabHost.findViewById(android.R.id.tabcontent);
-
- if (v == null) {
- // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
- throw new PostInflateException(
- "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
- }
-
- if ((v instanceof FrameLayout) == false) {
- throw new PostInflateException(String.format(
- "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
- "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
- }
-
- FrameLayout content = (FrameLayout)v;
-
- // now process the content of the framelayout and dynamically create tabs for it.
- final int count = content.getChildCount();
-
- if (count == 0) {
- throw new PostInflateException(
- "The FrameLayout for the TabHost has no content. Rendering failed.\n");
- }
-
- // this must be called before addTab() so that the TabHost searches its TabWidget
- // and FrameLayout.
- tabHost.setup();
-
- // for each child of the framelayout, add a new TabSpec
- for (int i = 0 ; i < count ; i++) {
- View child = content.getChildAt(i);
- String tabSpec = String.format("tab_spec%d", i+1);
- int id = child.getId();
- String[] resource = projectCallback.resolveResourceValue(id);
- String name;
- if (resource != null) {
- name = resource[0]; // 0 is resource name, 1 is resource type.
- } else {
- name = String.format("Tab %d", i+1); // default name if id is unresolved.
- }
- tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
- }
+ public static Map<String, String> getPlatformProperties() {
+ return sPlatformProperties;
}
/**
@@ -888,7 +475,7 @@ public final class Bridge implements ILayoutBridge {
* @param projectKey the key of the project, or null to query the framework cache.
* @return the cached Bitmap or null if not found.
*/
- static Bitmap getCachedBitmap(String value, Object projectKey) {
+ public static Bitmap getCachedBitmap(String value, Object projectKey) {
if (projectKey != null) {
Map<String, SoftReference<Bitmap>> map = sProjectBitmapCache.get(projectKey);
if (map != null) {
@@ -913,7 +500,7 @@ public final class Bridge implements ILayoutBridge {
* @param bmp the Bitmap object
* @param projectKey the key of the project, or null to put the bitmap in the framework cache.
*/
- static void setCachedBitmap(String value, Bitmap bmp, Object projectKey) {
+ public static void setCachedBitmap(String value, Bitmap bmp, Object projectKey) {
if (projectKey != null) {
Map<String, SoftReference<Bitmap>> map = sProjectBitmapCache.get(projectKey);
@@ -929,24 +516,24 @@ public final class Bridge implements ILayoutBridge {
}
/**
- * Returns the 9 patch for a specific path, from a specific project cache, or from the
+ * Returns the 9 patch chunk for a specific path, from a specific project cache, or from the
* framework cache.
* @param value the path of the 9 patch
* @param projectKey the key of the project, or null to query the framework cache.
* @return the cached 9 patch or null if not found.
*/
- static NinePatch getCached9Patch(String value, Object projectKey) {
+ public static NinePatchChunk getCached9Patch(String value, Object projectKey) {
if (projectKey != null) {
- Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey);
+ Map<String, SoftReference<NinePatchChunk>> map = sProject9PatchCache.get(projectKey);
if (map != null) {
- SoftReference<NinePatch> ref = map.get(value);
+ SoftReference<NinePatchChunk> ref = map.get(value);
if (ref != null) {
return ref.get();
}
}
} else {
- SoftReference<NinePatch> ref = sFramework9PatchCache.get(value);
+ SoftReference<NinePatchChunk> ref = sFramework9PatchCache.get(value);
if (ref != null) {
return ref.get();
}
@@ -956,224 +543,25 @@ public final class Bridge implements ILayoutBridge {
}
/**
- * Sets a 9 patch in a project cache or in the framework cache.
+ * Sets a 9 patch chunk in a project cache or in the framework cache.
* @param value the path of the 9 patch
* @param ninePatch the 9 patch object
* @param projectKey the key of the project, or null to put the bitmap in the framework cache.
*/
- static void setCached9Patch(String value, NinePatch ninePatch, Object projectKey) {
+ public static void setCached9Patch(String value, NinePatchChunk ninePatch, Object projectKey) {
if (projectKey != null) {
- Map<String, SoftReference<NinePatch>> map = sProject9PatchCache.get(projectKey);
+ Map<String, SoftReference<NinePatchChunk>> map = sProject9PatchCache.get(projectKey);
if (map == null) {
- map = new HashMap<String, SoftReference<NinePatch>>();
+ map = new HashMap<String, SoftReference<NinePatchChunk>>();
sProject9PatchCache.put(projectKey, map);
}
- map.put(value, new SoftReference<NinePatch>(ninePatch));
+ map.put(value, new SoftReference<NinePatchChunk>(ninePatch));
} else {
- sFramework9PatchCache.put(value, new SoftReference<NinePatch>(ninePatch));
+ sFramework9PatchCache.put(value, new SoftReference<NinePatchChunk>(ninePatch));
}
}
- private static final class PostInflateException extends Exception {
- private static final long serialVersionUID = 1L;
-
- public PostInflateException(String message) {
- super(message);
- }
- }
-
- /**
- * Implementation of {@link IWindowSession} so that mSession is not null in
- * the {@link SurfaceView}.
- */
- private static final class WindowSession implements IWindowSession {
-
- @SuppressWarnings("unused")
- public int add(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3,
- InputChannel outInputchannel)
- throws RemoteException {
- // pass for now.
- return 0;
- }
-
- @SuppressWarnings("unused")
- public int addWithoutInputChannel(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3)
- throws RemoteException {
- // pass for now.
- return 0;
- }
-
- @SuppressWarnings("unused")
- public void finishDrawing(IWindow arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void finishKey(IWindow arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public boolean getInTouchMode() throws RemoteException {
- // pass for now.
- return false;
- }
-
- @SuppressWarnings("unused")
- public boolean performHapticFeedback(IWindow window, int effectId, boolean always) {
- // pass for now.
- return false;
- }
-
- @SuppressWarnings("unused")
- public MotionEvent getPendingPointerMove(IWindow arg0) throws RemoteException {
- // pass for now.
- return null;
- }
-
- @SuppressWarnings("unused")
- public MotionEvent getPendingTrackballMove(IWindow arg0) throws RemoteException {
- // pass for now.
- return null;
- }
-
- @SuppressWarnings("unused")
- public int relayout(IWindow arg0, LayoutParams arg1, int arg2, int arg3, int arg4,
- boolean arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
- throws RemoteException {
- // pass for now.
- return 0;
- }
-
- public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void remove(IWindow arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void setInTouchMode(boolean arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void setTransparentRegion(IWindow arg0, Region arg1) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void setInsets(IWindow window, int touchable, Rect contentInsets,
- Rect visibleInsets) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void setWallpaperPosition(IBinder window, float x, float y,
- float xStep, float yStep) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void wallpaperOffsetsComplete(IBinder window) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
- int z, Bundle extras, boolean sync) {
- // pass for now.
- return null;
- }
-
- @SuppressWarnings("unused")
- public void wallpaperCommandComplete(IBinder window, Bundle result) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void closeSystemDialogs(String reason) {
- // pass for now.
- }
-
- public IBinder asBinder() {
- // pass for now.
- return null;
- }
- }
-
- /**
- * Implementation of {@link IWindow} to pass to the {@link AttachInfo}.
- */
- private static final class Window implements IWindow {
-
- @SuppressWarnings("unused")
- public void dispatchAppVisibility(boolean arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchGetNewSurface() throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchKey(KeyEvent arg0) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void executeCommand(String arg0, String arg1, ParcelFileDescriptor arg2)
- throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5)
- throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
- boolean sync) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void dispatchWallpaperCommand(String action, int x, int y,
- int z, Bundle extras, boolean sync) {
- // pass for now.
- }
-
- @SuppressWarnings("unused")
- public void closeSystemDialogs(String reason) {
- // pass for now.
- }
-
- public IBinder asBinder() {
- // pass for now.
- return null;
- }
- }
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
index 791e53b..112af1e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeConstants.java
@@ -41,24 +41,6 @@ public class BridgeConstants {
public final static String R = "com.android.internal.R";
- public final static String PREFIX_ANDROID_RESOURCE_REF = "@android:";
- public final static String PREFIX_RESOURCE_REF = "@";
- public final static String PREFIX_ANDROID_THEME_REF = "?android:";
- public final static String PREFIX_THEME_REF = "?";
-
- public final static String PREFIX_ANDROID = "android:";
-
- public final static String RES_STYLE = "style";
- public final static String RES_ATTR = "attr";
- public final static String RES_DIMEN = "dimen";
- public final static String RES_DRAWABLE = "drawable";
- public final static String RES_COLOR = "color";
- public final static String RES_LAYOUT = "layout";
- public final static String RES_STRING = "string";
- public final static String RES_ID = "id";
-
- public final static String REFERENCE_STYLE = RES_STYLE + "/";
- public final static String REFERENCE_NULL = "@null";
public final static String MATCH_PARENT = "match_parent";
public final static String FILL_PARENT = "fill_parent";
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java
deleted file mode 100644
index 20ccc0b..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContentResolver.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.layoutlib.bridge;
-
-import android.content.ContentProviderOperation;
-import android.content.ContentProviderResult;
-import android.content.ContentResolver;
-import android.content.ContentValues;
-import android.content.Context;
-import android.content.IContentProvider;
-import android.content.OperationApplicationException;
-import android.content.res.AssetFileDescriptor;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.CursorWindow;
-import android.database.IBulkCursor;
-import android.database.IContentObserver;
-import android.net.Uri;
-import android.os.Bundle;
-import android.os.IBinder;
-import android.os.ParcelFileDescriptor;
-import android.os.RemoteException;
-
-import java.io.FileNotFoundException;
-import java.util.ArrayList;
-
-/**
- * A mock content resolver for the LayoutLib Bridge.
- * <p/>
- * It won't serve any actual data but it's good enough for all
- * the widgets which expect to have a content resolver available via
- * {@link BridgeContext#getContentResolver()}.
- */
-public class BridgeContentResolver extends ContentResolver {
-
- private BridgeContentProvider mProvider = null;
-
- public static final class BridgeContentProvider implements IContentProvider {
-
- public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> arg0)
- throws RemoteException, OperationApplicationException {
- // TODO Auto-generated method stub
- return null;
- }
-
- public int bulkInsert(Uri arg0, ContentValues[] arg1) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- public IBulkCursor bulkQuery(Uri arg0, String[] arg1, String arg2, String[] arg3,
- String arg4, IContentObserver arg5, CursorWindow arg6) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- public Bundle call(String arg0, String arg1, Bundle arg2) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- public int delete(Uri arg0, String arg1, String[] arg2) throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- public String getType(Uri arg0) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- public Uri insert(Uri arg0, ContentValues arg1) throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- public AssetFileDescriptor openAssetFile(Uri arg0, String arg1) throws RemoteException,
- FileNotFoundException {
- // TODO Auto-generated method stub
- return null;
- }
-
- public ParcelFileDescriptor openFile(Uri arg0, String arg1) throws RemoteException,
- FileNotFoundException {
- // TODO Auto-generated method stub
- return null;
- }
-
- public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4)
- throws RemoteException {
- // TODO Auto-generated method stub
- return null;
- }
-
- public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3)
- throws RemoteException {
- // TODO Auto-generated method stub
- return 0;
- }
-
- public IBinder asBinder() {
- // TODO Auto-generated method stub
- return null;
- }
-
- }
-
- public BridgeContentResolver(Context context) {
- super(context);
- }
-
- @Override
- public IContentProvider acquireProvider(Context c, String name) {
- if (mProvider == null) {
- mProvider = new BridgeContentProvider();
- }
-
- return mProvider;
- }
-
- @Override
- public IContentProvider acquireExistingProvider(Context c, String name) {
- if (mProvider == null) {
- mProvider = new BridgeContentProvider();
- }
-
- return mProvider;
- }
-
- @Override
- public boolean releaseProvider(IContentProvider icp) {
- // ignore
- return false;
- }
-
- /**
- * Stub for the layoutlib bridge content resolver.
- */
- @Override
- public void registerContentObserver(Uri uri, boolean notifyForDescendents,
- ContentObserver observer) {
- // pass
- }
-
- /**
- * Stub for the layoutlib bridge content resolver.
- */
- @Override
- public void unregisterContentObserver(ContentObserver observer) {
- // pass
- }
-
- /**
- * Stub for the layoutlib bridge content resolver.
- */
- @Override
- public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
- // pass
- }
-
- /**
- * Stub for the layoutlib bridge content resolver.
- */
- @Override
- public void startSync(Uri uri, Bundle extras) {
- // pass
- }
-
- /**
- * Stub for the layoutlib bridge content resolver.
- */
- @Override
- public void cancelSync(Uri uri) {
- // pass
- }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
new file mode 100644
index 0000000..bf22c4d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge;
+
+import com.android.ide.common.rendering.api.IAnimationListener;
+import com.android.ide.common.rendering.api.ILayoutPullParser;
+import com.android.ide.common.rendering.api.RenderParams;
+import com.android.ide.common.rendering.api.RenderSession;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.ViewInfo;
+import com.android.ide.common.rendering.api.Result.Status;
+import com.android.layoutlib.bridge.impl.RenderSessionImpl;
+
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewParent;
+
+import java.awt.image.BufferedImage;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * An implementation of {@link RenderSession}.
+ *
+ * This is a pretty basic class that does almost nothing. All of the work is done in
+ * {@link RenderSessionImpl}.
+ *
+ */
+public class BridgeRenderSession extends RenderSession {
+
+ private final RenderSessionImpl mSession;
+ private Result mLastResult;
+
+ @Override
+ public Result getResult() {
+ return mLastResult;
+ }
+
+ @Override
+ public BufferedImage getImage() {
+ return mSession.getImage();
+ }
+
+ @Override
+ public boolean isAlphaChannelImage() {
+ return mSession.isAlphaChannelImage();
+ }
+
+ @Override
+ public List<ViewInfo> getRootViews() {
+ return mSession.getViewInfos();
+ }
+
+ @Override
+ public Map<String, String> getDefaultProperties(Object viewObject) {
+ return mSession.getDefaultProperties(viewObject);
+ }
+
+ @Override
+ public Result getProperty(Object objectView, String propertyName) {
+ // TODO Auto-generated method stub
+ return super.getProperty(objectView, propertyName);
+ }
+
+ @Override
+ public Result setProperty(Object objectView, String propertyName, String propertyValue) {
+ // TODO Auto-generated method stub
+ return super.setProperty(objectView, propertyName, propertyValue);
+ }
+
+ @Override
+ public Result getViewParent(Object viewObject) {
+ if (viewObject instanceof View) {
+ return Status.SUCCESS.createResult(((View)viewObject).getParent());
+ }
+
+ throw new IllegalArgumentException("viewObject is not a View");
+ }
+
+ @Override
+ public Result getViewIndex(Object viewObject) {
+ if (viewObject instanceof View) {
+ View view = (View) viewObject;
+ ViewParent parentView = view.getParent();
+
+ if (parentView instanceof ViewGroup) {
+ Status.SUCCESS.createResult(((ViewGroup) parentView).indexOfChild(view));
+ }
+
+ return Status.SUCCESS.createResult();
+ }
+
+ throw new IllegalArgumentException("viewObject is not a View");
+ }
+
+ @Override
+ public Result render(long timeout) {
+ try {
+ Bridge.prepareThread();
+ mLastResult = mSession.acquire(timeout);
+ if (mLastResult.isSuccess()) {
+ mLastResult = mSession.render(false /*freshRender*/);
+ }
+ } finally {
+ mSession.release();
+ Bridge.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+
+ @Override
+ public Result animate(Object targetObject, String animationName,
+ boolean isFrameworkAnimation, IAnimationListener listener) {
+ // Animation is only supported in API 11+
+ return super.animate(targetObject, animationName, isFrameworkAnimation, listener);
+ }
+
+ @Override
+ public Result insertChild(Object parentView, ILayoutPullParser childXml, int index,
+ IAnimationListener listener) {
+ if (parentView instanceof ViewGroup == false) {
+ throw new IllegalArgumentException("parentView is not a ViewGroup");
+ }
+
+ try {
+ Bridge.prepareThread();
+ mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+ if (mLastResult.isSuccess()) {
+ mLastResult = mSession.insertChild((ViewGroup) parentView, childXml, index,
+ listener);
+ }
+ } finally {
+ mSession.release();
+ Bridge.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+
+
+ @Override
+ public Result moveChild(Object parentView, Object childView, int index,
+ Map<String, String> layoutParams, IAnimationListener listener) {
+ if (parentView instanceof ViewGroup == false) {
+ throw new IllegalArgumentException("parentView is not a ViewGroup");
+ }
+ if (childView instanceof View == false) {
+ throw new IllegalArgumentException("childView is not a View");
+ }
+
+ try {
+ Bridge.prepareThread();
+ mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+ if (mLastResult.isSuccess()) {
+ mLastResult = mSession.moveChild((ViewGroup) parentView, (View) childView, index,
+ layoutParams, listener);
+ }
+ } finally {
+ mSession.release();
+ Bridge.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+
+ @Override
+ public Result removeChild(Object childView, IAnimationListener listener) {
+ if (childView instanceof View == false) {
+ throw new IllegalArgumentException("childView is not a View");
+ }
+
+ try {
+ Bridge.prepareThread();
+ mLastResult = mSession.acquire(RenderParams.DEFAULT_TIMEOUT);
+ if (mLastResult.isSuccess()) {
+ mLastResult = mSession.removeChild((View) childView, listener);
+ }
+ } finally {
+ mSession.release();
+ Bridge.cleanupThread();
+ }
+
+ return mLastResult;
+ }
+
+ @Override
+ public void dispose() {
+ }
+
+ /*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
+ mSession = scene;
+ if (scene != null) {
+ mSession.setScene(this);
+ }
+ mLastResult = lastResult;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/LayoutResult.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/LayoutResult.java
deleted file mode 100644
index c4c5225..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/LayoutResult.java
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge;
-
-import com.android.layoutlib.api.ILayoutResult;
-
-import java.awt.image.BufferedImage;
-
-/**
- * Implementation of {@link ILayoutResult}
- */
-public final class LayoutResult implements ILayoutResult {
-
- private final ILayoutViewInfo mRootView;
- private final BufferedImage mImage;
- private final int mSuccess;
- private final String mErrorMessage;
-
- /**
- * Creates a {@link #SUCCESS} {@link ILayoutResult} with the specified params
- * @param rootView
- * @param image
- */
- public LayoutResult(ILayoutViewInfo rootView, BufferedImage image) {
- mSuccess = SUCCESS;
- mErrorMessage = null;
- mRootView = rootView;
- mImage = image;
- }
-
- /**
- * Creates a LayoutResult with a specific success code and associated message
- * @param code
- * @param message
- */
- public LayoutResult(int code, String message) {
- mSuccess = code;
- mErrorMessage = message;
- mRootView = null;
- mImage = null;
- }
-
- public int getSuccess() {
- return mSuccess;
- }
-
- public String getErrorMessage() {
- return mErrorMessage;
- }
-
- public BufferedImage getImage() {
- return mImage;
- }
-
- public ILayoutViewInfo getRootView() {
- return mRootView;
- }
-
- /**
- * Implementation of {@link ILayoutResult.ILayoutViewInfo}
- */
- public static final class LayoutViewInfo implements ILayoutViewInfo {
- private final Object mKey;
- private final String mName;
- private final int mLeft;
- private final int mRight;
- private final int mTop;
- private final int mBottom;
- private ILayoutViewInfo[] mChildren;
-
- public LayoutViewInfo(String name, Object key, int left, int top, int right, int bottom) {
- mName = name;
- mKey = key;
- mLeft = left;
- mRight = right;
- mTop = top;
- mBottom = bottom;
- }
-
- public void setChildren(ILayoutViewInfo[] children) {
- mChildren = children;
- }
-
- public ILayoutViewInfo[] getChildren() {
- return mChildren;
- }
-
- public Object getViewKey() {
- return mKey;
- }
-
- public String getName() {
- return mName;
- }
-
- public int getLeft() {
- return mLeft;
- }
-
- public int getTop() {
- return mTop;
- }
-
- public int getRight() {
- return mRight;
- }
-
- public int getBottom() {
- return mBottom;
- }
- }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
deleted file mode 100644
index abbf2f0..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/NinePatchDrawable.java
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge;
-
-import com.android.ninepatch.NinePatch;
-
-import android.graphics.Canvas;
-import android.graphics.ColorFilter;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-
-public class NinePatchDrawable extends Drawable {
-
- private NinePatch m9Patch;
-
- NinePatchDrawable(NinePatch ninePatch) {
- m9Patch = ninePatch;
- }
-
- @Override
- public int getMinimumWidth() {
- return m9Patch.getWidth();
- }
-
- @Override
- public int getMinimumHeight() {
- return m9Patch.getHeight();
- }
-
- /**
- * Return the intrinsic width of the underlying drawable object. Returns
- * -1 if it has no intrinsic width, such as with a solid color.
- */
- @Override
- public int getIntrinsicWidth() {
- return m9Patch.getWidth();
- }
-
- /**
- * Return the intrinsic height of the underlying drawable object. Returns
- * -1 if it has no intrinsic height, such as with a solid color.
- */
- @Override
- public int getIntrinsicHeight() {
- return m9Patch.getHeight();
- }
-
- /**
- * Return in padding the insets suggested by this Drawable for placing
- * content inside the drawable's bounds. Positive values move toward the
- * center of the Drawable (set Rect.inset). Returns true if this drawable
- * actually has a padding, else false. When false is returned, the padding
- * is always set to 0.
- */
- @Override
- public boolean getPadding(Rect padding) {
- int[] padd = new int[4];
- m9Patch.getPadding(padd);
- padding.left = padd[0];
- padding.top = padd[1];
- padding.right = padd[2];
- padding.bottom = padd[3];
- return true;
- }
-
- @Override
- public void draw(Canvas canvas) {
- Rect r = getBounds();
- m9Patch.draw(canvas.getGraphics2d(), r.left, r.top, r.width(), r.height());
-
- return;
- }
-
-
- // ----------- Not implemented methods ---------------
-
-
- @Override
- public int getOpacity() {
- // FIXME
- return 0xFF;
- }
-
- @Override
- public void setAlpha(int arg0) {
- // FIXME !
- }
-
- @Override
- public void setColorFilter(ColorFilter arg0) {
- // FIXME
- }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceValue.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceValue.java
deleted file mode 100644
index 01a4871..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceValue.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge;
-
-import com.android.layoutlib.api.IResourceValue;
-
-/**
- * Basic implementation of IResourceValue.
- */
-class ResourceValue implements IResourceValue {
- private final String mType;
- private final String mName;
- private String mValue = null;
-
- ResourceValue(String name) {
- mType = null;
- mName = name;
- }
-
- public ResourceValue(String type, String name, String value) {
- mType = type;
- mName = name;
- mValue = value;
- }
-
- public String getType() {
- return mType;
- }
-
- public final String getName() {
- return mName;
- }
-
- public final String getValue() {
- return mValue;
- }
-
- public final void setValue(String value) {
- mValue = value;
- }
-
- public void replaceWith(ResourceValue value) {
- mValue = value.mValue;
- }
-
- public boolean isFramework() {
- // ResourceValue object created directly in the framework are used to describe
- // non resolvable coming from the XML. Since they will never be cached (as they can't
- // be a value pointing to a bitmap, or they'd be resolvable.), the return value deoes
- // not matter.
- return false;
- }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeAssetManager.java
index 71803fc..a825060 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeAssetManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeAssetManager.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
+
+import com.android.layoutlib.bridge.Bridge;
import android.content.res.AssetManager;
@@ -28,7 +30,7 @@ public class BridgeAssetManager extends AssetManager {
* <p/>
* {@link Bridge} calls this method after setting up a new bridge.
*/
- /*package*/ static AssetManager initSystem() {
+ /*package*/ public static AssetManager initSystem() {
if (!(AssetManager.sSystem instanceof BridgeAssetManager)) {
// Note that AssetManager() creates a system AssetManager and we override it
// with our BridgeAssetManager.
@@ -42,7 +44,7 @@ public class BridgeAssetManager extends AssetManager {
* Clears the static {@link AssetManager#sSystem} to make sure we don't leave objects
* around that would prevent us from unloading the library.
*/
- /*package*/ static void clearSystem() {
+ public static void clearSystem() {
AssetManager.sSystem = null;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
new file mode 100644
index 0000000..3835378
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentProvider.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.android;
+
+import android.content.ContentProviderOperation;
+import android.content.ContentProviderResult;
+import android.content.ContentValues;
+import android.content.IContentProvider;
+import android.content.OperationApplicationException;
+import android.content.res.AssetFileDescriptor;
+import android.database.Cursor;
+import android.database.CursorWindow;
+import android.database.IBulkCursor;
+import android.database.IContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+
+/**
+ * Mock implementation of {@link IContentProvider}.
+ *
+ * TODO: never return null when the method is not supposed to. Return fake data instead.
+ */
+public final class BridgeContentProvider implements IContentProvider {
+
+ public ContentProviderResult[] applyBatch(ArrayList<ContentProviderOperation> arg0)
+ throws RemoteException, OperationApplicationException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int bulkInsert(Uri arg0, ContentValues[] arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public IBulkCursor bulkQuery(Uri arg0, String[] arg1, String arg2, String[] arg3,
+ String arg4, IContentObserver arg5, CursorWindow arg6) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Bundle call(String arg0, String arg1, Bundle arg2) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int delete(Uri arg0, String arg1, String[] arg2) throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public String getType(Uri arg0) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Uri insert(Uri arg0, ContentValues arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public AssetFileDescriptor openAssetFile(Uri arg0, String arg1) throws RemoteException,
+ FileNotFoundException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public ParcelFileDescriptor openFile(Uri arg0, String arg1) throws RemoteException,
+ FileNotFoundException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public Cursor query(Uri arg0, String[] arg1, String arg2, String[] arg3, String arg4)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public int update(Uri arg0, ContentValues arg1, String arg2, String[] arg3)
+ throws RemoteException {
+ // TODO Auto-generated method stub
+ return 0;
+ }
+
+ public IBinder asBinder() {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public String[] getStreamTypes(Uri arg0, String arg1) throws RemoteException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+ public AssetFileDescriptor openTypedAssetFile(Uri arg0, String arg1, Bundle arg2)
+ throws RemoteException, FileNotFoundException {
+ // TODO Auto-generated method stub
+ return null;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java
new file mode 100644
index 0000000..0257686
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContentResolver.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 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.
+ */
+
+package com.android.layoutlib.bridge.android;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.IContentProvider;
+import android.database.ContentObserver;
+import android.net.Uri;
+import android.os.Bundle;
+
+/**
+ * A mock content resolver for the LayoutLib Bridge.
+ * <p/>
+ * It won't serve any actual data but it's good enough for all
+ * the widgets which expect to have a content resolver available via
+ * {@link BridgeContext#getContentResolver()}.
+ */
+public class BridgeContentResolver extends ContentResolver {
+
+ private BridgeContentProvider mProvider = null;
+
+ public BridgeContentResolver(Context context) {
+ super(context);
+ }
+
+ @Override
+ public IContentProvider acquireProvider(Context c, String name) {
+ if (mProvider == null) {
+ mProvider = new BridgeContentProvider();
+ }
+
+ return mProvider;
+ }
+
+ @Override
+ public IContentProvider acquireExistingProvider(Context c, String name) {
+ if (mProvider == null) {
+ mProvider = new BridgeContentProvider();
+ }
+
+ return mProvider;
+ }
+
+ @Override
+ public boolean releaseProvider(IContentProvider icp) {
+ // ignore
+ return false;
+ }
+
+ /**
+ * Stub for the layoutlib bridge content resolver.
+ */
+ @Override
+ public void registerContentObserver(Uri uri, boolean notifyForDescendents,
+ ContentObserver observer) {
+ // pass
+ }
+
+ /**
+ * Stub for the layoutlib bridge content resolver.
+ */
+ @Override
+ public void unregisterContentObserver(ContentObserver observer) {
+ // pass
+ }
+
+ /**
+ * Stub for the layoutlib bridge content resolver.
+ */
+ @Override
+ public void notifyChange(Uri uri, ContentObserver observer, boolean syncToNetwork) {
+ // pass
+ }
+
+ /**
+ * Stub for the layoutlib bridge content resolver.
+ */
+ @Override
+ public void startSync(Uri uri, Bundle extras) {
+ // pass
+ }
+
+ /**
+ * Stub for the layoutlib bridge content resolver.
+ */
+ @Override
+ public void cancelSync(Uri uri) {
+ // pass
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index ecd22e2..c4eee17 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -14,13 +14,20 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
-
-import com.android.layoutlib.api.ILayoutLog;
-import com.android.layoutlib.api.IProjectCallback;
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IStyleResourceValue;
-
+package com.android.layoutlib.bridge.android;
+
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.Stack;
+import com.android.resources.ResourceType;
+import com.android.util.Pair;
+
+import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -47,7 +54,8 @@ import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
-import android.view.BridgeInflater;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
import android.view.View;
import java.io.File;
@@ -57,81 +65,98 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
+import java.util.IdentityHashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.Map.Entry;
/**
- * Custom implementation of Context to handle non compiled resources.
+ * Custom implementation of Context/Activity to handle non compiled resources.
*/
-public final class BridgeContext extends Context {
+public final class BridgeContext extends Activity {
- private final Resources mResources;
- private final Theme mTheme;
+ private Resources mSystemResources;
private final HashMap<View, Object> mViewKeyMap = new HashMap<View, Object>();
- private final IStyleResourceValue mThemeValues;
private final Object mProjectKey;
- private final Map<String, Map<String, IResourceValue>> mProjectResources;
- private final Map<String, Map<String, IResourceValue>> mFrameworkResources;
- private final Map<IStyleResourceValue, IStyleResourceValue> mStyleInheritanceMap;
+ private final DisplayMetrics mMetrics;
+ private final RenderResources mRenderResources;
+ private final ApplicationInfo mApplicationInfo;
+
+ private final Map<Object, Map<String, String>> mDefaultPropMaps =
+ new IdentityHashMap<Object, Map<String,String>>();
- // maps for dynamically generated id representing style objects (IStyleResourceValue)
- private Map<Integer, IStyleResourceValue> mDynamicIdToStyleMap;
- private Map<IStyleResourceValue, Integer> mStyleToDynamicIdMap;
+ // maps for dynamically generated id representing style objects (StyleResourceValue)
+ private Map<Integer, StyleResourceValue> mDynamicIdToStyleMap;
+ private Map<StyleResourceValue, Integer> mStyleToDynamicIdMap;
private int mDynamicIdGenerator = 0x01030000; // Base id for framework R.style
// cache for TypedArray generated from IStyleResourceValue object
private Map<int[], Map<Integer, TypedArray>> mTypedArrayCache;
- private BridgeInflater mInflater;
+ private BridgeInflater mBridgeInflater;
private final IProjectCallback mProjectCallback;
- private final ILayoutLog mLogger;
private BridgeContentResolver mContentResolver;
+ private final Stack<BridgeXmlBlockParser> mParserStack = new Stack<BridgeXmlBlockParser>();
+
/**
* @param projectKey An Object identifying the project. This is used for the cache mechanism.
* @param metrics the {@link DisplayMetrics}.
* @param themeName The name of the theme to use.
* @param projectResources the resources of the project. The map contains (String, map) pairs
* where the string is the type of the resource reference used in the layout file, and the
- * map contains (String, {@link IResourceValue}) pairs where the key is the resource name,
+ * map contains (String, {@link }) pairs where the key is the resource name,
* and the value is the resource value.
* @param frameworkResources the framework resources. The map contains (String, map) pairs
* where the string is the type of the resource reference used in the layout file, and the map
- * contains (String, {@link IResourceValue}) pairs where the key is the resource name, and the
+ * contains (String, {@link ResourceValue}) pairs where the key is the resource name, and the
* value is the resource value.
* @param styleInheritanceMap
- * @param customViewLoader
+ * @param projectCallback
+ * @param targetSdkVersion the targetSdkVersion of the application.
*/
public BridgeContext(Object projectKey, DisplayMetrics metrics,
- IStyleResourceValue currentTheme,
- Map<String, Map<String, IResourceValue>> projectResources,
- Map<String, Map<String, IResourceValue>> frameworkResources,
- Map<IStyleResourceValue, IStyleResourceValue> styleInheritanceMap,
- IProjectCallback customViewLoader, ILayoutLog logger) {
+ RenderResources renderResources,
+ IProjectCallback projectCallback,
+ int targetSdkVersion) {
mProjectKey = projectKey;
- mProjectCallback = customViewLoader;
- mLogger = logger;
+ mMetrics = metrics;
+ mProjectCallback = projectCallback;
+
+ mRenderResources = renderResources;
+
+ mApplicationInfo = new ApplicationInfo();
+ mApplicationInfo.targetSdkVersion = targetSdkVersion;
+ }
+
+ /**
+ * Initializes the {@link Resources} singleton to be linked to this {@link Context}, its
+ * {@link DisplayMetrics}, {@link Configuration}, and {@link IProjectCallback}.
+ *
+ * @see #disposeResources()
+ */
+ public void initResources() {
+ AssetManager assetManager = AssetManager.getSystem();
Configuration config = new Configuration();
- AssetManager assetManager = BridgeAssetManager.initSystem();
- mResources = BridgeResources.initSystem(
+ mSystemResources = BridgeResources.initSystem(
this,
assetManager,
- metrics,
+ mMetrics,
config,
- customViewLoader);
-
- mTheme = mResources.newTheme();
+ mProjectCallback);
+ mTheme = mSystemResources.newTheme();
+ }
- mThemeValues = currentTheme;
- mProjectResources = projectResources;
- mFrameworkResources = frameworkResources;
- mStyleInheritanceMap = styleInheritanceMap;
+ /**
+ * Disposes the {@link Resources} singleton.
+ */
+ public void disposeResources() {
+ BridgeResources.disposeSystem();
}
public void setBridgeInflater(BridgeInflater inflater) {
- mInflater = inflater;
+ mBridgeInflater = inflater;
}
public void addViewKey(View view, Object viewKey) {
@@ -146,19 +171,112 @@ public final class BridgeContext extends Context {
return mProjectKey;
}
+ public DisplayMetrics getMetrics() {
+ return mMetrics;
+ }
+
public IProjectCallback getProjectCallback() {
return mProjectCallback;
}
- public ILayoutLog getLogger() {
- return mLogger;
+ public RenderResources getRenderResources() {
+ return mRenderResources;
+ }
+
+ public Map<String, String> getDefaultPropMap(Object key) {
+ return mDefaultPropMaps.get(key);
+ }
+
+ /**
+ * Adds a parser to the stack.
+ * @param parser the parser to add.
+ */
+ public void pushParser(BridgeXmlBlockParser parser) {
+ mParserStack.push(parser);
+ }
+
+ /**
+ * Removes the parser at the top of the stack
+ */
+ public void popParser() {
+ mParserStack.pop();
+ }
+
+ /**
+ * Returns the current parser at the top the of the stack.
+ * @return a parser or null.
+ */
+ public BridgeXmlBlockParser getCurrentParser() {
+ return mParserStack.peek();
+ }
+
+ /**
+ * Returns the previous parser.
+ * @return a parser or null if there isn't any previous parser
+ */
+ public BridgeXmlBlockParser getPreviousParser() {
+ if (mParserStack.size() < 2) {
+ return null;
+ }
+ return mParserStack.get(mParserStack.size() - 2);
+ }
+
+ public boolean resolveThemeAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
+ Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(resid);
+ if (resourceInfo == null) {
+ resourceInfo = mProjectCallback.resolveResourceId(resid);
+ }
+
+ if (resourceInfo == null) {
+ return false;
+ }
+
+ ResourceValue value = mRenderResources.findItemInTheme(resourceInfo.getSecond());
+ if (resolveRefs) {
+ value = mRenderResources.resolveResValue(value);
+ }
+
+ // check if this is a style resource
+ if (value instanceof StyleResourceValue) {
+ // get the id that will represent this style.
+ outValue.resourceId = getDynamicIdByStyle((StyleResourceValue)value);
+ return true;
+ }
+
+
+ int a;
+ // if this is a framework value.
+ if (value.isFramework()) {
+ // look for idName in the android R classes.
+ // use 0 a default res value as it's not a valid id value.
+ a = getFrameworkResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
+ } else {
+ // look for idName in the project R class.
+ // use 0 a default res value as it's not a valid id value.
+ a = getProjectResourceValue(value.getResourceType(), value.getName(), 0 /*defValue*/);
+ }
+
+ if (a != 0) {
+ outValue.resourceId = a;
+ return true;
+ }
+
+ return false;
+ }
+
+
+ // ------------- Activity Methods
+
+ @Override
+ public LayoutInflater getLayoutInflater() {
+ return mBridgeInflater;
}
// ------------ Context methods
@Override
public Resources getResources() {
- return mResources;
+ return mSystemResources;
}
@Override
@@ -174,7 +292,7 @@ public final class BridgeContext extends Context {
@Override
public Object getSystemService(String service) {
if (LAYOUT_INFLATER_SERVICE.equals(service)) {
- return mInflater;
+ return mBridgeInflater;
}
// AutoCompleteTextView and MultiAutoCompleteTextView want a window
@@ -183,20 +301,25 @@ public final class BridgeContext extends Context {
return null;
}
+ // needed by SearchView
+ if (INPUT_METHOD_SERVICE.equals(service)) {
+ return null;
+ }
+
throw new UnsupportedOperationException("Unsupported Service: " + service);
}
@Override
public final TypedArray obtainStyledAttributes(int[] attrs) {
- return createStyleBasedTypedArray(mThemeValues, attrs);
+ return createStyleBasedTypedArray(mRenderResources.getCurrentTheme(), attrs);
}
@Override
public final TypedArray obtainStyledAttributes(int resid, int[] attrs)
throws Resources.NotFoundException {
- // get the IStyleResourceValue based on the resId;
- IStyleResourceValue style = getStyleByDynamicId(resid);
+ // get the StyleResourceValue based on the resId;
+ StyleResourceValue style = getStyleByDynamicId(resid);
if (style == null) {
throw new Resources.NotFoundException();
@@ -241,63 +364,128 @@ public final class BridgeContext extends Context {
public TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs,
int defStyleAttr, int defStyleRes) {
+ Map<String, String> defaultPropMap = null;
+ boolean isPlatformFile = true;
+
// Hint: for XmlPullParser, attach source //DEVICE_SRC/dalvik/libcore/xml/src/java
- BridgeXmlBlockParser parser = null;
if (set instanceof BridgeXmlBlockParser) {
+ BridgeXmlBlockParser parser = null;
parser = (BridgeXmlBlockParser)set;
+
+ isPlatformFile = parser.isPlatformFile();
+
+ Object key = parser.getViewCookie();
+ if (key != null) {
+ defaultPropMap = mDefaultPropMaps.get(key);
+ if (defaultPropMap == null) {
+ defaultPropMap = new HashMap<String, String>();
+ mDefaultPropMaps.put(key, defaultPropMap);
+ }
+ }
+
+ } else if (set instanceof BridgeLayoutParamsMapAttributes) {
+ // this is only for temp layout params generated dynamically, so this is never
+ // platform content.
+ isPlatformFile = false;
} else if (set != null) { // null parser is ok
// really this should not be happening since its instantiated in Bridge
- mLogger.error("Parser is not a BridgeXmlBlockParser!");
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Parser is not a BridgeXmlBlockParser!", null /*data*/);
return null;
}
boolean[] frameworkAttributes = new boolean[1];
TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, frameworkAttributes);
- BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length,
- parser != null ? parser.isPlatformFile() : true);
+ BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
+ isPlatformFile);
// resolve the defStyleAttr value into a IStyleResourceValue
- IStyleResourceValue defStyleValues = null;
+ StyleResourceValue defStyleValues = null;
// look for a custom style.
String customStyle = null;
- if (parser != null) {
- customStyle = parser.getAttributeValue(null /* namespace*/, "style");
+ if (set != null) {
+ customStyle = set.getAttributeValue(null /* namespace*/, "style");
}
if (customStyle != null) {
- IResourceValue item = findResValue(customStyle, false /*forceFrameworkOnly*/);
+ ResourceValue item = mRenderResources.findResValue(customStyle,
+ false /*forceFrameworkOnly*/);
+
+ // resolve it in case it links to something else
+ item = mRenderResources.resolveResValue(item);
- if (item instanceof IStyleResourceValue) {
- defStyleValues = (IStyleResourceValue)item;
+ if (item instanceof StyleResourceValue) {
+ defStyleValues = (StyleResourceValue)item;
}
}
- if (defStyleValues == null && defStyleAttr != 0) {
- // get the name from the int.
- String defStyleName = searchAttr(defStyleAttr);
+ if (defStyleValues == null) {
+ if (defStyleAttr != 0) {
+ // get the name from the int.
+ String defStyleName = searchAttr(defStyleAttr);
- // look for the style in the current theme, and its parent:
- if (mThemeValues != null) {
- IResourceValue item = findItemInStyle(mThemeValues, defStyleName);
+ if (defaultPropMap != null) {
+ defaultPropMap.put("style", defStyleName);
+ }
+
+ // look for the style in the current theme, and its parent:
+ ResourceValue item = mRenderResources.findItemInTheme(defStyleName);
if (item != null) {
// item is a reference to a style entry. Search for it.
- item = findResValue(item.getValue(), false /*forceFrameworkOnly*/);
+ item = mRenderResources.findResValue(item.getValue(),
+ false /*forceFrameworkOnly*/);
- if (item instanceof IStyleResourceValue) {
- defStyleValues = (IStyleResourceValue)item;
+ if (item instanceof StyleResourceValue) {
+ defStyleValues = (StyleResourceValue)item;
}
} else {
- // TODO: log the error properly
- System.out.println("Failed to find defStyle: " + defStyleName);
+ Bridge.getLog().error(null,
+ String.format(
+ "Failed to find style '%s' in current theme", defStyleName),
+ null /*data*/);
+ }
+ } else if (defStyleRes != 0) {
+ Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
+ if (value == null) {
+ value = mProjectCallback.resolveResourceId(defStyleRes);
}
- }
- }
- if (defStyleRes != 0) {
- // FIXME: See what we need to do with this.
- throw new UnsupportedOperationException();
+ if (value != null) {
+ if (value.getFirst() == ResourceType.STYLE) {
+ // look for the style in the current theme, and its parent:
+ ResourceValue item = mRenderResources.findItemInTheme(value.getSecond());
+ if (item != null) {
+ if (item instanceof StyleResourceValue) {
+ if (defaultPropMap != null) {
+ defaultPropMap.put("style", item.getName());
+ }
+
+ defStyleValues = (StyleResourceValue)item;
+ }
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Style with id 0x%x (resolved to '%s') does not exist.",
+ defStyleRes, value.getSecond()),
+ null /*data*/);
+ }
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Resouce id 0x%x is not of type STYLE (instead %s)",
+ defStyleRes, value.getFirst().toString()),
+ null /*data*/);
+ }
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Failed to find style with id 0x%x in current theme",
+ defStyleRes),
+ null /*data*/);
+ }
+ }
}
String namespace = BridgeConstants.NS_RESOURCES;
@@ -312,37 +500,43 @@ public final class BridgeContext extends Context {
String name = styleAttribute.getValue();
String value = null;
- if (parser != null) {
- value = parser.getAttributeValue(namespace, name);
+ if (set != null) {
+ value = set.getAttributeValue(namespace, name);
}
// if there's no direct value for this attribute in the XML, we look for default
// values in the widget defStyle, and then in the theme.
if (value == null) {
- IResourceValue resValue = null;
+ ResourceValue resValue = null;
// look for the value in the defStyle first (and its parent if needed)
if (defStyleValues != null) {
- resValue = findItemInStyle(defStyleValues, name);
+ resValue = mRenderResources.findItemInStyle(defStyleValues, name);
}
// if the item is not present in the defStyle, we look in the main theme (and
// its parent themes)
- if (resValue == null && mThemeValues != null) {
- resValue = findItemInStyle(mThemeValues, name);
+ if (resValue == null) {
+ resValue = mRenderResources.findItemInTheme(name);
}
// if we found a value, we make sure this doesn't reference another value.
// So we resolve it.
if (resValue != null) {
- resValue = resolveResValue(resValue);
+ // put the first default value, before the resolution.
+ if (defaultPropMap != null) {
+ defaultPropMap.put(name, resValue.getValue());
+ }
+
+ resValue = mRenderResources.resolveResValue(resValue);
}
ta.bridgeSetValue(index, name, resValue);
} else {
// there is a value in the XML, but we need to resolve it in case it's
// referencing another resource or a theme value.
- ta.bridgeSetValue(index, name, resolveValue(null, name, value));
+ ta.bridgeSetValue(index, name,
+ mRenderResources.resolveValue(null, name, value, isPlatformFile));
}
}
}
@@ -365,11 +559,11 @@ public final class BridgeContext extends Context {
* values found in the given style.
* @see #obtainStyledAttributes(int, int[])
*/
- private BridgeTypedArray createStyleBasedTypedArray(IStyleResourceValue style, int[] attrs)
+ private BridgeTypedArray createStyleBasedTypedArray(StyleResourceValue style, int[] attrs)
throws Resources.NotFoundException {
TreeMap<Integer, String> styleNameMap = searchAttrs(attrs, null);
- BridgeTypedArray ta = ((BridgeResources) mResources).newTypeArray(attrs.length,
+ BridgeTypedArray ta = ((BridgeResources) mSystemResources).newTypeArray(attrs.length,
false /* platformResourceFlag */);
// loop through all the values in the style map, and init the TypedArray with
@@ -380,10 +574,10 @@ public final class BridgeContext extends Context {
String name = styleAttribute.getValue();
// get the value from the style, or its parent styles.
- IResourceValue resValue = findItemInStyle(style, name);
+ ResourceValue resValue = mRenderResources.findItemInStyle(style, name);
// resolve it to make sure there are no references left.
- ta.bridgeSetValue(index, name, resolveResValue(resValue));
+ ta.bridgeSetValue(index, name, mRenderResources.resolveResValue(resValue));
}
ta.sealArray();
@@ -393,274 +587,6 @@ public final class BridgeContext extends Context {
/**
- * Resolves the value of a resource, if the value references a theme or resource value.
- * <p/>
- * This method ensures that it returns a {@link IResourceValue} object that does not
- * reference another resource.
- * If the resource cannot be resolved, it returns <code>null</code>.
- * <p/>
- * If a value that does not need to be resolved is given, the method will return a new
- * instance of IResourceValue that contains the input value.
- *
- * @param type the type of the resource
- * @param name the name of the attribute containing this value.
- * @param value the resource value, or reference to resolve
- * @return the resolved resource value or <code>null</code> if it failed to resolve it.
- */
- private IResourceValue resolveValue(String type, String name, String value) {
- if (value == null) {
- return null;
- }
-
- // get the IResourceValue referenced by this value
- IResourceValue resValue = findResValue(value, false /*forceFrameworkOnly*/);
-
- // if resValue is null, but value is not null, this means it was not a reference.
- // we return the name/value wrapper in a IResourceValue
- if (resValue == null) {
- return new ResourceValue(type, name, value);
- }
-
- // we resolved a first reference, but we need to make sure this isn't a reference also.
- return resolveResValue(resValue);
- }
-
- /**
- * Returns the {@link IResourceValue} referenced by the value of <var>value</var>.
- * <p/>
- * This method ensures that it returns a {@link IResourceValue} object that does not
- * reference another resource.
- * If the resource cannot be resolved, it returns <code>null</code>.
- * <p/>
- * If a value that does not need to be resolved is given, the method will return the input
- * value.
- *
- * @param value the value containing the reference to resolve.
- * @return a {@link IResourceValue} object or <code>null</code>
- */
- IResourceValue resolveResValue(IResourceValue value) {
- if (value == null) {
- return null;
- }
-
- // if the resource value is a style, we simply return it.
- if (value instanceof IStyleResourceValue) {
- return value;
- }
-
- // else attempt to find another IResourceValue referenced by this one.
- IResourceValue resolvedValue = findResValue(value.getValue(), value.isFramework());
-
- // if the value did not reference anything, then we simply return the input value
- if (resolvedValue == null) {
- return value;
- }
-
- // otherwise, we attempt to resolve this new value as well
- return resolveResValue(resolvedValue);
- }
-
- /**
- * Searches for, and returns a {@link IResourceValue} by its reference.
- * <p/>
- * The reference format can be:
- * <pre>@resType/resName</pre>
- * <pre>@android:resType/resName</pre>
- * <pre>@resType/android:resName</pre>
- * <pre>?resType/resName</pre>
- * <pre>?android:resType/resName</pre>
- * <pre>?resType/android:resName</pre>
- * Any other string format will return <code>null</code>.
- * <p/>
- * The actual format of a reference is <pre>@[namespace:]resType/resName</pre> but this method
- * only support the android namespace.
- *
- * @param reference the resource reference to search for.
- * @param forceFrameworkOnly if true all references are considered to be toward framework
- * resource even if the reference does not include the android: prefix.
- * @return a {@link IResourceValue} or <code>null</code>.
- */
- IResourceValue findResValue(String reference, boolean forceFrameworkOnly) {
- if (reference == null) {
- return null;
- }
- if (reference.startsWith(BridgeConstants.PREFIX_THEME_REF)) {
- // no theme? no need to go further!
- if (mThemeValues == null) {
- return null;
- }
-
- boolean frameworkOnly = false;
-
- // eleminate the prefix from the string
- if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_THEME_REF)) {
- frameworkOnly = true;
- reference = reference.substring(BridgeConstants.PREFIX_ANDROID_THEME_REF.length());
- } else {
- reference = reference.substring(BridgeConstants.PREFIX_THEME_REF.length());
- }
-
- // at this point, value can contain type/name (drawable/foo for instance).
- // split it to make sure.
- String[] segments = reference.split("\\/");
-
- // we look for the referenced item name.
- String referenceName = null;
-
- if (segments.length == 2) {
- // there was a resType in the reference. If it's attr, we ignore it
- // else, we assert for now.
- if (BridgeConstants.RES_ATTR.equals(segments[0])) {
- referenceName = segments[1];
- } else {
- // At this time, no support for ?type/name where type is not "attr"
- return null;
- }
- } else {
- // it's just an item name.
- referenceName = segments[0];
- }
-
- // now we look for android: in the referenceName in order to support format
- // such as: ?attr/android:name
- if (referenceName.startsWith(BridgeConstants.PREFIX_ANDROID)) {
- frameworkOnly = true;
- referenceName = referenceName.substring(BridgeConstants.PREFIX_ANDROID.length());
- }
-
- // Now look for the item in the theme, starting with the current one.
- if (frameworkOnly) {
- // FIXME for now we do the same as if it didn't specify android:
- return findItemInStyle(mThemeValues, referenceName);
- }
-
- return findItemInStyle(mThemeValues, referenceName);
- } else if (reference.startsWith(BridgeConstants.PREFIX_RESOURCE_REF)) {
- boolean frameworkOnly = false;
-
- // check for the specific null reference value.
- if (BridgeConstants.REFERENCE_NULL.equals(reference)) {
- return null;
- }
-
- // Eliminate the prefix from the string.
- if (reference.startsWith(BridgeConstants.PREFIX_ANDROID_RESOURCE_REF)) {
- frameworkOnly = true;
- reference = reference.substring(
- BridgeConstants.PREFIX_ANDROID_RESOURCE_REF.length());
- } else {
- reference = reference.substring(BridgeConstants.PREFIX_RESOURCE_REF.length());
- }
-
- // at this point, value contains type/[android:]name (drawable/foo for instance)
- String[] segments = reference.split("\\/");
-
- // now we look for android: in the resource name in order to support format
- // such as: @drawable/android:name
- if (segments[1].startsWith(BridgeConstants.PREFIX_ANDROID)) {
- frameworkOnly = true;
- segments[1] = segments[1].substring(BridgeConstants.PREFIX_ANDROID.length());
- }
-
- return findResValue(segments[0], segments[1],
- forceFrameworkOnly ? true :frameworkOnly);
- }
-
- // Looks like the value didn't reference anything. Return null.
- return null;
- }
-
- /**
- * Searches for, and returns a {@link IResourceValue} by its name, and type.
- * @param resType the type of the resource
- * @param resName the name of the resource
- * @param frameworkOnly if <code>true</code>, the method does not search in the
- * project resources
- */
- private IResourceValue findResValue(String resType, String resName, boolean frameworkOnly) {
- // map of IResouceValue for the given type
- Map<String, IResourceValue> typeMap;
-
- // if allowed, search in the project resources first.
- if (frameworkOnly == false) {
- typeMap = mProjectResources.get(resType);
- if (typeMap != null) {
- IResourceValue item = typeMap.get(resName);
- if (item != null) {
- return item;
- }
- }
- }
-
- // now search in the framework resources.
- typeMap = mFrameworkResources.get(resType);
- if (typeMap != null) {
- IResourceValue item = typeMap.get(resName);
- if (item != null) {
- return item;
- }
- }
-
- // didn't find the resource anywhere.
- return null;
- }
-
- /**
- * Returns a framework resource by type and name. The returned resource is resolved.
- * @param resourceType the type of the resource
- * @param resourceName the name of the resource
- */
- public IResourceValue getFrameworkResource(String resourceType, String resourceName) {
- return getResource(resourceType, resourceName, mFrameworkResources);
- }
-
- /**
- * Returns a project resource by type and name. The returned resource is resolved.
- * @param resourceType the type of the resource
- * @param resourceName the name of the resource
- */
- public IResourceValue getProjectResource(String resourceType, String resourceName) {
- return getResource(resourceType, resourceName, mProjectResources);
- }
-
- IResourceValue getResource(String resourceType, String resourceName,
- Map<String, Map<String, IResourceValue>> resourceRepository) {
- Map<String, IResourceValue> typeMap = resourceRepository.get(resourceType);
- if (typeMap != null) {
- IResourceValue item = typeMap.get(resourceName);
- if (item != null) {
- item = resolveResValue(item);
- return item;
- }
- }
-
- // didn't find the resource anywhere.
- return null;
-
- }
-
- /**
- * Returns the {@link IResourceValue} matching a given name in a given style. If the
- * item is not directly available in the style, the method looks in its parent style.
- * @param style the style to search in
- * @param itemName the name of the item to search for.
- * @return the {@link IResourceValue} object or <code>null</code>
- */
- IResourceValue findItemInStyle(IStyleResourceValue style, String itemName) {
- IResourceValue item = style.findItem(itemName);
-
- // if we didn't find it, we look in the parent style (if applicable)
- if (item == null && mStyleInheritanceMap != null) {
- IStyleResourceValue parentStyle = mStyleInheritanceMap.get(style);
- if (parentStyle != null) {
- return findItemInStyle(parentStyle, itemName);
- }
- }
-
- return item;
- }
-
- /**
* The input int[] attrs is one of com.android.internal.R.styleable fields where the name
* of the field is the style being referenced and the array contains one index per attribute.
* <p/>
@@ -675,14 +601,14 @@ public final class BridgeContext extends Context {
*/
private TreeMap<Integer,String> searchAttrs(int[] attrs, boolean[] outFrameworkFlag) {
// get the name of the array from the framework resources
- String arrayName = Bridge.resolveResourceValue(attrs);
+ String arrayName = Bridge.resolveResourceId(attrs);
if (arrayName != null) {
// if we found it, get the name of each of the int in the array.
TreeMap<Integer,String> attributes = new TreeMap<Integer, String>();
for (int i = 0 ; i < attrs.length ; i++) {
- String[] info = Bridge.resolveResourceValue(attrs[i]);
+ Pair<ResourceType, String> info = Bridge.resolveResourceId(attrs[i]);
if (info != null) {
- attributes.put(i, info[0]);
+ attributes.put(i, info.getSecond());
} else {
// FIXME Not sure what we should be doing here...
attributes.put(i, null);
@@ -698,13 +624,13 @@ public final class BridgeContext extends Context {
// if the name was not found in the framework resources, look in the project
// resources
- arrayName = mProjectCallback.resolveResourceValue(attrs);
+ arrayName = mProjectCallback.resolveResourceId(attrs);
if (arrayName != null) {
TreeMap<Integer,String> attributes = new TreeMap<Integer, String>();
for (int i = 0 ; i < attrs.length ; i++) {
- String[] info = mProjectCallback.resolveResourceValue(attrs[i]);
+ Pair<ResourceType, String> info = mProjectCallback.resolveResourceId(attrs[i]);
if (info != null) {
- attributes.put(i, info[0]);
+ attributes.put(i, info.getSecond());
} else {
// FIXME Not sure what we should be doing here...
attributes.put(i, null);
@@ -729,24 +655,24 @@ public final class BridgeContext extends Context {
* if nothing is found.
*/
public String searchAttr(int attr) {
- String[] info = Bridge.resolveResourceValue(attr);
+ Pair<ResourceType, String> info = Bridge.resolveResourceId(attr);
if (info != null) {
- return info[0];
+ return info.getSecond();
}
- info = mProjectCallback.resolveResourceValue(attr);
+ info = mProjectCallback.resolveResourceId(attr);
if (info != null) {
- return info[0];
+ return info.getSecond();
}
return null;
}
- int getDynamicIdByStyle(IStyleResourceValue resValue) {
+ int getDynamicIdByStyle(StyleResourceValue resValue) {
if (mDynamicIdToStyleMap == null) {
// create the maps.
- mDynamicIdToStyleMap = new HashMap<Integer, IStyleResourceValue>();
- mStyleToDynamicIdMap = new HashMap<IStyleResourceValue, Integer>();
+ mDynamicIdToStyleMap = new HashMap<Integer, StyleResourceValue>();
+ mStyleToDynamicIdMap = new HashMap<StyleResourceValue, Integer>();
}
// look for an existing id
@@ -764,7 +690,7 @@ public final class BridgeContext extends Context {
return id;
}
- private IStyleResourceValue getStyleByDynamicId(int i) {
+ private StyleResourceValue getStyleByDynamicId(int i) {
if (mDynamicIdToStyleMap != null) {
return mDynamicIdToStyleMap.get(i);
}
@@ -772,8 +698,8 @@ public final class BridgeContext extends Context {
return null;
}
- int getFrameworkIdValue(String idName, int defValue) {
- Integer value = Bridge.getResourceValue(BridgeConstants.RES_ID, idName);
+ int getFrameworkResourceValue(ResourceType resType, String resName, int defValue) {
+ Integer value = Bridge.getResourceId(resType, resName);
if (value != null) {
return value.intValue();
}
@@ -781,9 +707,9 @@ public final class BridgeContext extends Context {
return defValue;
}
- int getProjectIdValue(String idName, int defValue) {
+ int getProjectResourceValue(ResourceType resType, String resName, int defValue) {
if (mProjectCallback != null) {
- Integer value = mProjectCallback.getResourceValue(BridgeConstants.RES_ID, idName);
+ Integer value = mProjectCallback.getResourceId(resType, resName);
if (value != null) {
return value.intValue();
}
@@ -1000,7 +926,7 @@ public final class BridgeContext extends Context {
@Override
public ApplicationInfo getApplicationInfo() {
- return new ApplicationInfo();
+ return mApplicationInfo;
}
@Override
@@ -1043,25 +969,20 @@ public final class BridgeContext extends Context {
}
- @SuppressWarnings("unused")
@Override
- public FileInputStream openFileInput(String arg0)
- throws FileNotFoundException {
+ public FileInputStream openFileInput(String arg0) throws FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
- @SuppressWarnings("unused")
@Override
- public FileOutputStream openFileOutput(String arg0, int arg1)
- throws FileNotFoundException {
+ public FileOutputStream openFileOutput(String arg0, int arg1) throws FileNotFoundException {
// TODO Auto-generated method stub
return null;
}
@Override
- public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1,
- CursorFactory arg2) {
+ public SQLiteDatabase openOrCreateDatabase(String arg0, int arg1, CursorFactory arg2) {
// TODO Auto-generated method stub
return null;
}
@@ -1142,14 +1063,12 @@ public final class BridgeContext extends Context {
}
- @SuppressWarnings("unused")
@Override
public void setWallpaper(Bitmap arg0) throws IOException {
// TODO Auto-generated method stub
}
- @SuppressWarnings("unused")
@Override
public void setWallpaper(InputStream arg0) throws IOException {
// TODO Auto-generated method stub
@@ -1204,4 +1123,9 @@ public final class BridgeContext extends Context {
public Context getApplicationContext() {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public boolean isRestricted() {
+ return false;
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
index 0910d79..cb8d8dd 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeInflater.java
@@ -14,36 +14,42 @@
* limitations under the License.
*/
-package android.view;
+package com.android.layoutlib.bridge.android;
-import com.android.layoutlib.api.IProjectCallback;
-import com.android.layoutlib.api.IResourceValue;
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.MergeCookie;
+import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.BridgeConstants;
-import com.android.layoutlib.bridge.BridgeContext;
-import com.android.layoutlib.bridge.BridgeXmlBlockParser;
+import com.android.resources.ResourceType;
+import com.android.util.Pair;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import android.content.Context;
import android.util.AttributeSet;
+import android.view.InflateException;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
import java.io.File;
import java.io.FileReader;
/**
- * Custom implementation of {@link LayoutInflater} to handle custom views.
+ * Custom implementation of {@link LayoutInflater} to handle custom views.
*/
public final class BridgeInflater extends LayoutInflater {
-
+
private final IProjectCallback mProjectCallback;
+ private boolean mIsInMerge = false;
/**
* List of class prefixes which are tried first by default.
* <p/>
* This should match the list in com.android.internal.policy.impl.PhoneLayoutInflater.
- */
+ */
private static final String[] sClassPrefixList = {
"android.widget.",
"android.webkit."
@@ -53,10 +59,10 @@ public final class BridgeInflater extends LayoutInflater {
super(original, newContext);
mProjectCallback = null;
}
-
+
/**
* Instantiate a new BridgeInflater with an {@link IProjectCallback} object.
- *
+ *
* @param context The Android application context.
* @param projectCallback the {@link IProjectCallback} object.
*/
@@ -82,7 +88,7 @@ public final class BridgeInflater extends LayoutInflater {
// Ignore. We'll try again using the base class below.
}
}
-
+
// Next try using the parent loader. This will most likely only work for
// fully-qualified class names.
try {
@@ -92,7 +98,7 @@ public final class BridgeInflater extends LayoutInflater {
} catch (ClassNotFoundException e) {
// Ignore. We'll try again using the custom view loader below.
}
-
+
// Finally try again using the custom view loader
try {
if (view == null) {
@@ -109,12 +115,12 @@ public final class BridgeInflater extends LayoutInflater {
ClassNotFoundException exception = new ClassNotFoundException("onCreateView", e);
throw exception;
}
-
+
setupViewInContext(view, attrs);
-
+
return view;
}
-
+
@Override
public View createViewFromTag(String name, AttributeSet attrs) {
View view = null;
@@ -128,7 +134,7 @@ public final class BridgeInflater extends LayoutInflater {
// Wrap the real exception in an InflateException so that the calling
// method can deal with it.
InflateException exception = new InflateException();
- if (e2.getClass().equals(ClassNotFoundException.class) == false) {
+ if (e2.getClass().equals(ClassNotFoundException.class) == false) {
exception.initCause(e2);
} else {
exception.initCause(e);
@@ -136,30 +142,30 @@ public final class BridgeInflater extends LayoutInflater {
throw exception;
}
}
-
+
setupViewInContext(view, attrs);
-
+
return view;
}
-
+
@Override
public View inflate(int resource, ViewGroup root) {
Context context = getContext();
if (context instanceof BridgeContext) {
BridgeContext bridgeContext = (BridgeContext)context;
-
- IResourceValue value = null;
- String[] layoutInfo = Bridge.resolveResourceValue(resource);
+ ResourceValue value = null;
+
+ Pair<ResourceType, String> layoutInfo = Bridge.resolveResourceId(resource);
if (layoutInfo != null) {
- value = bridgeContext.getFrameworkResource(BridgeConstants.RES_LAYOUT,
- layoutInfo[0]);
+ value = bridgeContext.getRenderResources().getFrameworkResource(
+ ResourceType.LAYOUT, layoutInfo.getSecond());
} else {
- layoutInfo = mProjectCallback.resolveResourceValue(resource);
-
+ layoutInfo = mProjectCallback.resolveResourceId(resource);
+
if (layoutInfo != null) {
- value = bridgeContext.getProjectResource(BridgeConstants.RES_LAYOUT,
- layoutInfo[0]);
+ value = bridgeContext.getRenderResources().getProjectResource(
+ ResourceType.LAYOUT, layoutInfo.getSecond());
}
}
@@ -170,21 +176,23 @@ public final class BridgeInflater extends LayoutInflater {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(f));
-
+
BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
parser, bridgeContext, false);
-
+
return inflate(bridgeParser, root);
} catch (Exception e) {
- bridgeContext.getLogger().error(e);
- // return null below.
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+ "Failed to parse file " + f.getAbsolutePath(), e, null /*data*/);
+
+ return null;
}
}
}
}
return null;
}
-
+
private View loadCustomView(String name, AttributeSet attrs) throws ClassNotFoundException,
Exception{
if (mProjectCallback != null) {
@@ -192,12 +200,12 @@ public final class BridgeInflater extends LayoutInflater {
if (name.equals("view")) {
name = attrs.getAttributeValue(null, "class");
}
-
+
mConstructorArgs[1] = attrs;
Object customView = mProjectCallback.loadView(name, mConstructorSignature,
mConstructorArgs);
-
+
if (customView instanceof View) {
return (View)customView;
}
@@ -205,21 +213,43 @@ public final class BridgeInflater extends LayoutInflater {
return null;
}
-
-
-
+
private void setupViewInContext(View view, AttributeSet attrs) {
if (getContext() instanceof BridgeContext) {
BridgeContext bc = (BridgeContext) getContext();
if (attrs instanceof BridgeXmlBlockParser) {
- Object viewKey = ((BridgeXmlBlockParser) attrs).getViewKey();
+ BridgeXmlBlockParser parser = (BridgeXmlBlockParser) attrs;
+
+ // get the view key
+ Object viewKey = parser.getViewCookie();
+
+ // if there's no view key and the depth is 1 (ie this is the first tag), or 2
+ // (this is first item in included merge layout)
+ // look for a previous parser in the context, and check if this one has a viewkey.
+ int testDepth = mIsInMerge ? 2 : 1;
+ if (viewKey == null && parser.getDepth() == testDepth) {
+ BridgeXmlBlockParser previousParser = bc.getPreviousParser();
+ if (previousParser != null) {
+ viewKey = previousParser.getViewCookie();
+ }
+ }
+
if (viewKey != null) {
+ if (testDepth == 2) {
+ // include-merge case
+ viewKey = new MergeCookie(viewKey);
+ }
+
bc.addViewKey(view, viewKey);
}
}
}
}
+ public void setIsInMerge(boolean isInMerge) {
+ mIsInMerge = isInMerge;
+ }
+
@Override
public LayoutInflater cloneInContext(Context newContext) {
return new BridgeInflater(this, newContext);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
new file mode 100644
index 0000000..d208408
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeLayoutParamsMapAttributes.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.android;
+
+import com.android.layoutlib.bridge.BridgeConstants;
+
+import android.util.AttributeSet;
+
+import java.util.Map;
+
+/**
+ * An implementation of the {@link AttributeSet} interface on top of a map of attribute in the form
+ * of (name, value).
+ *
+ * This is meant to be called only from {@link BridgeContext#obtainStyledAttributes(AttributeSet, int[], int, int)}
+ * in the case of LayoutParams and therefore isn't a full implementation.
+ */
+public class BridgeLayoutParamsMapAttributes implements AttributeSet {
+
+ private final Map<String, String> mAttributes;
+
+ public BridgeLayoutParamsMapAttributes(Map<String, String> attributes) {
+ mAttributes = attributes;
+ }
+
+ public String getAttributeValue(String namespace, String name) {
+ if (BridgeConstants.NS_RESOURCES.equals(namespace)) {
+ return mAttributes.get(name);
+ }
+
+ return null;
+ }
+
+ // ---- the following methods are not called from
+ // BridgeContext#obtainStyledAttributes(AttributeSet, int[], int, int)
+ // Should they ever be called, we'll just implement them on a need basis.
+
+ public int getAttributeCount() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getAttributeName(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getAttributeValue(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getPositionDescription() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getAttributeNameResource(int index) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getAttributeListValue(String namespace, String attribute,
+ String[] options, int defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getAttributeBooleanValue(String namespace, String attribute,
+ boolean defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getAttributeResourceValue(String namespace, String attribute,
+ int defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getAttributeIntValue(String namespace, String attribute,
+ int defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getAttributeUnsignedIntValue(String namespace, String attribute,
+ int defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public float getAttributeFloatValue(String namespace, String attribute,
+ float defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getAttributeListValue(int index,
+ String[] options, int defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean getAttributeBooleanValue(int index, boolean defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getAttributeResourceValue(int index, int defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getAttributeIntValue(int index, int defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getAttributeUnsignedIntValue(int index, int defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public float getAttributeFloatValue(int index, float defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getIdAttribute() {
+ throw new UnsupportedOperationException();
+ }
+
+ public String getClassAttribute() {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getIdAttributeResourceValue(int defaultValue) {
+ throw new UnsupportedOperationException();
+ }
+
+ public int getStyleAttribute() {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
index 6358abb..5e5aeb1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeResources.java
@@ -14,10 +14,17 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
-
-import com.android.layoutlib.api.IProjectCallback;
-import com.android.layoutlib.api.IResourceValue;
+package com.android.layoutlib.bridge.android;
+
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.ninepatch.NinePatch;
+import com.android.resources.ResourceType;
+import com.android.util.Pair;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
@@ -52,6 +59,35 @@ public final class BridgeResources extends Resources {
private boolean[] mPlatformResourceFlag = new boolean[1];
/**
+ * Simpler wrapper around FileInputStream. This is used when the input stream represent
+ * not a normal bitmap but a nine patch.
+ * This is useful when the InputStream is created in a method but used in another that needs
+ * to know whether this is 9-patch or not, such as BitmapFactory.
+ */
+ public class NinePatchInputStream extends FileInputStream {
+ private boolean mFakeMarkSupport = true;
+ public NinePatchInputStream(File file) throws FileNotFoundException {
+ super(file);
+ }
+
+ @Override
+ public boolean markSupported() {
+ if (mFakeMarkSupport) {
+ // this is needed so that BitmapFactory doesn't wrap this in a BufferedInputStream.
+ return true;
+ }
+
+ return super.markSupported();
+ }
+
+ public void disableFakeMarkSupport() {
+ // disable fake mark support so that in case codec actually try to use them
+ // we don't lie to them.
+ mFakeMarkSupport = false;
+ }
+ }
+
+ /**
* This initializes the static field {@link Resources#mSystem} which is used
* by methods who get global resources using {@link Resources#getSystem()}.
* <p/>
@@ -64,21 +100,18 @@ public final class BridgeResources extends Resources {
DisplayMetrics metrics,
Configuration config,
IProjectCallback projectCallback) {
- if (!(Resources.mSystem instanceof BridgeResources)) {
- Resources.mSystem = new BridgeResources(context,
- assets,
- metrics,
- config,
- projectCallback);
- }
- return Resources.mSystem;
+ return Resources.mSystem = new BridgeResources(context,
+ assets,
+ metrics,
+ config,
+ projectCallback);
}
/**
- * Clears the static {@link Resources#mSystem} to make sure we don't leave objects
+ * Disposes the static {@link Resources#mSystem} to make sure we don't leave objects
* around that would prevent us from unloading the library.
*/
- /*package*/ static void clearSystem() {
+ /*package*/ static void disposeSystem() {
if (Resources.mSystem instanceof BridgeResources) {
((BridgeResources)(Resources.mSystem)).mContext = null;
((BridgeResources)(Resources.mSystem)).mProjectCallback = null;
@@ -97,22 +130,24 @@ public final class BridgeResources extends Resources {
return new BridgeTypedArray(this, mContext, numEntries, platformFile);
}
- private IResourceValue getResourceValue(int id, boolean[] platformResFlag_out) {
+ private ResourceValue getResourceValue(int id, boolean[] platformResFlag_out) {
// first get the String related to this id in the framework
- String[] resourceInfo = Bridge.resolveResourceValue(id);
+ Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
if (resourceInfo != null) {
platformResFlag_out[0] = true;
- return mContext.getFrameworkResource(resourceInfo[1], resourceInfo[0]);
+ return mContext.getRenderResources().getFrameworkResource(
+ resourceInfo.getFirst(), resourceInfo.getSecond());
}
// didn't find a match in the framework? look in the project.
if (mProjectCallback != null) {
- resourceInfo = mProjectCallback.resolveResourceValue(id);
+ resourceInfo = mProjectCallback.resolveResourceId(id);
if (resourceInfo != null) {
platformResFlag_out[0] = false;
- return mContext.getProjectResource(resourceInfo[1], resourceInfo[0]);
+ return mContext.getRenderResources().getProjectResource(
+ resourceInfo.getFirst(), resourceInfo.getSecond());
}
}
@@ -121,10 +156,10 @@ public final class BridgeResources extends Resources {
@Override
public Drawable getDrawable(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
- return ResourceHelper.getDrawable(value, mContext, value.isFramework());
+ return ResourceHelper.getDrawable(value, mContext);
}
// id was not found or not resolved. Throw a NotFoundException.
@@ -136,12 +171,14 @@ public final class BridgeResources extends Resources {
@Override
public int getColor(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
try {
return ResourceHelper.getColor(value.getValue());
} catch (NumberFormatException e) {
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e,
+ null /*data*/);
return 0;
}
}
@@ -155,14 +192,12 @@ public final class BridgeResources extends Resources {
@Override
public ColorStateList getColorStateList(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue resValue = getResourceValue(id, mPlatformResourceFlag);
- if (value != null) {
- try {
- int color = ResourceHelper.getColor(value.getValue());
- return ColorStateList.valueOf(color);
- } catch (NumberFormatException e) {
- return null;
+ if (resValue != null) {
+ ColorStateList stateList = ResourceHelper.getColorStateList(resValue, mContext);
+ if (stateList != null) {
+ return stateList;
}
}
@@ -175,7 +210,7 @@ public final class BridgeResources extends Resources {
@Override
public CharSequence getText(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
return value.getValue();
@@ -190,27 +225,76 @@ public final class BridgeResources extends Resources {
@Override
public XmlResourceParser getLayout(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
- File xml = new File(value.getValue());
- if (xml.isFile()) {
- // we need to create a pull parser around the layout XML file, and then
- // give that to our XmlBlockParser
- try {
- KXmlParser parser = new KXmlParser();
+ XmlPullParser parser = null;
+
+ try {
+ // check if the current parser can provide us with a custom parser.
+ BridgeXmlBlockParser currentParser = mContext.getCurrentParser();
+ if (currentParser != null) {
+ parser = currentParser.getParser(value.getName());
+ }
+
+ // create a new one manually if needed.
+ if (parser == null) {
+ File xml = new File(value.getValue());
+ if (xml.isFile()) {
+ // we need to create a pull parser around the layout XML file, and then
+ // give that to our XmlBlockParser
+ parser = new KXmlParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ parser.setInput(new FileReader(xml));
+ }
+ }
+
+ if (parser != null) {
+ return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
+ }
+ } catch (XmlPullParserException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Failed to configure parser for " + value.getValue(), e, null /*data*/);
+ // we'll return null below.
+ } catch (FileNotFoundException e) {
+ // this shouldn't happen since we check above.
+ }
+
+ }
+
+ // id was not found or not resolved. Throw a NotFoundException.
+ throwException(id);
+
+ // this is not used since the method above always throws
+ return null;
+ }
+
+ @Override
+ public XmlResourceParser getAnimation(int id) throws NotFoundException {
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+
+ if (value != null) {
+ XmlPullParser parser = null;
+
+ try {
+ File xml = new File(value.getValue());
+ if (xml.isFile()) {
+ // we need to create a pull parser around the layout XML file, and then
+ // give that to our XmlBlockParser
+ parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(xml));
return new BridgeXmlBlockParser(parser, mContext, mPlatformResourceFlag[0]);
- } catch (XmlPullParserException e) {
- mContext.getLogger().error(e);
-
- // we'll return null below.
- } catch (FileNotFoundException e) {
- // this shouldn't happen since we check above.
}
+ } catch (XmlPullParserException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Failed to configure parser for " + value.getValue(), e, null /*data*/);
+ // we'll return null below.
+ } catch (FileNotFoundException e) {
+ // this shouldn't happen since we check above.
}
+
}
// id was not found or not resolved. Throw a NotFoundException.
@@ -233,7 +317,7 @@ public final class BridgeResources extends Resources {
@Override
public float getDimension(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
@@ -262,7 +346,7 @@ public final class BridgeResources extends Resources {
@Override
public int getDimensionPixelOffset(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
@@ -284,7 +368,7 @@ public final class BridgeResources extends Resources {
@Override
public int getDimensionPixelSize(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
@@ -306,7 +390,7 @@ public final class BridgeResources extends Resources {
@Override
public int getInteger(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null && value.getValue() != null) {
String v = value.getValue();
@@ -361,7 +445,7 @@ public final class BridgeResources extends Resources {
@Override
public String getString(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null && value.getValue() != null) {
return value.getValue();
@@ -377,7 +461,7 @@ public final class BridgeResources extends Resources {
@Override
public void getValue(int id, TypedValue outValue, boolean resolveRefs)
throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
@@ -406,7 +490,7 @@ public final class BridgeResources extends Resources {
@Override
public XmlResourceParser getXml(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
String v = value.getValue();
@@ -470,16 +554,22 @@ public final class BridgeResources extends Resources {
@Override
public InputStream openRawResource(int id) throws NotFoundException {
- IResourceValue value = getResourceValue(id, mPlatformResourceFlag);
+ ResourceValue value = getResourceValue(id, mPlatformResourceFlag);
if (value != null) {
- String v = value.getValue();
+ String path = value.getValue();
- if (v != null) {
+ if (path != null) {
// check this is a file
- File f = new File(value.getValue());
+ File f = new File(path);
if (f.isFile()) {
try {
+ // if it's a nine-patch return a custom input stream so that
+ // other methods (mainly bitmap factory) can detect it's a 9-patch
+ // and actually load it as a 9-patch instead of a normal bitmap
+ if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
+ return new NinePatchInputStream(f);
+ }
return new FileInputStream(f);
} catch (FileNotFoundException e) {
NotFoundException newE = new NotFoundException();
@@ -501,9 +591,17 @@ public final class BridgeResources extends Resources {
public InputStream openRawResource(int id, TypedValue value) throws NotFoundException {
getValue(id, value, true);
- File f = new File(value.string.toString());
+ String path = value.string.toString();
+
+ File f = new File(path);
if (f.isFile()) {
try {
+ // if it's a nine-patch return a custom input stream so that
+ // other methods (mainly bitmap factory) can detect it's a 9-patch
+ // and actually load it as a 9-patch instead of a normal bitmap
+ if (path.toLowerCase().endsWith(NinePatch.EXTENSION_9PATCH)) {
+ return new NinePatchInputStream(f);
+ }
return new FileInputStream(f);
} catch (FileNotFoundException e) {
NotFoundException exception = new NotFoundException();
@@ -527,18 +625,18 @@ public final class BridgeResources extends Resources {
*/
private void throwException(int id) throws NotFoundException {
// first get the String related to this id in the framework
- String[] resourceInfo = Bridge.resolveResourceValue(id);
+ Pair<ResourceType, String> resourceInfo = Bridge.resolveResourceId(id);
// if the name is unknown in the framework, get it from the custom view loader.
if (resourceInfo == null && mProjectCallback != null) {
- resourceInfo = mProjectCallback.resolveResourceValue(id);
+ resourceInfo = mProjectCallback.resolveResourceId(id);
}
String message = null;
if (resourceInfo != null) {
message = String.format(
"Could not find %1$s resource matching value 0x%2$X (resolved name: %3$s) in current configuration.",
- resourceInfo[1], id, resourceInfo[0]);
+ resourceInfo.getFirst(), id, resourceInfo.getSecond());
} else {
message = String.format(
"Could not resolve resource value: 0x%1$X.", id);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index 70c5bd7..b9f769f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -14,14 +14,21 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.StyleResourceValue;
import com.android.internal.util.XmlUtils;
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IStyleResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.resources.ResourceType;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
import android.content.res.ColorStateList;
import android.content.res.Resources;
@@ -33,39 +40,38 @@ import android.view.ViewGroup.LayoutParams;
import java.io.File;
import java.io.FileReader;
+import java.util.Arrays;
import java.util.Map;
/**
- * TODO: describe.
+ * Custom implementation of TypedArray to handle non compiled resources.
*/
public final class BridgeTypedArray extends TypedArray {
- @SuppressWarnings("hiding")
- private BridgeResources mResources;
+ private BridgeResources mBridgeResources;
private BridgeContext mContext;
- @SuppressWarnings("hiding")
- private IResourceValue[] mData;
+ private ResourceValue[] mResourceData;
private String[] mNames;
private final boolean mPlatformFile;
public BridgeTypedArray(BridgeResources resources, BridgeContext context, int len,
boolean platformFile) {
super(null, null, null, 0);
- mResources = resources;
+ mBridgeResources = resources;
mContext = context;
mPlatformFile = platformFile;
- mData = new IResourceValue[len];
+ mResourceData = new ResourceValue[len];
mNames = new String[len];
}
/** A bridge-specific method that sets a value in the type array */
- public void bridgeSetValue(int index, String name, IResourceValue value) {
- mData[index] = value;
+ public void bridgeSetValue(int index, String name, ResourceValue value) {
+ mResourceData[index] = value;
mNames[index] = name;
}
/**
- * Seals the array after all calls to {@link #bridgeSetValue(int, String, IResourceValue)} have
+ * Seals the array after all calls to {@link #bridgeSetValue(int, String, ResourceValue)} have
* been done.
* <p/>This allows to compute the list of non default values, permitting
* {@link #getIndexCount()} to return the proper value.
@@ -74,7 +80,7 @@ public final class BridgeTypedArray extends TypedArray {
// fills TypedArray.mIndices which is used to implement getIndexCount/getIndexAt
// first count the array size
int count = 0;
- for (IResourceValue data : mData) {
+ for (ResourceValue data : mResourceData) {
if (data != null) {
count++;
}
@@ -86,8 +92,8 @@ public final class BridgeTypedArray extends TypedArray {
// fill the array with the indices.
int index = 1;
- for (int i = 0 ; i < mData.length ; i++) {
- if (mData[i] != null) {
+ for (int i = 0 ; i < mResourceData.length ; i++) {
+ if (mResourceData[i] != null) {
mIndices[index++] = i;
}
}
@@ -98,7 +104,7 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int length() {
- return mData.length;
+ return mResourceData.length;
}
/**
@@ -106,7 +112,7 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public Resources getResources() {
- return mResources;
+ return mBridgeResources;
}
/**
@@ -119,9 +125,9 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public CharSequence getText(int index) {
- if (mData[index] != null) {
+ if (mResourceData[index] != null) {
// FIXME: handle styled strings!
- return mData[index].getValue();
+ return mResourceData[index].getValue();
}
return null;
@@ -137,8 +143,8 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public String getString(int index) {
- if (mData[index] != null) {
- return mData[index].getValue();
+ if (mResourceData[index] != null) {
+ return mResourceData[index].getValue();
}
return null;
@@ -154,11 +160,11 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public boolean getBoolean(int index, boolean defValue) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return defValue;
}
- String s = mData[index].getValue();
+ String s = mResourceData[index].getValue();
if (s != null) {
return XmlUtils.convertValueToBoolean(s, defValue);
}
@@ -176,11 +182,15 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getInt(int index, int defValue) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return defValue;
}
- String s = mData[index].getValue();
+ String s = mResourceData[index].getValue();
+
+ if (RenderResources.REFERENCE_NULL.equals(s)) {
+ return defValue;
+ }
try {
return (s == null) ? defValue : XmlUtils.convertValueToInt(s, defValue);
@@ -204,9 +214,10 @@ public final class BridgeTypedArray extends TypedArray {
if (i != null) {
result |= i.intValue();
} else {
- mContext.getLogger().warning(String.format(
- "Unknown constant \"%s\" in attribute \"%2$s\"",
- keyword, mNames[index]));
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+ String.format(
+ "\"%s\" in attribute \"%2$s\" is not a valid value",
+ keyword, mNames[index]), null /*data*/);
}
}
return result;
@@ -224,19 +235,20 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public float getFloat(int index, float defValue) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return defValue;
}
- String s = mData[index].getValue();
+ String s = mResourceData[index].getValue();
if (s != null) {
try {
return Float.parseFloat(s);
} catch (NumberFormatException e) {
- mContext.getLogger().warning(String.format(
- "Unable to convert \"%s\" into a float in attribute \"%2$s\"",
- s, mNames[index]));
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+ String.format(
+ "\"%s\" in attribute \"%2$s\" cannot be converted to float.",
+ s, mNames[index]), null /*data*/);
// we'll return the default value below.
}
@@ -258,19 +270,14 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getColor(int index, int defValue) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return defValue;
}
- String s = mData[index].getValue();
- try {
- return ResourceHelper.getColor(s);
- } catch (NumberFormatException e) {
- mContext.getLogger().warning(String.format(
- "Unable to convert \"%s\" into a color in attribute \"%2$s\"",
- s, mNames[index]));
-
- // we'll return the default value below.
+ ColorStateList colorStateList = ResourceHelper.getColorStateList(
+ mResourceData[index], mContext);
+ if (colorStateList != null) {
+ return colorStateList.getDefaultColor();
}
return defValue;
@@ -287,49 +294,56 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public ColorStateList getColorStateList(int index) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return null;
}
- String value = mData[index].getValue();
+ ResourceValue resValue = mResourceData[index];
+ String value = resValue.getValue();
if (value == null) {
return null;
}
- try {
- int color = ResourceHelper.getColor(value);
- return ColorStateList.valueOf(color);
- } catch (NumberFormatException e) {
- // if it's not a color value, we'll attempt to read the xml based color below.
+ if (RenderResources.REFERENCE_NULL.equals(value)) {
+ return null;
}
// let the framework inflate the ColorStateList from the XML file.
- try {
- File f = new File(value);
- if (f.isFile()) {
+ File f = new File(value);
+ if (f.isFile()) {
+ try {
KXmlParser parser = new KXmlParser();
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(f));
- ColorStateList colorStateList = ColorStateList.createFromXml(
- mContext.getResources(),
- // FIXME: we need to know if this resource is platform or not
- new BridgeXmlBlockParser(parser, mContext, false));
- return colorStateList;
+ BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
+ parser, mContext, resValue.isFramework());
+ try {
+ return ColorStateList.createFromXml(mContext.getResources(), blockParser);
+ } finally {
+ blockParser.ensurePopped();
+ }
+ } catch (XmlPullParserException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Failed to configure parser for " + value, e, null /*data*/);
+ return null;
+ } catch (Exception e) {
+ // this is an error and not warning since the file existence is checked before
+ // attempting to parse it.
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+ "Failed to parse file " + value, e, null /*data*/);
+
+ return null;
}
- } catch (Exception e) {
- // this is an error and not warning since the file existence is checked before
- // attempting to parse it.
- mContext.getLogger().error(e);
-
- // return null below.
}
- // looks like were unable to resolve the color value.
- mContext.getLogger().warning(String.format(
- "Unable to resolve color value \"%1$s\" in attribute \"%2$s\"",
- value, mNames[index]));
+ try {
+ int color = ResourceHelper.getColor(value);
+ return ColorStateList.valueOf(color);
+ } catch (NumberFormatException e) {
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null /*data*/);
+ }
return null;
}
@@ -345,19 +359,20 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getInteger(int index, int defValue) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return defValue;
}
- String s = mData[index].getValue();
+ String s = mResourceData[index].getValue();
if (s != null) {
try {
return Integer.parseInt(s);
} catch (NumberFormatException e) {
- mContext.getLogger().warning(String.format(
- "Unable to convert \"%s\" into a integer in attribute \"%2$s\"",
- s, mNames[index]));
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+ String.format(
+ "\"%s\" in attribute \"%2$s\" cannont be converted to an integer.",
+ s, mNames[index]), null /*data*/);
// The default value is returned below.
}
@@ -384,11 +399,11 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public float getDimension(int index, float defValue) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return defValue;
}
- String s = mData[index].getValue();
+ String s = mResourceData[index].getValue();
if (s == null) {
return defValue;
@@ -397,16 +412,19 @@ public final class BridgeTypedArray extends TypedArray {
return LayoutParams.MATCH_PARENT;
} else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
return LayoutParams.WRAP_CONTENT;
+ } else if (RenderResources.REFERENCE_NULL.equals(s)) {
+ return defValue;
}
if (ResourceHelper.stringToFloat(s, mValue)) {
- return mValue.getDimension(mResources.mMetrics);
+ return mValue.getDimension(mBridgeResources.mMetrics);
}
// looks like we were unable to resolve the dimension value
- mContext.getLogger().warning(String.format(
- "Unable to resolve dimension value \"%1$s\" in attribute \"%2$s\"",
- s, mNames[index]));
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+ String.format(
+ "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
+ s, mNames[index]), null /*data*/);
return defValue;
}
@@ -453,11 +471,11 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getDimensionPixelSize(int index, int defValue) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return defValue;
}
- String s = mData[index].getValue();
+ String s = mResourceData[index].getValue();
if (s == null) {
return defValue;
@@ -466,18 +484,27 @@ public final class BridgeTypedArray extends TypedArray {
return LayoutParams.MATCH_PARENT;
} else if (s.equals(BridgeConstants.WRAP_CONTENT)) {
return LayoutParams.WRAP_CONTENT;
+ } else if (RenderResources.REFERENCE_NULL.equals(s)) {
+ return defValue;
}
- // FIXME huh?
+ if (ResourceHelper.stringToFloat(s, mValue)) {
+ float f = mValue.getDimension(mBridgeResources.mMetrics);
+
+ final int res = (int)(f+0.5f);
+ if (res != 0) return res;
+ if (f == 0) return 0;
+ if (f > 0) return 1;
+ return defValue; // this is basically unreachable.
+ }
- float f = getDimension(index, defValue);
- final int res = (int)(f+0.5f);
- if (res != 0) return res;
- if (f == 0) return 0;
- if (f > 0) return 1;
+ // looks like we were unable to resolve the dimension value
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+ String.format(
+ "\"%1$s\" in attribute \"%2$s\" is not a valid format.",
+ s, mNames[index]), null /*data*/);
- throw new UnsupportedOperationException("Can't convert to dimension: " +
- Integer.toString(index));
+ return defValue;
}
/**
@@ -519,11 +546,11 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public float getFraction(int index, int base, int pbase, float defValue) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return defValue;
}
- String value = mData[index].getValue();
+ String value = mResourceData[index].getValue();
if (value == null) {
return defValue;
}
@@ -533,9 +560,10 @@ public final class BridgeTypedArray extends TypedArray {
}
// looks like we were unable to resolve the fraction value
- mContext.getLogger().warning(String.format(
- "Unable to resolve fraction value \"%1$s\" in attribute \"%2$s\"",
- value, mNames[index]));
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+ String.format(
+ "\"%1$s\" in attribute \"%2$s\" cannont be converted to a fraction.",
+ value, mNames[index]), null /*data*/);
return defValue;
}
@@ -556,8 +584,8 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public int getResourceId(int index, int defValue) {
- // get the IResource for this index
- IResourceValue resValue = mData[index];
+ // get the Resource for this index
+ ResourceValue resValue = mResourceData[index];
// no data, return the default value.
if (resValue == null) {
@@ -565,24 +593,30 @@ public final class BridgeTypedArray extends TypedArray {
}
// check if this is a style resource
- if (resValue instanceof IStyleResourceValue) {
+ if (resValue instanceof StyleResourceValue) {
// get the id that will represent this style.
- return mContext.getDynamicIdByStyle((IStyleResourceValue)resValue);
+ return mContext.getDynamicIdByStyle((StyleResourceValue)resValue);
}
- // if the attribute was a reference to an id, and not a declaration of an id (@+id), then
- // the xml attribute value was "resolved" which leads us to a IResourceValue with
- // getType() returning "id" and getName() returning the id name
+ if (RenderResources.REFERENCE_NULL.equals(resValue.getValue())) {
+ return defValue;
+ }
+
+ // if the attribute was a reference to a resource, and not a declaration of an id (@+id),
+ // then the xml attribute value was "resolved" which leads us to a ResourceValue with a
+ // valid getType() and getName() returning a resource name.
// (and getValue() returning null!). We need to handle this!
- if (resValue.getType() != null && resValue.getType().equals(BridgeConstants.RES_ID)) {
+ if (resValue.getResourceType() != null) {
// if this is a framework id
if (mPlatformFile || resValue.isFramework()) {
// look for idName in the android R classes
- return mContext.getFrameworkIdValue(resValue.getName(), defValue);
+ return mContext.getFrameworkResourceValue(
+ resValue.getResourceType(), resValue.getName(), defValue);
}
// look for idName in the project R class.
- return mContext.getProjectIdValue(resValue.getName(), defValue);
+ return mContext.getProjectResourceValue(
+ resValue.getResourceType(), resValue.getName(), defValue);
}
// else, try to get the value, and resolve it somehow.
@@ -619,29 +653,33 @@ public final class BridgeTypedArray extends TypedArray {
// if this is a framework id
if (mPlatformFile || value.startsWith("@android") || value.startsWith("@+android")) {
// look for idName in the android R classes
- return mContext.getFrameworkIdValue(idName, defValue);
+ return mContext.getFrameworkResourceValue(ResourceType.ID, idName, defValue);
}
// look for idName in the project R class.
- return mContext.getProjectIdValue(idName, defValue);
+ return mContext.getProjectResourceValue(ResourceType.ID, idName, defValue);
}
// not a direct id valid reference? resolve it
Integer idValue = null;
if (resValue.isFramework()) {
- idValue = Bridge.getResourceValue(resValue.getType(), resValue.getName());
+ idValue = Bridge.getResourceId(resValue.getResourceType(),
+ resValue.getName());
} else {
- idValue = mContext.getProjectCallback().getResourceValue(
- resValue.getType(), resValue.getName());
+ idValue = mContext.getProjectCallback().getResourceId(
+ resValue.getResourceType(), resValue.getName());
}
if (idValue != null) {
return idValue.intValue();
}
- mContext.getLogger().warning(String.format(
- "Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index]));
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_RESOLVE,
+ String.format(
+ "Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index]),
+ resValue);
+
return defValue;
}
@@ -657,28 +695,17 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public Drawable getDrawable(int index) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return null;
}
- IResourceValue value = mData[index];
+ ResourceValue value = mResourceData[index];
String stringValue = value.getValue();
- if (stringValue == null || BridgeConstants.REFERENCE_NULL.equals(stringValue)) {
+ if (stringValue == null || RenderResources.REFERENCE_NULL.equals(stringValue)) {
return null;
}
- Drawable d = ResourceHelper.getDrawable(value, mContext, mData[index].isFramework());
-
- if (d != null) {
- return d;
- }
-
- // looks like we were unable to resolve the drawable
- mContext.getLogger().warning(String.format(
- "Unable to resolve drawable \"%1$s\" in attribute \"%2$s\"", stringValue,
- mNames[index]));
-
- return null;
+ return ResourceHelper.getDrawable(value, mContext);
}
@@ -694,18 +721,23 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public CharSequence[] getTextArray(int index) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return null;
}
- String value = mData[index].getValue();
+ String value = mResourceData[index].getValue();
if (value != null) {
+ if (RenderResources.REFERENCE_NULL.equals(value)) {
+ return null;
+ }
+
return new CharSequence[] { value };
}
- mContext.getLogger().warning(String.format(
- String.format("Unknown value for getTextArray(%d) => %s", //DEBUG
- index, mData[index].getName())));
+ Bridge.getLog().warning(LayoutLog.TAG_RESOURCES_FORMAT,
+ String.format(
+ String.format("Unknown value for getTextArray(%d) => %s", //DEBUG
+ index, mResourceData[index].getName())), null /*data*/);
return null;
}
@@ -721,11 +753,11 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public boolean getValue(int index, TypedValue outValue) {
- if (mData[index] == null) {
+ if (mResourceData[index] == null) {
return false;
}
- String s = mData[index].getValue();
+ String s = mResourceData[index].getValue();
return ResourceHelper.stringToFloat(s, outValue);
}
@@ -739,7 +771,7 @@ public final class BridgeTypedArray extends TypedArray {
*/
@Override
public boolean hasValue(int index) {
- return mData[index] != null;
+ return mResourceData[index] != null;
}
/**
@@ -786,6 +818,6 @@ public final class BridgeTypedArray extends TypedArray {
@Override
public String toString() {
- return mData.toString();
+ return Arrays.toString(mResourceData);
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
new file mode 100644
index 0000000..0efa102
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindow.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.android;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.ParcelFileDescriptor;
+import android.os.RemoteException;
+import android.view.IWindow;
+import android.view.KeyEvent;
+import android.view.MotionEvent;
+import android.view.View.AttachInfo;
+
+/**
+ * Implementation of {@link IWindow} to pass to the {@link AttachInfo}.
+ */
+public final class BridgeWindow implements IWindow {
+
+ public void dispatchAppVisibility(boolean arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public void dispatchGetNewSurface() throws RemoteException {
+ // pass for now.
+ }
+
+ public void dispatchKey(KeyEvent arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public void dispatchPointer(MotionEvent arg0, long arg1, boolean arg2) throws RemoteException {
+ // pass for now.
+ }
+
+ public void dispatchTrackball(MotionEvent arg0, long arg1, boolean arg2)
+ throws RemoteException {
+ // pass for now.
+ }
+
+ public void executeCommand(String arg0, String arg1, ParcelFileDescriptor arg2)
+ throws RemoteException {
+ // pass for now.
+ }
+
+ public void resized(int arg0, int arg1, Rect arg2, Rect arg3, boolean arg4, Configuration arg5)
+ throws RemoteException {
+ // pass for now.
+ }
+
+ public void windowFocusChanged(boolean arg0, boolean arg1) throws RemoteException {
+ // pass for now.
+ }
+
+ public void dispatchWallpaperOffsets(float x, float y, float xStep, float yStep,
+ boolean sync) {
+ // pass for now.
+ }
+
+ public void dispatchWallpaperCommand(String action, int x, int y,
+ int z, Bundle extras, boolean sync) {
+ // pass for now.
+ }
+
+ public void closeSystemDialogs(String reason) {
+ // pass for now.
+ }
+
+ public void dispatchSystemUiVisibilityChanged(int visibility) {
+ // pass for now.
+ }
+
+ public IBinder asBinder() {
+ // pass for now.
+ return null;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
new file mode 100644
index 0000000..7866bfa
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeWindowSession.java
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.android;
+
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.graphics.Region;
+import android.os.Bundle;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.view.IWindow;
+import android.view.IWindowSession;
+import android.view.InputChannel;
+import android.view.Surface;
+import android.view.SurfaceView;
+import android.view.WindowManager.LayoutParams;
+
+/**
+ * Implementation of {@link IWindowSession} so that mSession is not null in
+ * the {@link SurfaceView}.
+ */
+public final class BridgeWindowSession implements IWindowSession {
+
+ public int add(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3,
+ InputChannel outInputchannel)
+ throws RemoteException {
+ // pass for now.
+ return 0;
+ }
+
+ public int addWithoutInputChannel(IWindow arg0, LayoutParams arg1, int arg2, Rect arg3)
+ throws RemoteException {
+ // pass for now.
+ return 0;
+ }
+
+ public void finishDrawing(IWindow arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public boolean getInTouchMode() throws RemoteException {
+ // pass for now.
+ return false;
+ }
+
+ public boolean performHapticFeedback(IWindow window, int effectId, boolean always) {
+ // pass for now.
+ return false;
+ }
+
+ public int relayout(IWindow arg0, LayoutParams arg1, int arg2, int arg3, int arg4,
+ boolean arg4_5, Rect arg5, Rect arg6, Rect arg7, Configuration arg7b, Surface arg8)
+ throws RemoteException {
+ // pass for now.
+ return 0;
+ }
+
+ public void getDisplayFrame(IWindow window, Rect outDisplayFrame) {
+ // pass for now.
+ }
+
+ public void remove(IWindow arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public void setInTouchMode(boolean arg0) throws RemoteException {
+ // pass for now.
+ }
+
+ public void setTransparentRegion(IWindow arg0, Region arg1) throws RemoteException {
+ // pass for now.
+ }
+
+ public void setWallpaperPosition(IBinder window, float x, float y,
+ float xStep, float yStep) {
+ // pass for now.
+ }
+
+ public void wallpaperOffsetsComplete(IBinder window) {
+ // pass for now.
+ }
+
+ public Bundle sendWallpaperCommand(IBinder window, String action, int x, int y,
+ int z, Bundle extras, boolean sync) {
+ // pass for now.
+ return null;
+ }
+
+ public void wallpaperCommandComplete(IBinder window, Bundle result) {
+ // pass for now.
+ }
+
+ public IBinder asBinder() {
+ // pass for now.
+ return null;
+ }
+
+ public void setInsets(IWindow arg0, int arg1, Rect arg2, Rect arg3) throws RemoteException {
+ // TODO Auto-generated method stub
+
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
index d842a66..2f54ae6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlBlockParser.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParser.java
@@ -14,9 +14,10 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
-import com.android.layoutlib.api.IXmlPullParser;
+
+import com.android.ide.common.rendering.api.ILayoutPullParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -36,14 +37,15 @@ import java.io.Reader;
*/
public class BridgeXmlBlockParser implements XmlResourceParser {
- private XmlPullParser mParser;
- private XmlPullAttributes mAttrib;
+ private final XmlPullParser mParser;
+ private final XmlPullAttributes mAttrib;
+ private final BridgeContext mContext;
+ private final boolean mPlatformFile;
private boolean mStarted = false;
- private boolean mDecNextDepth = false;
- private int mDepth = 0;
private int mEventType = START_DOCUMENT;
- private final boolean mPlatformFile;
+
+ private boolean mPopped = true; // default to true in case it's not pushed.
/**
* Builds a {@link BridgeXmlBlockParser}.
@@ -53,25 +55,45 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
*/
public BridgeXmlBlockParser(XmlPullParser parser, BridgeContext context, boolean platformFile) {
mParser = parser;
+ mContext = context;
mPlatformFile = platformFile;
mAttrib = new BridgeXmlPullAttributes(parser, context, mPlatformFile);
+
+ if (mContext != null) {
+ mContext.pushParser(this);
+ mPopped = false;
+ }
}
-
+
public boolean isPlatformFile() {
return mPlatformFile;
}
- public Object getViewKey() {
- if (mParser instanceof IXmlPullParser) {
- return ((IXmlPullParser)mParser).getViewKey();
+ public ILayoutPullParser getParser(String layoutName) {
+ if (mParser instanceof ILayoutPullParser) {
+ return ((ILayoutPullParser)mParser).getParser(layoutName);
+ }
+
+ return null;
+ }
+
+ public Object getViewCookie() {
+ if (mParser instanceof ILayoutPullParser) {
+ return ((ILayoutPullParser)mParser).getViewCookie();
}
return null;
}
-
-
+
+ public void ensurePopped() {
+ if (mContext != null && mPopped == false) {
+ mContext.popParser();
+ mPopped = true;
+ }
+ }
+
// ------- XmlResourceParser implementation
-
+
public void setFeature(String name, boolean state)
throws XmlPullParserException {
if (FEATURE_PROCESS_NAMESPACES.equals(name) && state) {
@@ -145,7 +167,7 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
}
public int getDepth() {
- return mDepth;
+ return mParser.getDepth();
}
public String getText() {
@@ -236,17 +258,10 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
return START_DOCUMENT;
}
int ev = mParser.next();
- if (mDecNextDepth) {
- mDepth--;
- mDecNextDepth = false;
- }
- switch (ev) {
- case START_TAG:
- mDepth++;
- break;
- case END_TAG:
- mDecNextDepth = true;
- break;
+
+ if (ev == END_TAG && mParser.getDepth() == 1) {
+ // done with parser remove it from the context stack.
+ ensurePopped();
}
mEventType = ev;
return ev;
@@ -301,7 +316,7 @@ public class BridgeXmlBlockParser implements XmlResourceParser {
// AttributeSet implementation
-
+
public void close() {
// pass
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlPullAttributes.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
index d145ff6..ba856e0 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeXmlPullAttributes.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeXmlPullAttributes.java
@@ -14,9 +14,13 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
-import com.android.layoutlib.api.IResourceValue;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.resources.ResourceType;
import org.xmlpull.v1.XmlPullParser;
@@ -55,7 +59,7 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
String ns = mParser.getAttributeNamespace(index);
if (BridgeConstants.NS_RESOURCES.equals(ns)) {
- Integer v = Bridge.getResourceValue(BridgeConstants.RES_ATTR, name);
+ Integer v = Bridge.getResourceId(ResourceType.ATTR, name);
if (v != null) {
return v.intValue();
}
@@ -66,8 +70,7 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
// this is not an attribute in the android namespace, we query the customviewloader, if
// the namespaces match.
if (mContext.getProjectCallback().getNamespace().equals(ns)) {
- Integer v = mContext.getProjectCallback().getResourceValue(BridgeConstants.RES_ATTR,
- name);
+ Integer v = mContext.getProjectCallback().getResourceId(ResourceType.ATTR, name);
if (v != null) {
return v.intValue();
}
@@ -100,16 +103,17 @@ public class BridgeXmlPullAttributes extends XmlPullAttributes {
private int resolveResourceValue(String value, int defaultValue) {
// now look for this particular value
- IResourceValue resource = mContext.resolveResValue(
- mContext.findResValue(value, mPlatformFile));
+ RenderResources resources = mContext.getRenderResources();
+ ResourceValue resource = resources.resolveResValue(
+ resources.findResValue(value, mPlatformFile));
if (resource != null) {
Integer id = null;
if (mPlatformFile || resource.isFramework()) {
- id = Bridge.getResourceValue(resource.getType(), resource.getName());
+ id = Bridge.getResourceId(resource.getResourceType(), resource.getName());
} else {
- id = mContext.getProjectCallback().getResourceValue(
- resource.getType(), resource.getName());
+ id = mContext.getProjectCallback().getResourceId(
+ resource.getResourceType(), resource.getName());
}
if (id != null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
new file mode 100644
index 0000000..0c4b0d3
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -0,0 +1,263 @@
+/*
+ * 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.layoutlib.bridge.bars;
+
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.impl.ResourceHelper;
+import com.android.resources.Density;
+import com.android.resources.ResourceType;
+
+import org.kxml2.io.KXmlParser;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.content.res.ColorStateList;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.TypedValue;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Base "bar" class for the window decor around the the edited layout.
+ * This is basically an horizontal layout that loads a given layout on creation (it is read
+ * through {@link Class#getResourceAsStream(String)}).
+ *
+ * The given layout should be a merge layout so that all the children belong to this class directly.
+ *
+ * It also provides a few utility methods to configure the content of the layout.
+ */
+abstract class CustomBar extends LinearLayout {
+
+ protected abstract TextView getStyleableTextView();
+
+ protected CustomBar(Context context, Density density, String layoutPath)
+ throws XmlPullParserException {
+ super(context);
+ setOrientation(LinearLayout.HORIZONTAL);
+ setGravity(Gravity.CENTER_VERTICAL);
+
+ LayoutInflater inflater = (LayoutInflater) getContext().getSystemService(
+ Context.LAYOUT_INFLATER_SERVICE);
+
+ KXmlParser parser = new KXmlParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ parser.setInput(
+ getClass().getResourceAsStream(layoutPath),
+ "UTF8");
+
+ BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
+ parser, (BridgeContext) context, false /*platformFile*/);
+
+ try {
+ inflater.inflate(bridgeParser, this, true);
+ } finally {
+ bridgeParser.ensurePopped();
+ }
+ }
+
+ private InputStream getIcon(String iconName, Density[] densityInOut, String[] pathOut,
+ boolean tryOtherDensities) {
+ // current density
+ Density density = densityInOut[0];
+
+ // bitmap url relative to this class
+ pathOut[0] = "/bars/" + density.getResourceValue() + "/" + iconName;
+
+ InputStream stream = getClass().getResourceAsStream(pathOut[0]);
+ if (stream == null && tryOtherDensities) {
+ for (Density d : Density.values()) {
+ if (d != density) {
+ densityInOut[0] = d;
+ stream = getIcon(iconName, densityInOut, pathOut, false /*tryOtherDensities*/);
+ if (stream != null) {
+ return stream;
+ }
+ }
+ }
+ }
+
+ return stream;
+ }
+
+ protected void loadIcon(int index, String iconName, Density density) {
+ View child = getChildAt(index);
+ if (child instanceof ImageView) {
+ ImageView imageView = (ImageView) child;
+
+ String[] pathOut = new String[1];
+ Density[] densityInOut = new Density[] { density };
+ InputStream stream = getIcon(iconName, densityInOut, pathOut,
+ true /*tryOtherDensities*/);
+ density = densityInOut[0];
+
+ if (stream != null) {
+ // look for a cached bitmap
+ Bitmap bitmap = Bridge.getCachedBitmap(pathOut[0], true /*isFramework*/);
+ if (bitmap == null) {
+ try {
+ bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
+ Bridge.setCachedBitmap(pathOut[0], bitmap, true /*isFramework*/);
+ } catch (IOException e) {
+ return;
+ }
+ }
+
+ if (bitmap != null) {
+ BitmapDrawable drawable = new BitmapDrawable(getContext().getResources(),
+ bitmap);
+ imageView.setBackgroundDrawable(drawable);
+ }
+ }
+ }
+ }
+
+ protected void loadIcon(int index, String iconReference) {
+ ResourceValue value = getResourceValue(iconReference);
+ if (value != null) {
+ loadIcon(index, value);
+ }
+ }
+
+ protected Drawable loadIcon(int index, ResourceType type, String name) {
+ BridgeContext bridgeContext = (BridgeContext) mContext;
+ RenderResources res = bridgeContext.getRenderResources();
+
+ // find the resource
+ ResourceValue value = res.getFrameworkResource(type, name);
+
+ // resolve it if needed
+ value = res.resolveResValue(value);
+ return loadIcon(index, value);
+ }
+
+ private Drawable loadIcon(int index, ResourceValue value) {
+ View child = getChildAt(index);
+ if (child instanceof ImageView) {
+ ImageView imageView = (ImageView) child;
+
+ Drawable drawable = ResourceHelper.getDrawable(
+ value, (BridgeContext) mContext);
+ if (drawable != null) {
+ imageView.setBackgroundDrawable(drawable);
+ }
+
+ return drawable;
+ }
+
+ return null;
+ }
+
+ protected TextView setText(int index, String stringReference) {
+ View child = getChildAt(index);
+ if (child instanceof TextView) {
+ TextView textView = (TextView) child;
+ ResourceValue value = getResourceValue(stringReference);
+ if (value != null) {
+ textView.setText(value.getValue());
+ } else {
+ textView.setText(stringReference);
+ }
+ return textView;
+ }
+
+ return null;
+ }
+
+ protected void setStyle(String themeEntryName) {
+
+ BridgeContext bridgeContext = (BridgeContext) mContext;
+ RenderResources res = bridgeContext.getRenderResources();
+
+ ResourceValue value = res.findItemInTheme(themeEntryName);
+ value = res.resolveResValue(value);
+
+ if (value instanceof StyleResourceValue == false) {
+ return;
+ }
+
+ StyleResourceValue style = (StyleResourceValue) value;
+
+ // get the background
+ ResourceValue backgroundValue = res.findItemInStyle(style, "background");
+ backgroundValue = res.resolveResValue(backgroundValue);
+ if (backgroundValue != null) {
+ Drawable d = ResourceHelper.getDrawable(backgroundValue, bridgeContext);
+ if (d != null) {
+ setBackgroundDrawable(d);
+ }
+ }
+
+ TextView textView = getStyleableTextView();
+ if (textView != null) {
+ // get the text style
+ ResourceValue textStyleValue = res.findItemInStyle(style, "titleTextStyle");
+ textStyleValue = res.resolveResValue(textStyleValue);
+ if (textStyleValue instanceof StyleResourceValue) {
+ StyleResourceValue textStyle = (StyleResourceValue) textStyleValue;
+
+ ResourceValue textSize = res.findItemInStyle(textStyle, "textSize");
+ textSize = res.resolveResValue(textSize);
+
+ if (textSize != null) {
+ TypedValue out = new TypedValue();
+ if (ResourceHelper.stringToFloat(textSize.getValue(), out)) {
+ textView.setTextSize(
+ out.getDimension(bridgeContext.getResources().mMetrics));
+ }
+ }
+
+
+ ResourceValue textColor = res.findItemInStyle(textStyle, "textColor");
+ textColor = res.resolveResValue(textColor);
+ if (textColor != null) {
+ ColorStateList stateList = ResourceHelper.getColorStateList(
+ textColor, bridgeContext);
+ if (stateList != null) {
+ textView.setTextColor(stateList);
+ }
+ }
+ }
+ }
+ }
+
+ private ResourceValue getResourceValue(String reference) {
+ BridgeContext bridgeContext = (BridgeContext) mContext;
+ RenderResources res = bridgeContext.getRenderResources();
+
+ // find the resource
+ ResourceValue value = res.findResValue(reference, false /*isFramework*/);
+
+ // resolve it if needed
+ return res.resolveResValue(value);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
new file mode 100644
index 0000000..5507ef9
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
@@ -0,0 +1,53 @@
+/*
+ * 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.layoutlib.bridge.bars;
+
+import com.android.resources.Density;
+import com.android.resources.ResourceType;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.LevelListDrawable;
+import android.view.Gravity;
+import android.widget.TextView;
+
+public class PhoneSystemBar extends CustomBar {
+
+ public PhoneSystemBar(Context context, Density density) throws XmlPullParserException {
+ super(context, density, "/bars/phone_system_bar.xml");
+
+ setGravity(mGravity | Gravity.RIGHT);
+ setBackgroundColor(0xFF000000);
+
+ // Cannot access the inside items through id because no R.id values have been
+ // created for them.
+ // We do know the order though.
+ // 0 is the spacer.
+ loadIcon(1, "stat_sys_wifi_signal_4_fully.png", density);
+ Drawable drawable = loadIcon(2, ResourceType.DRAWABLE, "stat_sys_battery_charge");
+ if (drawable instanceof LevelListDrawable) {
+ ((LevelListDrawable) drawable).setLevel(100);
+ }
+ }
+
+ @Override
+ protected TextView getStyleableTextView() {
+ return null;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
new file mode 100644
index 0000000..d7401d9
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/TitleBar.java
@@ -0,0 +1,46 @@
+/*
+ * 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.layoutlib.bridge.bars;
+
+import com.android.resources.Density;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.content.Context;
+import android.widget.TextView;
+
+public class TitleBar extends CustomBar {
+
+ private TextView mTextView;
+
+ public TitleBar(Context context, Density density, String label)
+ throws XmlPullParserException {
+ super(context, density, "/bars/title_bar.xml");
+
+ // Cannot access the inside items through id because no R.id values have been
+ // created for them.
+ // We do know the order though.
+ mTextView = setText(0, label);
+
+ setStyle("windowTitleBackgroundStyle");
+ }
+
+ @Override
+ protected TextView getStyleableTextView() {
+ return mTextView;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
new file mode 100644
index 0000000..ae1217d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.impl;
+
+import com.android.layoutlib.bridge.util.Debug;
+import com.android.layoutlib.bridge.util.SparseWeakArray;
+
+import android.util.SparseArray;
+
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Manages native delegates.
+ *
+ * This is used in conjunction with layoublib_create: certain Android java classes are mere
+ * wrappers around a heavily native based implementation, and we need a way to run these classes
+ * in our Eclipse rendering framework without bringing all the native code from the Android
+ * platform.
+ *
+ * Thus we instruct layoutlib_create to modify the bytecode of these classes to replace their
+ * native methods by "delegate calls".
+ *
+ * For example, a native method android.graphics.Matrix.init(...) will actually become
+ * a call to android.graphics.Matrix_Delegate.init(...).
+ *
+ * The Android java classes that use native code uses an int (Java side) to reference native
+ * objects. This int is generally directly the pointer to the C structure counterpart.
+ * Typically a creation method will return such an int, and then this int will be passed later
+ * to a Java method to identify the C object to manipulate.
+ *
+ * Since we cannot use the Java object reference as the int directly, DelegateManager manages the
+ * int -> Delegate class link.
+ *
+ * Native methods usually always have the int as parameters. The first thing the delegate method
+ * will do is call {@link #getDelegate(int)} to get the Java object matching the int.
+ *
+ * Typical native init methods are returning a new int back to the Java class, so
+ * {@link #addNewDelegate(Object)} does the same.
+ *
+ * The JNI references are counted, so we do the same through a {@link WeakReference}. Because
+ * the Java object needs to count as a reference (even though it only holds an int), we use the
+ * following mechanism:
+ *
+ * - {@link #addNewDelegate(Object)} and {@link #removeJavaReferenceFor(int)} adds and removes
+ * the delegate to/from a list. This list hold the reference and prevents the GC from reclaiming
+ * the delegate.
+ *
+ * - {@link #addNewDelegate(Object)} also adds the delegate to a {@link SparseArray} that holds a
+ * {@link WeakReference} to the delegate. This allows the delegate to be deleted automatically
+ * when nothing references it. This means that any class that holds a delegate (except for the
+ * Java main class) must not use the int but the Delegate class instead. The integers must
+ * only be used in the API between the main Java class and the Delegate.
+ *
+ * @param <T> the delegate class to manage
+ */
+public final class DelegateManager<T> {
+ private final Class<T> mClass;
+ private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>();
+ /** list used to store delegates when their main object holds a reference to them.
+ * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed
+ * @see #addNewDelegate(Object)
+ * @see #removeJavaReferenceFor(int)
+ */
+ private final List<T> mJavaReferences = new ArrayList<T>();
+ private int mDelegateCounter = 0;
+
+ public DelegateManager(Class<T> theClass) {
+ mClass = theClass;
+ }
+
+ /**
+ * Returns the delegate from the given native int.
+ * <p>
+ * If the int is zero, then this will always return null.
+ * <p>
+ * If the int is non zero and the delegate is not found, this will throw an assert.
+ *
+ * @param native_object the native int.
+ * @return the delegate or null if not found.
+ */
+ public T getDelegate(int native_object) {
+ if (native_object > 0) {
+ T delegate = mDelegates.get(native_object);
+
+ if (Debug.DEBUG) {
+ if (delegate == null) {
+ System.out.println("Unknown " + mClass.getSimpleName() + " with int " +
+ native_object);
+ }
+ }
+
+ assert delegate != null;
+ return delegate;
+ }
+ return null;
+ }
+
+ /**
+ * Adds a delegate to the manager and returns the native int used to identify it.
+ * @param newDelegate the delegate to add
+ * @return a unique native int to identify the delegate
+ */
+ public int addNewDelegate(T newDelegate) {
+ int native_object = ++mDelegateCounter;
+ mDelegates.put(native_object, newDelegate);
+ assert !mJavaReferences.contains(newDelegate);
+ mJavaReferences.add(newDelegate);
+
+ if (Debug.DEBUG) {
+ System.out.println("New " + mClass.getSimpleName() + " with int " + native_object);
+ }
+
+ return native_object;
+ }
+
+ /**
+ * Removes the main reference on the given delegate.
+ * @param native_object the native integer representing the delegate.
+ */
+ public void removeJavaReferenceFor(int native_object) {
+ T delegate = getDelegate(native_object);
+
+ if (Debug.DEBUG) {
+ System.out.println("Removing main Java ref on " + mClass.getSimpleName() +
+ " with int " + native_object);
+ }
+
+ mJavaReferences.remove(delegate);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
index 801503b..f62fad2 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/FontLoader.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/FontLoader.java
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.impl;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
@@ -134,6 +134,15 @@ public final class FontLoader {
return mFallBackFonts;
}
+ /**
+ * Returns a {@link Font} object given a family name and a style value (constant in
+ * {@link Typeface}).
+ * @param family the family name
+ * @param style a 1-item array containing the requested style. Based on the font being read
+ * the actual style may be different. The array contains the actual style after
+ * the method returns.
+ * @return the font object or null if no match could be found.
+ */
public synchronized Font getFont(String family, int[] style) {
if (family == null) {
return null;
@@ -154,7 +163,7 @@ public final class FontLoader {
mTtfToFontMap.put(ttf, styleMap);
}
- Font f = styleMap.get(style);
+ Font f = styleMap.get(style[0]);
if (f != null) {
return f;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
new file mode 100644
index 0000000..2abe56c
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java
@@ -0,0 +1,806 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.impl;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+
+import android.graphics.Bitmap_Delegate;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.graphics.Paint_Delegate;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.graphics.Region;
+import android.graphics.Region_Delegate;
+import android.graphics.Shader_Delegate;
+import android.graphics.Xfermode_Delegate;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Area;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+
+/**
+ * Class representing a graphics context snapshot, as well as a context stack as a linked list.
+ * <p>
+ * This is based on top of {@link Graphics2D} but can operate independently if none are available
+ * yet when setting transforms and clip information.
+ * <p>
+ * This allows for drawing through {@link #draw(Drawable, Paint_Delegate)} and
+ * {@link #draw(Drawable, Paint_Delegate)}
+ *
+ * Handling of layers (created with {@link Canvas#saveLayer(RectF, Paint, int)}) is handled through
+ * a list of Graphics2D for each layers. The class actually maintains a list of {@link Layer}
+ * for each layer. Doing a save() will duplicate this list so that each graphics2D object
+ * ({@link Layer#getGraphics()}) is configured only for the new snapshot.
+ */
+public class GcSnapshot {
+
+ private final GcSnapshot mPrevious;
+ private final int mFlags;
+
+ /** list of layers. The first item in the list is always the */
+ private final ArrayList<Layer> mLayers = new ArrayList<Layer>();
+
+ /** temp transform in case transformation are set before a Graphics2D exists */
+ private AffineTransform mTransform = null;
+ /** temp clip in case clipping is set before a Graphics2D exists */
+ private Area mClip = null;
+
+ // local layer data
+ /** a local layer created with {@link Canvas#saveLayer(RectF, Paint, int)}.
+ * If this is null, this does not mean there's no layer, just that the snapshot is not the
+ * one that created the layer.
+ * @see #getLayerSnapshot()
+ */
+ private final Layer mLocalLayer;
+ private final Paint_Delegate mLocalLayerPaint;
+ private final Rect mLayerBounds;
+
+ public interface Drawable {
+ void draw(Graphics2D graphics, Paint_Delegate paint);
+ }
+
+ /**
+ * Class containing information about a layer.
+ *
+ * This contains graphics, bitmap and layer information.
+ */
+ private static class Layer {
+ private final Graphics2D mGraphics;
+ private final Bitmap_Delegate mBitmap;
+ private final BufferedImage mImage;
+ /** the flags that were used to configure the layer. This is never changed, and passed
+ * as is when {@link #makeCopy()} is called */
+ private final int mFlags;
+ /** the original content of the layer when the next object was created. This is not
+ * passed in {@link #makeCopy()} and instead is recreated when a new layer is added
+ * (depending on its flags) */
+ private BufferedImage mOriginalCopy;
+
+ /**
+ * Creates a layer with a graphics and a bitmap. This is only used to create
+ * the base layer.
+ *
+ * @param graphics the graphics
+ * @param bitmap the bitmap
+ */
+ Layer(Graphics2D graphics, Bitmap_Delegate bitmap) {
+ mGraphics = graphics;
+ mBitmap = bitmap;
+ mImage = mBitmap.getImage();
+ mFlags = 0;
+ }
+
+ /**
+ * Creates a layer with a graphics and an image. If the image belongs to a
+ * {@link Bitmap_Delegate} (case of the base layer), then
+ * {@link Layer#Layer(Graphics2D, Bitmap_Delegate)} should be used.
+ *
+ * @param graphics the graphics the new graphics for this layer
+ * @param image the image the image from which the graphics came
+ * @param flags the flags that were used to save this layer
+ */
+ Layer(Graphics2D graphics, BufferedImage image, int flags) {
+ mGraphics = graphics;
+ mBitmap = null;
+ mImage = image;
+ mFlags = flags;
+ }
+
+ /** The Graphics2D, guaranteed to be non null */
+ Graphics2D getGraphics() {
+ return mGraphics;
+ }
+
+ /** The BufferedImage, guaranteed to be non null */
+ BufferedImage getImage() {
+ return mImage;
+ }
+
+ /** Returns the layer save flags. This is only valid for additional layers.
+ * For the base layer this will always return 0;
+ * For a given layer, all further copies of this {@link Layer} object in new snapshots
+ * will always return the same value.
+ */
+ int getFlags() {
+ return mFlags;
+ }
+
+ Layer makeCopy() {
+ if (mBitmap != null) {
+ return new Layer((Graphics2D) mGraphics.create(), mBitmap);
+ }
+
+ return new Layer((Graphics2D) mGraphics.create(), mImage, mFlags);
+ }
+
+ /** sets an optional copy of the original content to be used during restore */
+ void setOriginalCopy(BufferedImage image) {
+ mOriginalCopy = image;
+ }
+
+ BufferedImage getOriginalCopy() {
+ return mOriginalCopy;
+ }
+
+ /**
+ * Sets the clip for the graphics2D object associated with the layer.
+ * This should be used over the normal Graphics2D setClip method.
+ *
+ * @param clipShape the shape to use a the clip shape.
+ */
+ void setClip(Shape clipShape) {
+ // because setClip is only guaranteed to work with rectangle shape,
+ // first reset the clip to max and then intersect the current (empty)
+ // clip with the shap.
+ mGraphics.setClip(null);
+ mGraphics.clip(clipShape);
+ }
+
+ /**
+ * Clips the layer with the given shape. This performs an intersect between the current
+ * clip shape and the given shape.
+ * @param shape the new clip shape.
+ */
+ public void clip(Shape shape) {
+ mGraphics.clip(shape);
+ }
+ }
+
+ /**
+ * Creates the root snapshot associating it with a given bitmap.
+ * <p>
+ * If <var>bitmap</var> is null, then {@link GcSnapshot#setBitmap(Bitmap_Delegate)} must be
+ * called before the snapshot can be used to draw. Transform and clip operations are permitted
+ * before.
+ *
+ * @param image the image to associate to the snapshot or null.
+ * @return the root snapshot
+ */
+ public static GcSnapshot createDefaultSnapshot(Bitmap_Delegate bitmap) {
+ GcSnapshot snapshot = new GcSnapshot();
+ if (bitmap != null) {
+ snapshot.setBitmap(bitmap);
+ }
+
+ return snapshot;
+ }
+
+ /**
+ * Saves the current state according to the given flags and returns the new current snapshot.
+ * <p/>
+ * This is the equivalent of {@link Canvas#save(int)}
+ *
+ * @param flags the save flags.
+ * @return the new snapshot
+ *
+ * @see Canvas#save(int)
+ */
+ public GcSnapshot save(int flags) {
+ return new GcSnapshot(this, null /*layerbounds*/, null /*paint*/, flags);
+ }
+
+ /**
+ * Saves the current state and creates a new layer, and returns the new current snapshot.
+ * <p/>
+ * This is the equivalent of {@link Canvas#saveLayer(RectF, Paint, int)}
+ *
+ * @param layerBounds the layer bounds
+ * @param paint the Paint information used to blit the layer back into the layers underneath
+ * upon restore
+ * @param flags the save flags.
+ * @return the new snapshot
+ *
+ * @see Canvas#saveLayer(RectF, Paint, int)
+ */
+ public GcSnapshot saveLayer(RectF layerBounds, Paint_Delegate paint, int flags) {
+ return new GcSnapshot(this, layerBounds, paint, flags);
+ }
+
+ /**
+ * Creates the root snapshot.
+ * {@link #setGraphics2D(Graphics2D)} will have to be called on it when possible.
+ */
+ private GcSnapshot() {
+ mPrevious = null;
+ mFlags = 0;
+ mLocalLayer = null;
+ mLocalLayerPaint = null;
+ mLayerBounds = null;
+ }
+
+ /**
+ * Creates a new {@link GcSnapshot} on top of another one, with a layer data to be restored
+ * into the main graphics when {@link #restore()} is called.
+ *
+ * @param previous the previous snapshot head.
+ * @param layerBounds the region of the layer. Optional, if null, this is a normal save()
+ * @param paint the Paint information used to blit the layer back into the layers underneath
+ * upon restore
+ * @param flags the flags regarding what should be saved.
+ */
+ private GcSnapshot(GcSnapshot previous, RectF layerBounds, Paint_Delegate paint, int flags) {
+ assert previous != null;
+ mPrevious = previous;
+ mFlags = flags;
+
+ // make a copy of the current layers before adding the new one.
+ // This keeps the same BufferedImage reference but creates new Graphics2D for this
+ // snapshot.
+ // It does not copy whatever original copy the layers have, as they will be done
+ // only if the new layer doesn't clip drawing to itself.
+ for (Layer layer : mPrevious.mLayers) {
+ mLayers.add(layer.makeCopy());
+ }
+
+ if (layerBounds != null) {
+ // get the current transform
+ AffineTransform matrix = mLayers.get(0).getGraphics().getTransform();
+
+ // transform the layerBounds with the current transform and stores it into a int rect
+ RectF rect2 = new RectF();
+ mapRect(matrix, rect2, layerBounds);
+ mLayerBounds = new Rect();
+ rect2.round(mLayerBounds);
+
+ // get the base layer (always at index 0)
+ Layer baseLayer = mLayers.get(0);
+
+ // create the image for the layer
+ BufferedImage layerImage = new BufferedImage(
+ baseLayer.getImage().getWidth(),
+ baseLayer.getImage().getHeight(),
+ (mFlags & Canvas.HAS_ALPHA_LAYER_SAVE_FLAG) != 0 ?
+ BufferedImage.TYPE_INT_ARGB :
+ BufferedImage.TYPE_INT_RGB);
+
+ // create a graphics for it so that drawing can be done.
+ Graphics2D layerGraphics = layerImage.createGraphics();
+
+ // because this layer inherits the current context for transform and clip,
+ // set them to one from the base layer.
+ AffineTransform currentMtx = baseLayer.getGraphics().getTransform();
+ layerGraphics.setTransform(currentMtx);
+
+ // create a new layer for this new layer and add it to the list at the end.
+ mLayers.add(mLocalLayer = new Layer(layerGraphics, layerImage, flags));
+
+ // set the clip on it.
+ Shape currentClip = baseLayer.getGraphics().getClip();
+ mLocalLayer.setClip(currentClip);
+
+ // if the drawing is not clipped to the local layer only, we save the current content
+ // of all other layers. We are only interested in the part that will actually
+ // be drawn, so we create as small bitmaps as we can.
+ // This is so that we can erase the drawing that goes in the layers below that will
+ // be coming from the layer itself.
+ if ((mFlags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0) {
+ int w = mLayerBounds.width();
+ int h = mLayerBounds.height();
+ for (int i = 0 ; i < mLayers.size() - 1 ; i++) {
+ Layer layer = mLayers.get(i);
+ BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D graphics = image.createGraphics();
+ graphics.drawImage(layer.getImage(),
+ 0, 0, w, h,
+ mLayerBounds.left, mLayerBounds.top,
+ mLayerBounds.right, mLayerBounds.bottom,
+ null);
+ graphics.dispose();
+ layer.setOriginalCopy(image);
+ }
+ }
+ } else {
+ mLocalLayer = null;
+ mLayerBounds = null;
+ }
+
+ mLocalLayerPaint = paint;
+ }
+
+ public void dispose() {
+ for (Layer layer : mLayers) {
+ layer.getGraphics().dispose();
+ }
+
+ if (mPrevious != null) {
+ mPrevious.dispose();
+ }
+ }
+
+ /**
+ * Restores the top {@link GcSnapshot}, and returns the next one.
+ */
+ public GcSnapshot restore() {
+ return doRestore();
+ }
+
+ /**
+ * Restores the {@link GcSnapshot} to <var>saveCount</var>.
+ * @param saveCount the saveCount or -1 to only restore 1.
+ *
+ * @return the new head of the Gc snapshot stack.
+ */
+ public GcSnapshot restoreTo(int saveCount) {
+ return doRestoreTo(size(), saveCount);
+ }
+
+ public int size() {
+ if (mPrevious != null) {
+ return mPrevious.size() + 1;
+ }
+
+ return 1;
+ }
+
+ /**
+ * Link the snapshot to a Bitmap_Delegate.
+ * <p/>
+ * This is only for the case where the snapshot was created with a null image when calling
+ * {@link #createDefaultSnapshot(Bitmap_Delegate)}, and is therefore not yet linked to
+ * a previous snapshot.
+ * <p/>
+ * If any transform or clip information was set before, they are put into the Graphics object.
+ * @param bitmap the bitmap to link to.
+ */
+ public void setBitmap(Bitmap_Delegate bitmap) {
+ // create a new Layer for the bitmap. This will be the base layer.
+ Graphics2D graphics2D = bitmap.getImage().createGraphics();
+ Layer baseLayer = new Layer(graphics2D, bitmap);
+
+ // Set the current transform and clip which can either come from mTransform/mClip if they
+ // were set when there was no bitmap/layers or from the current base layers if there is
+ // one already.
+
+ graphics2D.setTransform(getTransform());
+ // reset mTransform in case there was one.
+ mTransform = null;
+
+ baseLayer.setClip(getClip());
+ // reset mClip in case there was one.
+ mClip = null;
+
+ // replace whatever current layers we have with this.
+ mLayers.clear();
+ mLayers.add(baseLayer);
+
+ }
+
+ public void translate(float dx, float dy) {
+ if (mLayers.size() > 0) {
+ for (Layer layer : mLayers) {
+ layer.getGraphics().translate(dx, dy);
+ }
+ } else {
+ if (mTransform == null) {
+ mTransform = new AffineTransform();
+ }
+ mTransform.translate(dx, dy);
+ }
+ }
+
+ public void rotate(double radians) {
+ if (mLayers.size() > 0) {
+ for (Layer layer : mLayers) {
+ layer.getGraphics().rotate(radians);
+ }
+ } else {
+ if (mTransform == null) {
+ mTransform = new AffineTransform();
+ }
+ mTransform.rotate(radians);
+ }
+ }
+
+ public void scale(float sx, float sy) {
+ if (mLayers.size() > 0) {
+ for (Layer layer : mLayers) {
+ layer.getGraphics().scale(sx, sy);
+ }
+ } else {
+ if (mTransform == null) {
+ mTransform = new AffineTransform();
+ }
+ mTransform.scale(sx, sy);
+ }
+ }
+
+ public AffineTransform getTransform() {
+ if (mLayers.size() > 0) {
+ // all graphics2D in the list have the same transform
+ return mLayers.get(0).getGraphics().getTransform();
+ } else {
+ if (mTransform == null) {
+ mTransform = new AffineTransform();
+ }
+ return mTransform;
+ }
+ }
+
+ public void setTransform(AffineTransform transform) {
+ if (mLayers.size() > 0) {
+ for (Layer layer : mLayers) {
+ layer.getGraphics().setTransform(transform);
+ }
+ } else {
+ if (mTransform == null) {
+ mTransform = new AffineTransform();
+ }
+ mTransform.setTransform(transform);
+ }
+ }
+
+ public boolean clip(Shape shape, int regionOp) {
+ // Simple case of intersect with existing layers.
+ // Because Graphics2D#setClip works a bit peculiarly, we optimize
+ // the case of clipping by intersection, as it's supported natively.
+ if (regionOp == Region.Op.INTERSECT.nativeInt && mLayers.size() > 0) {
+ for (Layer layer : mLayers) {
+ layer.clip(shape);
+ }
+
+ Shape currentClip = getClip();
+ return currentClip != null && currentClip.getBounds().isEmpty() == false;
+ }
+
+ Area area = null;
+
+ if (regionOp == Region.Op.REPLACE.nativeInt) {
+ area = new Area(shape);
+ } else {
+ area = Region_Delegate.combineShapes(getClip(), shape, regionOp);
+ }
+
+ assert area != null;
+
+ if (mLayers.size() > 0) {
+ if (area != null) {
+ for (Layer layer : mLayers) {
+ layer.setClip(area);
+ }
+ }
+
+ Shape currentClip = getClip();
+ return currentClip != null && currentClip.getBounds().isEmpty() == false;
+ } else {
+ if (area != null) {
+ mClip = area;
+ } else {
+ mClip = new Area();
+ }
+
+ return mClip.getBounds().isEmpty() == false;
+ }
+ }
+
+ public boolean clipRect(float left, float top, float right, float bottom, int regionOp) {
+ return clip(new Rectangle2D.Float(left, top, right - left, bottom - top), regionOp);
+ }
+
+ /**
+ * Returns the current clip, or null if none have been setup.
+ */
+ public Shape getClip() {
+ if (mLayers.size() > 0) {
+ // they all have the same clip
+ return mLayers.get(0).getGraphics().getClip();
+ } else {
+ return mClip;
+ }
+ }
+
+ private GcSnapshot doRestoreTo(int size, int saveCount) {
+ if (size <= saveCount) {
+ return this;
+ }
+
+ // restore the current one first.
+ GcSnapshot previous = doRestore();
+
+ if (size == saveCount + 1) { // this was the only one that needed restore.
+ return previous;
+ } else {
+ return previous.doRestoreTo(size - 1, saveCount);
+ }
+ }
+
+ /**
+ * Executes the Drawable's draw method, with a null paint delegate.
+ * <p/>
+ * Note that the method can be called several times if there are more than one active layer.
+ * @param drawable
+ */
+ public void draw(Drawable drawable) {
+ draw(drawable, null, false /*compositeOnly*/, false /*forceSrcMode*/);
+ }
+
+ /**
+ * Executes the Drawable's draw method.
+ * <p/>
+ * Note that the method can be called several times if there are more than one active layer.
+ * @param drawable
+ * @param paint
+ * @param compositeOnly whether the paint is used for composite only. This is typically
+ * the case for bitmaps.
+ * @param forceSrcMode if true, this overrides the composite to be SRC
+ */
+ public void draw(Drawable drawable, Paint_Delegate paint, boolean compositeOnly,
+ boolean forceSrcMode) {
+ // the current snapshot may not have a mLocalLayer (ie it was created on save() instead
+ // of saveLayer(), but that doesn't mean there's no layer.
+ // mLayers however saves all the information we need (flags).
+ if (mLayers.size() == 1) {
+ // no layer, only base layer. easy case.
+ drawInLayer(mLayers.get(0), drawable, paint, compositeOnly, forceSrcMode);
+ } else {
+ // draw in all the layers until the layer save flags tells us to stop (ie drawing
+ // in that layer is limited to the layer itself.
+ int flags;
+ int i = mLayers.size() - 1;
+
+ do {
+ Layer layer = mLayers.get(i);
+
+ drawInLayer(layer, drawable, paint, compositeOnly, forceSrcMode);
+
+ // then go to previous layer, only if there are any left, and its flags
+ // doesn't restrict drawing to the layer itself.
+ i--;
+ flags = layer.getFlags();
+ } while (i >= 0 && (flags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0);
+ }
+ }
+
+ private void drawInLayer(Layer layer, Drawable drawable, Paint_Delegate paint,
+ boolean compositeOnly, boolean forceSrcMode) {
+ Graphics2D originalGraphics = layer.getGraphics();
+ // get a Graphics2D object configured with the drawing parameters.
+ Graphics2D configuredGraphics2D =
+ paint != null ?
+ createCustomGraphics(originalGraphics, paint, compositeOnly, forceSrcMode) :
+ (Graphics2D) originalGraphics.create();
+
+ if (configuredGraphics2D != null) {
+ try {
+ drawable.draw(configuredGraphics2D, paint);
+ } finally {
+ // dispose Graphics2D object
+ configuredGraphics2D.dispose();
+ }
+ }
+ }
+
+ private GcSnapshot doRestore() {
+ if (mPrevious != null) {
+ if (mLocalLayer != null) {
+ // prepare to blit the layers in which we have draw, in the layer beneath
+ // them, starting with the top one (which is the current local layer).
+ int i = mLayers.size() - 1;
+ int flags;
+ do {
+ Layer dstLayer = mLayers.get(i - 1);
+
+ restoreLayer(dstLayer);
+
+ flags = dstLayer.getFlags();
+ i--;
+ } while (i > 0 && (flags & Canvas.CLIP_TO_LAYER_SAVE_FLAG) == 0);
+ }
+
+ // if this snapshot does not save everything, then set the previous snapshot
+ // to this snapshot content
+
+ // didn't save the matrix? set the current matrix on the previous snapshot
+ if ((mFlags & Canvas.MATRIX_SAVE_FLAG) == 0) {
+ AffineTransform mtx = getTransform();
+ for (Layer layer : mPrevious.mLayers) {
+ layer.getGraphics().setTransform(mtx);
+ }
+ }
+
+ // didn't save the clip? set the current clip on the previous snapshot
+ if ((mFlags & Canvas.CLIP_SAVE_FLAG) == 0) {
+ Shape clip = getClip();
+ for (Layer layer : mPrevious.mLayers) {
+ layer.setClip(clip);
+ }
+ }
+ }
+
+ for (Layer layer : mLayers) {
+ layer.getGraphics().dispose();
+ }
+
+ return mPrevious;
+ }
+
+ private void restoreLayer(Layer dstLayer) {
+
+ Graphics2D baseGfx = dstLayer.getImage().createGraphics();
+
+ // if the layer contains an original copy this means the flags
+ // didn't restrict drawing to the local layer and we need to make sure the
+ // layer bounds in the layer beneath didn't receive any drawing.
+ // so we use the originalCopy to erase the new drawings in there.
+ BufferedImage originalCopy = dstLayer.getOriginalCopy();
+ if (originalCopy != null) {
+ Graphics2D g = (Graphics2D) baseGfx.create();
+ g.setComposite(AlphaComposite.Src);
+
+ g.drawImage(originalCopy,
+ mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom,
+ 0, 0, mLayerBounds.width(), mLayerBounds.height(),
+ null);
+ g.dispose();
+ }
+
+ // now draw put the content of the local layer onto the layer,
+ // using the paint information
+ Graphics2D g = createCustomGraphics(baseGfx, mLocalLayerPaint,
+ true /*alphaOnly*/, false /*forceSrcMode*/);
+
+ if (g != null) {
+ g.drawImage(mLocalLayer.getImage(),
+ mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom,
+ mLayerBounds.left, mLayerBounds.top, mLayerBounds.right, mLayerBounds.bottom,
+ null);
+ g.dispose();
+ }
+
+ baseGfx.dispose();
+ }
+
+ /**
+ * Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
+ * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
+ */
+ private Graphics2D createCustomGraphics(Graphics2D original, Paint_Delegate paint,
+ boolean compositeOnly, boolean forceSrcMode) {
+ // make new one graphics
+ Graphics2D g = (Graphics2D) original.create();
+
+ // configure it
+
+ if (paint.isAntiAliased()) {
+ g.setRenderingHint(
+ RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+ g.setRenderingHint(
+ RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+ }
+
+ boolean customShader = false;
+
+ // get the shader first, as it'll replace the color if it can be used it.
+ if (compositeOnly == false) {
+ Shader_Delegate shaderDelegate = paint.getShader();
+ if (shaderDelegate != null) {
+ if (shaderDelegate.isSupported()) {
+ // shader could have a local matrix that's not valid (for instance 0 scaling).
+ if (shaderDelegate.isValid()) {
+ java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint();
+ assert shaderPaint != null;
+ if (shaderPaint != null) {
+ g.setPaint(shaderPaint);
+ customShader = true;
+ }
+ } else {
+ g.dispose();
+ return null;
+ }
+ } else {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_SHADER,
+ shaderDelegate.getSupportMessage(),
+ null /*throwable*/, null /*data*/);
+ }
+ }
+
+ // if no shader, use the paint color
+ if (customShader == false) {
+ g.setColor(new Color(paint.getColor(), true /*hasAlpha*/));
+ }
+
+ // set the stroke
+ g.setStroke(paint.getJavaStroke());
+ }
+
+ // the alpha for the composite. Always opaque if the normal paint color is used since
+ // it contains the alpha
+ int alpha = (compositeOnly || customShader) ? paint.getAlpha() : 0xFF;
+
+ if (forceSrcMode) {
+ g.setComposite(AlphaComposite.getInstance(
+ AlphaComposite.SRC, alpha / 255.f));
+ } else {
+ boolean customXfermode = false;
+ Xfermode_Delegate xfermodeDelegate = paint.getXfermode();
+ if (xfermodeDelegate != null) {
+ if (xfermodeDelegate.isSupported()) {
+ Composite composite = xfermodeDelegate.getComposite(alpha);
+ assert composite != null;
+ if (composite != null) {
+ g.setComposite(composite);
+ customXfermode = true;
+ }
+ } else {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_XFERMODE,
+ xfermodeDelegate.getSupportMessage(),
+ null /*throwable*/, null /*data*/);
+ }
+ }
+
+ // if there was no custom xfermode, but we have alpha (due to a shader and a non
+ // opaque alpha channel in the paint color), then we create an AlphaComposite anyway
+ // that will handle the alpha.
+ if (customXfermode == false && alpha != 0xFF) {
+ g.setComposite(AlphaComposite.getInstance(
+ AlphaComposite.SRC_OVER, alpha / 255.f));
+ }
+ }
+
+ return g;
+ }
+
+ private void mapRect(AffineTransform matrix, RectF dst, RectF src) {
+ // array with 4 corners
+ float[] corners = new float[] {
+ src.left, src.top,
+ src.right, src.top,
+ src.right, src.bottom,
+ src.left, src.bottom,
+ };
+
+ // apply the transform to them.
+ matrix.transform(corners, 0, corners, 0, 4);
+
+ // now put the result in the rect. We take the min/max of Xs and min/max of Ys
+ dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
+ dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
+
+ dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
+ dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
new file mode 100644
index 0000000..8e80c21
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.impl;
+
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_LOCK_INTERRUPTED;
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_TIMEOUT;
+import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
+
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderParams;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.RenderResources.FrameworkResourceIdProvider;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.resources.ResourceType;
+
+import android.util.DisplayMetrics;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.locks.ReentrantLock;
+
+/**
+ * Base class for rendering action.
+ *
+ * It provides life-cycle methods to init and stop the rendering.
+ * The most important methods are:
+ * {@link #init(long)} and {@link #acquire(long)} to start a rendering and {@link #release()}
+ * after the rendering.
+ *
+ *
+ * @param <T> the {@link RenderParams} implementation
+ *
+ */
+public abstract class RenderAction<T extends RenderParams> extends FrameworkResourceIdProvider {
+
+ /**
+ * The current context being rendered. This is set through {@link #acquire(long)} and
+ * {@link #init(long)}, and unset in {@link #release()}.
+ */
+ private static BridgeContext sCurrentContext = null;
+
+ private final T mParams;
+
+ private BridgeContext mContext;
+
+ /**
+ * Creates a renderAction.
+ * <p>
+ * This <b>must</b> be followed by a call to {@link RenderAction#init()}, which act as a
+ * call to {@link RenderAction#acquire(long)}
+ *
+ * @param params the RenderParams. This must be a copy that the action can keep
+ *
+ */
+ protected RenderAction(T params) {
+ mParams = params;
+ }
+
+ /**
+ * Initializes and acquires the scene, creating various Android objects such as context,
+ * inflater, and parser.
+ *
+ * @param timeout the time to wait if another rendering is happening.
+ *
+ * @return whether the scene was prepared
+ *
+ * @see #acquire(long)
+ * @see #release()
+ */
+ public Result init(long timeout) {
+ // acquire the lock. if the result is null, lock was just acquired, otherwise, return
+ // the result.
+ Result result = acquireLock(timeout);
+ if (result != null) {
+ return result;
+ }
+
+ // setup the display Metrics.
+ DisplayMetrics metrics = new DisplayMetrics();
+ metrics.densityDpi = mParams.getDensity().getDpiValue();
+ metrics.density = metrics.densityDpi / (float) DisplayMetrics.DENSITY_DEFAULT;
+ metrics.scaledDensity = metrics.density;
+ metrics.widthPixels = mParams.getScreenWidth();
+ metrics.heightPixels = mParams.getScreenHeight();
+ metrics.xdpi = mParams.getXdpi();
+ metrics.ydpi = mParams.getYdpi();
+
+ RenderResources resources = mParams.getResources();
+
+ // build the context
+ mContext = new BridgeContext(mParams.getProjectKey(), metrics, resources,
+ mParams.getProjectCallback(), mParams.getTargetSdkVersion());
+
+ setUp();
+
+ return SUCCESS.createResult();
+ }
+
+ /**
+ * Prepares the scene for action.
+ * <p>
+ * This call is blocking if another rendering/inflating is currently happening, and will return
+ * whether the preparation worked.
+ *
+ * The preparation can fail if another rendering took too long and the timeout was elapsed.
+ *
+ * More than one call to this from the same thread will have no effect and will return
+ * {@link Result#SUCCESS}.
+ *
+ * After scene actions have taken place, only one call to {@link #release()} must be
+ * done.
+ *
+ * @param timeout the time to wait if another rendering is happening.
+ *
+ * @return whether the scene was prepared
+ *
+ * @see #release()
+ *
+ * @throws IllegalStateException if {@link #init(long)} was never called.
+ */
+ public Result acquire(long timeout) {
+ if (mContext == null) {
+ throw new IllegalStateException("After scene creation, #init() must be called");
+ }
+
+ // acquire the lock. if the result is null, lock was just acquired, otherwise, return
+ // the result.
+ Result result = acquireLock(timeout);
+ if (result != null) {
+ return result;
+ }
+
+ setUp();
+
+ return SUCCESS.createResult();
+ }
+
+ /**
+ * Acquire the lock so that the scene can be acted upon.
+ * <p>
+ * This returns null if the lock was just acquired, otherwise it returns
+ * {@link Result#SUCCESS} if the lock already belonged to that thread, or another
+ * instance (see {@link Result#getStatus()}) if an error occurred.
+ *
+ * @param timeout the time to wait if another rendering is happening.
+ * @return null if the lock was just acquire or another result depending on the state.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene.
+ */
+ private Result acquireLock(long timeout) {
+ ReentrantLock lock = Bridge.getLock();
+ if (lock.isHeldByCurrentThread() == false) {
+ try {
+ boolean acquired = lock.tryLock(timeout, TimeUnit.MILLISECONDS);
+
+ if (acquired == false) {
+ return ERROR_TIMEOUT.createResult();
+ }
+ } catch (InterruptedException e) {
+ return ERROR_LOCK_INTERRUPTED.createResult();
+ }
+ } else {
+ // This thread holds the lock already. Checks that this wasn't for a different context.
+ // If this is called by init, mContext will be null and so should sCurrentContext
+ // anyway
+ if (mContext != sCurrentContext) {
+ throw new IllegalStateException("Acquiring different scenes from same thread without releases");
+ }
+ return SUCCESS.createResult();
+ }
+
+ return null;
+ }
+
+ /**
+ * Cleans up the scene after an action.
+ */
+ public void release() {
+ ReentrantLock lock = Bridge.getLock();
+
+ // with the use of finally blocks, it is possible to find ourself calling this
+ // without a successful call to prepareScene. This test makes sure that unlock() will
+ // not throw IllegalMonitorStateException.
+ if (lock.isHeldByCurrentThread()) {
+ tearDown();
+ lock.unlock();
+ }
+ }
+
+ /**
+ * Sets up the session for rendering.
+ * <p/>
+ * The counterpart is {@link #tearDown()}.
+ */
+ private void setUp() {
+ // make sure the Resources object references the context (and other objects) for this
+ // scene
+ mContext.initResources();
+ sCurrentContext = mContext;
+
+ LayoutLog currentLog = mParams.getLog();
+ Bridge.setLog(currentLog);
+ mContext.getRenderResources().setFrameworkResourceIdProvider(this);
+ mContext.getRenderResources().setLogger(currentLog);
+ }
+
+ /**
+ * Tear down the session after rendering.
+ * <p/>
+ * The counterpart is {@link #setUp()}.
+ */
+ private void tearDown() {
+ // Make sure to remove static references, otherwise we could not unload the lib
+ mContext.disposeResources();
+ sCurrentContext = null;
+
+ Bridge.setLog(null);
+ mContext.getRenderResources().setFrameworkResourceIdProvider(null);
+ mContext.getRenderResources().setLogger(null);
+ }
+
+ public static BridgeContext getCurrentContext() {
+ return sCurrentContext;
+ }
+
+ protected T getParams() {
+ return mParams;
+ }
+
+ protected BridgeContext getContext() {
+ return mContext;
+ }
+
+ /**
+ * Returns the log associated with the session.
+ * @return the log or null if there are none.
+ */
+ public LayoutLog getLog() {
+ if (mParams != null) {
+ return mParams.getLog();
+ }
+
+ return null;
+ }
+
+ /**
+ * Checks that the lock is owned by the current thread and that the current context is the one
+ * from this scene.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #acquire(long)} was not called.
+ */
+ protected void checkLock() {
+ ReentrantLock lock = Bridge.getLock();
+ if (lock.isHeldByCurrentThread() == false) {
+ throw new IllegalStateException("scene must be acquired first. see #acquire(long)");
+ }
+ if (sCurrentContext != mContext) {
+ throw new IllegalStateException("Thread acquired a scene but is rendering a different one");
+ }
+ }
+
+ // --- FrameworkResourceIdProvider methods
+
+ @Override
+ public Integer getId(ResourceType resType, String resName) {
+ return Bridge.getResourceId(resType, resName);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
new file mode 100644
index 0000000..10a4368
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderDrawable.java
@@ -0,0 +1,140 @@
+/*
+ * 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.layoutlib.bridge.impl;
+
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
+
+import com.android.ide.common.rendering.api.DrawableParams;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.Result.Status;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.BridgeWindow;
+import com.android.layoutlib.bridge.android.BridgeWindowSession;
+import com.android.resources.ResourceType;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.view.View;
+import android.view.View.AttachInfo;
+import android.view.View.MeasureSpec;
+import android.widget.FrameLayout;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+
+/**
+ * Action to render a given Drawable provided through {@link DrawableParams#getDrawable()}.
+ *
+ * The class only provides a simple {@link #render()} method, but the full life-cycle of the
+ * action must be respected.
+ *
+ * @see RenderAction
+ *
+ */
+public class RenderDrawable extends RenderAction<DrawableParams> {
+
+ public RenderDrawable(DrawableParams params) {
+ super(new DrawableParams(params));
+ }
+
+ public Result render() {
+ checkLock();
+ try {
+ // get the drawable resource value
+ DrawableParams params = getParams();
+ ResourceValue drawableResource = params.getDrawable();
+
+ // resolve it
+ BridgeContext context = getContext();
+ drawableResource = context.getRenderResources().resolveResValue(drawableResource);
+
+ if (drawableResource == null ||
+ drawableResource.getResourceType() != ResourceType.DRAWABLE) {
+ return Status.ERROR_NOT_A_DRAWABLE.createResult();
+ }
+
+ // create a simple FrameLayout
+ FrameLayout content = new FrameLayout(context);
+
+ // get the actual Drawable object to draw
+ Drawable d = ResourceHelper.getDrawable(drawableResource, context);
+ content.setBackgroundDrawable(d);
+
+ // set the AttachInfo on the root view.
+ AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
+ new Handler(), null);
+ info.mHasWindowFocus = true;
+ info.mWindowVisibility = View.VISIBLE;
+ info.mInTouchMode = false; // this is so that we can display selections.
+ content.dispatchAttachedToWindow(info, 0);
+
+
+ // measure
+ int w = params.getScreenWidth();
+ int h = params.getScreenHeight();
+ int w_spec = MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY);
+ int h_spec = MeasureSpec.makeMeasureSpec(h, MeasureSpec.EXACTLY);
+ content.measure(w_spec, h_spec);
+
+ // now do the layout.
+ content.layout(0, 0, w, h);
+
+ // preDraw setup
+ content.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
+
+ // draw into a new image
+ BufferedImage image = getImage(w, h);
+
+ // create an Android bitmap around the BufferedImage
+ Bitmap bitmap = Bitmap_Delegate.createBitmap(image,
+ true /*isMutable*/, params.getDensity());
+
+ // create a Canvas around the Android bitmap
+ Canvas canvas = new Canvas(bitmap);
+ canvas.setDensity(params.getDensity().getDpiValue());
+
+ // and draw
+ content.draw(canvas);
+
+ return Status.SUCCESS.createResult(image);
+ } catch (IOException e) {
+ return ERROR_UNKNOWN.createResult(e.getMessage(), e);
+ }
+ }
+
+ protected BufferedImage getImage(int w, int h) {
+ BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB);
+ Graphics2D gc = image.createGraphics();
+ gc.setComposite(AlphaComposite.Src);
+
+ gc.setColor(new Color(0x00000000, true));
+ gc.fillRect(0, 0, w, h);
+
+ // done
+ gc.dispose();
+
+ return image;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
new file mode 100644
index 0000000..348c579
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -0,0 +1,1059 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.impl;
+
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_INFLATION;
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_NOT_INFLATED;
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_UNKNOWN;
+import static com.android.ide.common.rendering.api.Result.Status.ERROR_VIEWGROUP_NO_CHILDREN;
+import static com.android.ide.common.rendering.api.Result.Status.SUCCESS;
+
+import com.android.ide.common.rendering.api.IAnimationListener;
+import com.android.ide.common.rendering.api.ILayoutPullParser;
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.ide.common.rendering.api.RenderParams;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.RenderSession;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.ide.common.rendering.api.Result;
+import com.android.ide.common.rendering.api.SessionParams;
+import com.android.ide.common.rendering.api.ViewInfo;
+import com.android.ide.common.rendering.api.Result.Status;
+import com.android.ide.common.rendering.api.SessionParams.RenderingMode;
+import com.android.internal.util.XmlUtils;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.BridgeInflater;
+import com.android.layoutlib.bridge.android.BridgeLayoutParamsMapAttributes;
+import com.android.layoutlib.bridge.android.BridgeWindow;
+import com.android.layoutlib.bridge.android.BridgeWindowSession;
+import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
+import com.android.layoutlib.bridge.bars.PhoneSystemBar;
+import com.android.layoutlib.bridge.bars.TitleBar;
+import com.android.resources.ResourceType;
+import com.android.resources.ScreenSize;
+import com.android.util.Pair;
+
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import android.util.DisplayMetrics;
+import android.util.TypedValue;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.View.AttachInfo;
+import android.view.View.MeasureSpec;
+import android.view.ViewGroup.LayoutParams;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.TabHost;
+import android.widget.TabWidget;
+import android.widget.TabHost.TabSpec;
+
+import java.awt.AlphaComposite;
+import java.awt.Color;
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Class implementing the render session.
+ *
+ * A session is a stateful representation of a layout file. It is initialized with data coming
+ * through the {@link Bridge} API to inflate the layout. Further actions and rendering can then
+ * be done on the layout.
+ *
+ */
+public class RenderSessionImpl extends RenderAction<SessionParams> {
+
+ private static final int DEFAULT_TITLE_BAR_HEIGHT = 25;
+ private static final int DEFAULT_STATUS_BAR_HEIGHT = 25;
+
+ // scene state
+ private RenderSession mScene;
+ private BridgeXmlBlockParser mBlockParser;
+ private BridgeInflater mInflater;
+ private ResourceValue mWindowBackground;
+ private ViewGroup mViewRoot;
+ private FrameLayout mContentRoot;
+ private Canvas mCanvas;
+ private int mMeasuredScreenWidth = -1;
+ private int mMeasuredScreenHeight = -1;
+ private boolean mIsAlphaChannelImage;
+ private boolean mWindowIsFloating;
+
+ private int mStatusBarSize;
+ private int mTitleBarSize;
+
+
+ // information being returned through the API
+ private BufferedImage mImage;
+ private List<ViewInfo> mViewInfoList;
+
+ private static final class PostInflateException extends Exception {
+ private static final long serialVersionUID = 1L;
+
+ public PostInflateException(String message) {
+ super(message);
+ }
+ }
+
+ /**
+ * Creates a layout scene with all the information coming from the layout bridge API.
+ * <p>
+ * This <b>must</b> be followed by a call to {@link RenderSessionImpl#init()}, which act as a
+ * call to {@link RenderSessionImpl#acquire(long)}
+ *
+ * @see LayoutBridge#createScene(com.android.layoutlib.api.SceneParams)
+ */
+ public RenderSessionImpl(SessionParams params) {
+ super(new SessionParams(params));
+ }
+
+ /**
+ * Initializes and acquires the scene, creating various Android objects such as context,
+ * inflater, and parser.
+ *
+ * @param timeout the time to wait if another rendering is happening.
+ *
+ * @return whether the scene was prepared
+ *
+ * @see #acquire(long)
+ * @see #release()
+ */
+ @Override
+ public Result init(long timeout) {
+ Result result = super.init(timeout);
+ if (result.isSuccess() == false) {
+ return result;
+ }
+
+ SessionParams params = getParams();
+ BridgeContext context = getContext();
+
+ RenderResources resources = getParams().getResources();
+ DisplayMetrics metrics = getContext().getMetrics();
+
+ // use default of true in case it's not found to use alpha by default
+ mIsAlphaChannelImage = getBooleanThemeValue(resources,
+ "windowIsFloating", true /*defaultValue*/);
+
+ mWindowIsFloating = getBooleanThemeValue(resources, "windowIsFloating",
+ true /*defaultValue*/);
+
+ findBackground(resources);
+ findStatusBar(resources, metrics);
+ findTitleBar(resources, metrics);
+
+ // build the inflater and parser.
+ mInflater = new BridgeInflater(context, params.getProjectCallback());
+ context.setBridgeInflater(mInflater);
+
+ mBlockParser = new BridgeXmlBlockParser(
+ params.getLayoutDescription(), context, false /* platformResourceFlag */);
+
+ return SUCCESS.createResult();
+ }
+
+ /**
+ * Inflates the layout.
+ * <p>
+ * {@link #acquire(long)} must have been called before this.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #init(long)} was not called.
+ */
+ public Result inflate() {
+ checkLock();
+
+ try {
+
+ SessionParams params = getParams();
+ BridgeContext context = getContext();
+
+ // the view group that receives the window background.
+ ViewGroup backgroundView = null;
+
+ if (mWindowIsFloating || params.isForceNoDecor()) {
+ backgroundView = mViewRoot = mContentRoot = new FrameLayout(context);
+ } else {
+ /*
+ * we're creating the following layout
+ *
+ +-------------------------------------------------+
+ | System bar |
+ +-------------------------------------------------+
+ | (Layout with background drawable) |
+ | +---------------------------------------------+ |
+ | | Title (optional) | |
+ | +---------------------------------------------+ |
+ | | Content, vertical extending | |
+ | | | |
+ | +---------------------------------------------+ |
+ +-------------------------------------------------+
+
+ */
+
+ LinearLayout topLayout = new LinearLayout(context);
+ mViewRoot = topLayout;
+ topLayout.setOrientation(LinearLayout.VERTICAL);
+
+ if (mStatusBarSize > 0) {
+ // system bar
+ try {
+ PhoneSystemBar systemBar = new PhoneSystemBar(context,
+ params.getDensity());
+ systemBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mStatusBarSize));
+ topLayout.addView(systemBar);
+ } catch (XmlPullParserException e) {
+
+ }
+ }
+
+ LinearLayout backgroundLayout = new LinearLayout(context);
+ backgroundView = backgroundLayout;
+ backgroundLayout.setOrientation(LinearLayout.VERTICAL);
+ LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ layoutParams.weight = 1;
+ backgroundLayout.setLayoutParams(layoutParams);
+ topLayout.addView(backgroundLayout);
+
+
+ // if the theme says no title, then the size will be 0
+ if (mTitleBarSize > 0) {
+ try {
+ TitleBar titleBar = new TitleBar(context,
+ params.getDensity(), params.getAppLabel());
+ titleBar.setLayoutParams(
+ new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, mTitleBarSize));
+ backgroundLayout.addView(titleBar);
+ } catch (XmlPullParserException e) {
+
+ }
+ }
+
+ // content frame
+ mContentRoot = new FrameLayout(context);
+ layoutParams = new LinearLayout.LayoutParams(
+ LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
+ layoutParams.weight = 1;
+ mContentRoot.setLayoutParams(layoutParams);
+ backgroundLayout.addView(mContentRoot);
+ }
+
+
+ View view = mInflater.inflate(mBlockParser, mContentRoot);
+
+ // set the AttachInfo on the root view.
+ AttachInfo info = new AttachInfo(new BridgeWindowSession(), new BridgeWindow(),
+ new Handler(), null);
+ info.mHasWindowFocus = true;
+ info.mWindowVisibility = View.VISIBLE;
+ info.mInTouchMode = false; // this is so that we can display selections.
+ mViewRoot.dispatchAttachedToWindow(info, 0);
+
+ // post-inflate process. For now this supports TabHost/TabWidget
+ postInflateProcess(view, params.getProjectCallback());
+
+ // get the background drawable
+ if (mWindowBackground != null && backgroundView != null) {
+ Drawable d = ResourceHelper.getDrawable(mWindowBackground, context);
+ backgroundView.setBackgroundDrawable(d);
+ }
+
+ return SUCCESS.createResult();
+ } catch (PostInflateException e) {
+ return ERROR_INFLATION.createResult(e.getMessage(), e);
+ } catch (Throwable e) {
+ // get the real cause of the exception.
+ Throwable t = e;
+ while (t.getCause() != null) {
+ t = t.getCause();
+ }
+
+ return ERROR_INFLATION.createResult(t.getMessage(), t);
+ }
+ }
+
+ /**
+ * Renders the scene.
+ * <p>
+ * {@link #acquire(long)} must have been called before this.
+ *
+ * @param freshRender whether the render is a new one and should erase the existing bitmap (in
+ * the case where bitmaps are reused). This is typically needed when not playing
+ * animations.)
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #acquire(long)} was not called.
+ *
+ * @see RenderParams#getRenderingMode()
+ * @see RenderSession#render(long)
+ */
+ public Result render(boolean freshRender) {
+ checkLock();
+
+ SessionParams params = getParams();
+
+ try {
+ if (mViewRoot == null) {
+ return ERROR_NOT_INFLATED.createResult();
+ }
+
+ RenderingMode renderingMode = params.getRenderingMode();
+
+ // only do the screen measure when needed.
+ boolean newRenderSize = false;
+ if (mMeasuredScreenWidth == -1) {
+ newRenderSize = true;
+ mMeasuredScreenWidth = params.getScreenWidth();
+ mMeasuredScreenHeight = params.getScreenHeight();
+
+ if (renderingMode != RenderingMode.NORMAL) {
+ int widthMeasureSpecMode = renderingMode.isHorizExpand() ?
+ MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
+ : MeasureSpec.EXACTLY;
+ int heightMeasureSpecMode = renderingMode.isVertExpand() ?
+ MeasureSpec.UNSPECIFIED // this lets us know the actual needed size
+ : MeasureSpec.EXACTLY;
+
+ // We used to compare the measured size of the content to the screen size but
+ // this does not work anymore due to the 2 following issues:
+ // - If the content is in a decor (system bar, title/action bar), the root view
+ // will not resize even with the UNSPECIFIED because of the embedded layout.
+ // - If there is no decor, but a dialog frame, then the dialog padding prevents
+ // comparing the size of the content to the screen frame (as it would not
+ // take into account the dialog padding).
+
+ // The solution is to first get the content size in a normal rendering, inside
+ // the decor or the dialog padding.
+ // Then measure only the content with UNSPECIFIED to see the size difference
+ // and apply this to the screen size.
+
+ // first measure the full layout, with EXACTLY to get the size of the
+ // content as it is inside the decor/dialog
+ Pair<Integer, Integer> exactMeasure = measureView(
+ mViewRoot, mContentRoot.getChildAt(0),
+ mMeasuredScreenWidth, MeasureSpec.EXACTLY,
+ mMeasuredScreenHeight, MeasureSpec.EXACTLY);
+
+ // now measure the content only using UNSPECIFIED (where applicable, based on
+ // the rendering mode). This will give us the size the content needs.
+ Pair<Integer, Integer> result = measureView(
+ mContentRoot, mContentRoot.getChildAt(0),
+ mMeasuredScreenWidth, widthMeasureSpecMode,
+ mMeasuredScreenHeight, heightMeasureSpecMode);
+
+ // now look at the difference and add what is needed.
+ if (renderingMode.isHorizExpand()) {
+ int measuredWidth = exactMeasure.getFirst();
+ int neededWidth = result.getFirst();
+ if (neededWidth > measuredWidth) {
+ mMeasuredScreenWidth += neededWidth - measuredWidth;
+ }
+ }
+
+ if (renderingMode.isVertExpand()) {
+ int measuredHeight = exactMeasure.getSecond();
+ int neededHeight = result.getSecond();
+ if (neededHeight > measuredHeight) {
+ mMeasuredScreenHeight += neededHeight - measuredHeight;
+ }
+ }
+ }
+ }
+
+ // measure again with the size we need
+ // This must always be done before the call to layout
+ measureView(mViewRoot, null /*measuredView*/,
+ mMeasuredScreenWidth, MeasureSpec.EXACTLY,
+ mMeasuredScreenHeight, MeasureSpec.EXACTLY);
+
+ // now do the layout.
+ mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
+
+ if (params.isLayoutOnly()) {
+ // delete the canvas and image to reset them on the next full rendering
+ mImage = null;
+ mCanvas = null;
+ } else {
+ mViewRoot.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
+
+ // draw the views
+ // create the BufferedImage into which the layout will be rendered.
+ boolean newImage = false;
+ if (newRenderSize || mCanvas == null) {
+ if (params.getImageFactory() != null) {
+ mImage = params.getImageFactory().getImage(
+ mMeasuredScreenWidth,
+ mMeasuredScreenHeight);
+ } else {
+ mImage = new BufferedImage(
+ mMeasuredScreenWidth,
+ mMeasuredScreenHeight,
+ BufferedImage.TYPE_INT_ARGB);
+ newImage = true;
+ }
+
+ if (params.isBgColorOverridden()) {
+ // since we override the content, it's the same as if it was a new image.
+ newImage = true;
+ Graphics2D gc = mImage.createGraphics();
+ gc.setColor(new Color(params.getOverrideBgColor(), true));
+ gc.setComposite(AlphaComposite.Src);
+ gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
+ gc.dispose();
+ }
+
+ // create an Android bitmap around the BufferedImage
+ Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
+ true /*isMutable*/, params.getDensity());
+
+ // create a Canvas around the Android bitmap
+ mCanvas = new Canvas(bitmap);
+ mCanvas.setDensity(params.getDensity().getDpiValue());
+ }
+
+ if (freshRender && newImage == false) {
+ Graphics2D gc = mImage.createGraphics();
+ gc.setComposite(AlphaComposite.Src);
+
+ gc.setColor(new Color(0x00000000, true));
+ gc.fillRect(0, 0,
+ mMeasuredScreenWidth, mMeasuredScreenHeight);
+
+ // done
+ gc.dispose();
+ }
+
+ mViewRoot.draw(mCanvas);
+ }
+
+ mViewInfoList = startVisitingViews(mViewRoot, 0);
+
+ // success!
+ return SUCCESS.createResult();
+ } catch (Throwable e) {
+ // get the real cause of the exception.
+ Throwable t = e;
+ while (t.getCause() != null) {
+ t = t.getCause();
+ }
+
+ return ERROR_UNKNOWN.createResult(t.getMessage(), t);
+ }
+ }
+
+ /**
+ * Executes {@link View#measure(int, int)} on a given view with the given parameters (used
+ * to create measure specs with {@link MeasureSpec#makeMeasureSpec(int, int)}.
+ *
+ * if <var>measuredView</var> is non null, the method returns a {@link Pair} of (width, height)
+ * for the view (using {@link View#getMeasuredWidth()} and {@link View#getMeasuredHeight()}).
+ *
+ * @param viewToMeasure the view on which to execute measure().
+ * @param measuredView if non null, the view to query for its measured width/height.
+ * @param width the width to use in the MeasureSpec.
+ * @param widthMode the MeasureSpec mode to use for the width.
+ * @param height the height to use in the MeasureSpec.
+ * @param heightMode the MeasureSpec mode to use for the height.
+ * @return the measured width/height if measuredView is non-null, null otherwise.
+ */
+ private Pair<Integer, Integer> measureView(ViewGroup viewToMeasure, View measuredView,
+ int width, int widthMode, int height, int heightMode) {
+ int w_spec = MeasureSpec.makeMeasureSpec(width, widthMode);
+ int h_spec = MeasureSpec.makeMeasureSpec(height, heightMode);
+ viewToMeasure.measure(w_spec, h_spec);
+
+ if (measuredView != null) {
+ return Pair.of(measuredView.getMeasuredWidth(), measuredView.getMeasuredHeight());
+ }
+
+ return null;
+ }
+
+ /**
+ * Insert a new child into an existing parent.
+ * <p>
+ * {@link #acquire(long)} must have been called before this.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #acquire(long)} was not called.
+ *
+ * @see RenderSession#insertChild(Object, ILayoutPullParser, int, IAnimationListener)
+ */
+ public Result insertChild(final ViewGroup parentView, ILayoutPullParser childXml,
+ final int index, final IAnimationListener listener) {
+ checkLock();
+
+ BridgeContext context = getContext();
+
+ // create a block parser for the XML
+ BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
+ childXml, context, false /* platformResourceFlag */);
+
+ // inflate the child without adding it to the root since we want to control where it'll
+ // get added. We do pass the parentView however to ensure that the layoutParams will
+ // be created correctly.
+ final View child = mInflater.inflate(blockParser, parentView, false /*attachToRoot*/);
+ blockParser.ensurePopped();
+
+ invalidateRenderingSize();
+
+ if (listener != null) {
+ // there is no support for animating views in this API level, so we fake the animation
+ // through a no animation thread.
+ new Thread("not animated insertChild") {
+ @Override
+ public void run() {
+ Result result = addView(parentView, child, index);
+ if (result.isSuccess() == false) {
+ listener.done(result);
+ }
+
+ // ready to do the work, acquire the scene.
+ result = acquire(250);
+ if (result.isSuccess() == false) {
+ listener.done(result);
+ return;
+ }
+
+ try {
+ result = render(false /*freshRender*/);
+ if (result.isSuccess()) {
+ listener.onNewFrame(RenderSessionImpl.this.getSession());
+ }
+ } finally {
+ release();
+ }
+
+ listener.done(result);
+ }
+ }.start();
+
+ // always return success since the real status will come through the listener.
+ return SUCCESS.createResult(child);
+ }
+
+ // add it to the parentView in the correct location
+ Result result = addView(parentView, child, index);
+ if (result.isSuccess() == false) {
+ return result;
+ }
+
+ result = render(false /*freshRender*/);
+ if (result.isSuccess()) {
+ result = result.getCopyWithData(child);
+ }
+
+ return result;
+ }
+
+ /**
+ * Adds a given view to a given parent at a given index.
+ *
+ * @param parent the parent to receive the view
+ * @param view the view to add to the parent
+ * @param index the index where to do the add.
+ *
+ * @return a Result with {@link Status#SUCCESS} or
+ * {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
+ * adding views.
+ */
+ private Result addView(ViewGroup parent, View view, int index) {
+ try {
+ parent.addView(view, index);
+ return SUCCESS.createResult();
+ } catch (UnsupportedOperationException e) {
+ // looks like this is a view class that doesn't support children manipulation!
+ return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
+ }
+ }
+
+ /**
+ * Moves a view to a new parent at a given location
+ * <p>
+ * {@link #acquire(long)} must have been called before this.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #acquire(long)} was not called.
+ *
+ * @see RenderSession#moveChild(Object, Object, int, Map, IAnimationListener)
+ */
+ public Result moveChild(final ViewGroup newParentView, final View childView, final int index,
+ Map<String, String> layoutParamsMap, final IAnimationListener listener) {
+ checkLock();
+
+ invalidateRenderingSize();
+
+ LayoutParams layoutParams = null;
+ if (layoutParamsMap != null) {
+ // need to create a new LayoutParams object for the new parent.
+ layoutParams = newParentView.generateLayoutParams(
+ new BridgeLayoutParamsMapAttributes(layoutParamsMap));
+ }
+
+ // get the current parent of the view that needs to be moved.
+ final ViewGroup previousParent = (ViewGroup) childView.getParent();
+
+ if (listener != null) {
+ final LayoutParams params = layoutParams;
+
+ // there is no support for animating views in this API level, so we fake the animation
+ // through a no animation thread.
+ new Thread("not animated moveChild") {
+ @Override
+ public void run() {
+ Result result = moveView(previousParent, newParentView, childView, index,
+ params);
+ if (result.isSuccess() == false) {
+ listener.done(result);
+ }
+
+ // ready to do the work, acquire the scene.
+ result = acquire(250);
+ if (result.isSuccess() == false) {
+ listener.done(result);
+ return;
+ }
+
+ try {
+ result = render(false /*freshRender*/);
+ if (result.isSuccess()) {
+ listener.onNewFrame(RenderSessionImpl.this.getSession());
+ }
+ } finally {
+ release();
+ }
+
+ listener.done(result);
+ }
+ }.start();
+
+ // always return success since the real status will come through the listener.
+ return SUCCESS.createResult(layoutParams);
+ }
+
+ Result result = moveView(previousParent, newParentView, childView, index, layoutParams);
+ if (result.isSuccess() == false) {
+ return result;
+ }
+
+ result = render(false /*freshRender*/);
+ if (layoutParams != null && result.isSuccess()) {
+ result = result.getCopyWithData(layoutParams);
+ }
+
+ return result;
+ }
+
+ /**
+ * Moves a View from its current parent to a new given parent at a new given location, with
+ * an optional new {@link LayoutParams} instance
+ *
+ * @param previousParent the previous parent, still owning the child at the time of the call.
+ * @param newParent the new parent
+ * @param movedView the view to move
+ * @param index the new location in the new parent
+ * @param params an option (can be null) {@link LayoutParams} instance.
+ *
+ * @return a Result with {@link Status#SUCCESS} or
+ * {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
+ * adding views.
+ */
+ private Result moveView(ViewGroup previousParent, final ViewGroup newParent,
+ final View movedView, final int index, final LayoutParams params) {
+ try {
+ // standard code with no animation. pretty simple.
+ previousParent.removeView(movedView);
+
+ // add it to the parentView in the correct location
+ if (params != null) {
+ newParent.addView(movedView, index, params);
+ } else {
+ newParent.addView(movedView, index);
+ }
+
+ return SUCCESS.createResult();
+ } catch (UnsupportedOperationException e) {
+ // looks like this is a view class that doesn't support children manipulation!
+ return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
+ }
+ }
+
+ /**
+ * Removes a child from its current parent.
+ * <p>
+ * {@link #acquire(long)} must have been called before this.
+ *
+ * @throws IllegalStateException if the current context is different than the one owned by
+ * the scene, or if {@link #acquire(long)} was not called.
+ *
+ * @see RenderSession#removeChild(Object, IAnimationListener)
+ */
+ public Result removeChild(final View childView, final IAnimationListener listener) {
+ checkLock();
+
+ invalidateRenderingSize();
+
+ final ViewGroup parent = (ViewGroup) childView.getParent();
+
+ if (listener != null) {
+ // there is no support for animating views in this API level, so we fake the animation
+ // through a no animation thread.
+ new Thread("not animated moveChild") {
+ @Override
+ public void run() {
+ Result result = removeView(parent, childView);
+ if (result.isSuccess() == false) {
+ listener.done(result);
+ }
+
+ // ready to do the work, acquire the scene.
+ result = acquire(250);
+ if (result.isSuccess() == false) {
+ listener.done(result);
+ return;
+ }
+
+ try {
+ result = render(false /*freshRender*/);
+ if (result.isSuccess()) {
+ listener.onNewFrame(RenderSessionImpl.this.getSession());
+ }
+ } finally {
+ release();
+ }
+
+ listener.done(result);
+ }
+ }.start();
+
+ // always return success since the real status will come through the listener.
+ return SUCCESS.createResult();
+ }
+
+ Result result = removeView(parent, childView);
+ if (result.isSuccess() == false) {
+ return result;
+ }
+
+ return render(false /*freshRender*/);
+ }
+
+ /**
+ * Removes a given view from its current parent.
+ *
+ * @param view the view to remove from its parent
+ *
+ * @return a Result with {@link Status#SUCCESS} or
+ * {@link Status#ERROR_VIEWGROUP_NO_CHILDREN} if the given parent doesn't support
+ * adding views.
+ */
+ private Result removeView(ViewGroup parent, View view) {
+ try {
+ parent.removeView(view);
+ return SUCCESS.createResult();
+ } catch (UnsupportedOperationException e) {
+ // looks like this is a view class that doesn't support children manipulation!
+ return ERROR_VIEWGROUP_NO_CHILDREN.createResult();
+ }
+ }
+
+
+ private void findBackground(RenderResources resources) {
+ if (getParams().isBgColorOverridden() == false) {
+ mWindowBackground = resources.findItemInTheme("windowBackground");
+ if (mWindowBackground != null) {
+ mWindowBackground = resources.resolveResValue(mWindowBackground);
+ }
+ }
+ }
+
+ private void findStatusBar(RenderResources resources, DisplayMetrics metrics) {
+ boolean windowFullscreen = getBooleanThemeValue(resources,
+ "windowFullscreen", false /*defaultValue*/);
+
+ if (windowFullscreen == false && mWindowIsFloating == false) {
+ // default value
+ mStatusBarSize = DEFAULT_STATUS_BAR_HEIGHT;
+
+ // get the real value
+ ResourceValue value = resources.getFrameworkResource(ResourceType.DIMEN,
+ "status_bar_height");
+
+ if (value != null) {
+ TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+ if (typedValue != null) {
+ // compute the pixel value based on the display metrics
+ mStatusBarSize = (int)typedValue.getDimension(metrics);
+ }
+ }
+ }
+ }
+
+ private void findTitleBar(RenderResources resources, DisplayMetrics metrics) {
+ if (mWindowIsFloating) {
+ return;
+ }
+
+ boolean windowNoTitle = getBooleanThemeValue(resources,
+ "windowNoTitle", false /*defaultValue*/);
+
+ if (windowNoTitle == false) {
+
+ // default size of the window title bar
+ mTitleBarSize = DEFAULT_TITLE_BAR_HEIGHT;
+
+ // get value from the theme.
+ ResourceValue value = resources.findItemInTheme("windowTitleSize");
+
+ // resolve it
+ value = resources.resolveResValue(value);
+
+ if (value != null) {
+ // get the numerical value, if available
+ TypedValue typedValue = ResourceHelper.getValue(value.getValue());
+ if (typedValue != null) {
+ // compute the pixel value based on the display metrics
+ mTitleBarSize = (int)typedValue.getDimension(metrics);
+ }
+ }
+ }
+ }
+
+ private boolean getBooleanThemeValue(RenderResources resources,
+ String name, boolean defaultValue) {
+
+ // get the title bar flag from the current theme.
+ ResourceValue value = resources.findItemInTheme(name);
+
+ // because it may reference something else, we resolve it.
+ value = resources.resolveResValue(value);
+
+ // if there's no value, return the default.
+ if (value == null || value.getValue() == null) {
+ return defaultValue;
+ }
+
+ return XmlUtils.convertValueToBoolean(value.getValue(), defaultValue);
+ }
+
+ /**
+ * Post process on a view hierachy that was just inflated.
+ * <p/>At the moment this only support TabHost: If {@link TabHost} is detected, look for the
+ * {@link TabWidget}, and the corresponding {@link FrameLayout} and make new tabs automatically
+ * based on the content of the {@link FrameLayout}.
+ * @param view the root view to process.
+ * @param projectCallback callback to the project.
+ */
+ private void postInflateProcess(View view, IProjectCallback projectCallback)
+ throws PostInflateException {
+ if (view instanceof TabHost) {
+ setupTabHost((TabHost)view, projectCallback);
+ } else if (view instanceof ViewGroup) {
+ ViewGroup group = (ViewGroup)view;
+ final int count = group.getChildCount();
+ for (int c = 0 ; c < count ; c++) {
+ View child = group.getChildAt(c);
+ postInflateProcess(child, projectCallback);
+ }
+ }
+ }
+
+ /**
+ * Sets up a {@link TabHost} object.
+ * @param tabHost the TabHost to setup.
+ * @param projectCallback The project callback object to access the project R class.
+ * @throws PostInflateException
+ */
+ private void setupTabHost(TabHost tabHost, IProjectCallback projectCallback)
+ throws PostInflateException {
+ // look for the TabWidget, and the FrameLayout. They have their own specific names
+ View v = tabHost.findViewById(android.R.id.tabs);
+
+ if (v == null) {
+ throw new PostInflateException(
+ "TabHost requires a TabWidget with id \"android:id/tabs\".\n");
+ }
+
+ if ((v instanceof TabWidget) == false) {
+ throw new PostInflateException(String.format(
+ "TabHost requires a TabWidget with id \"android:id/tabs\".\n" +
+ "View found with id 'tabs' is '%s'", v.getClass().getCanonicalName()));
+ }
+
+ v = tabHost.findViewById(android.R.id.tabcontent);
+
+ if (v == null) {
+ // TODO: see if we can fake tabs even without the FrameLayout (same below when the framelayout is empty)
+ throw new PostInflateException(
+ "TabHost requires a FrameLayout with id \"android:id/tabcontent\".");
+ }
+
+ if ((v instanceof FrameLayout) == false) {
+ throw new PostInflateException(String.format(
+ "TabHost requires a FrameLayout with id \"android:id/tabcontent\".\n" +
+ "View found with id 'tabcontent' is '%s'", v.getClass().getCanonicalName()));
+ }
+
+ FrameLayout content = (FrameLayout)v;
+
+ // now process the content of the framelayout and dynamically create tabs for it.
+ final int count = content.getChildCount();
+
+ // this must be called before addTab() so that the TabHost searches its TabWidget
+ // and FrameLayout.
+ tabHost.setup();
+
+ if (count == 0) {
+ // Create a dummy child to get a single tab
+ TabSpec spec = tabHost.newTabSpec("tag").setIndicator("Tab Label",
+ tabHost.getResources().getDrawable(android.R.drawable.ic_menu_info_details))
+ .setContent(new TabHost.TabContentFactory() {
+ public View createTabContent(String tag) {
+ return new LinearLayout(getContext());
+ }
+ });
+ tabHost.addTab(spec);
+ return;
+ } else {
+ // for each child of the framelayout, add a new TabSpec
+ for (int i = 0 ; i < count ; i++) {
+ View child = content.getChildAt(i);
+ String tabSpec = String.format("tab_spec%d", i+1);
+ int id = child.getId();
+ Pair<ResourceType, String> resource = projectCallback.resolveResourceId(id);
+ String name;
+ if (resource != null) {
+ name = resource.getSecond();
+ } else {
+ name = String.format("Tab %d", i+1); // default name if id is unresolved.
+ }
+ tabHost.addTab(tabHost.newTabSpec(tabSpec).setIndicator(name).setContent(id));
+ }
+ }
+ }
+
+ private List<ViewInfo> startVisitingViews(View view, int offset) {
+ if (view == null) {
+ return null;
+ }
+
+ // adjust the offset to this view.
+ offset += view.getTop();
+
+ if (view == mContentRoot) {
+ return visitAllChildren(mContentRoot, offset);
+ }
+
+ // otherwise, look for mContentRoot in the children
+ if (view instanceof ViewGroup) {
+ ViewGroup group = ((ViewGroup) view);
+
+ for (int i = 0; i < group.getChildCount(); i++) {
+ List<ViewInfo> list = startVisitingViews(group.getChildAt(i), offset);
+ if (list != null) {
+ return list;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Visits a View and its children and generate a {@link ViewInfo} containing the
+ * bounds of all the views.
+ * @param view the root View
+ * @param offset an offset for the view bounds.
+ */
+ private ViewInfo visit(View view, int offset) {
+ if (view == null) {
+ return null;
+ }
+
+ ViewInfo result = new ViewInfo(view.getClass().getName(),
+ getContext().getViewKey(view),
+ view.getLeft(), view.getTop() + offset, view.getRight(), view.getBottom() + offset,
+ view, view.getLayoutParams());
+
+ if (view instanceof ViewGroup) {
+ ViewGroup group = ((ViewGroup) view);
+ result.setChildren(visitAllChildren(group, 0 /*offset*/));
+ }
+
+ return result;
+ }
+
+ /**
+ * Visits all the children of a given ViewGroup generate a list of {@link ViewInfo}
+ * containing the bounds of all the views.
+ * @param view the root View
+ * @param offset an offset for the view bounds.
+ */
+ private List<ViewInfo> visitAllChildren(ViewGroup viewGroup, int offset) {
+ if (viewGroup == null) {
+ return null;
+ }
+
+ List<ViewInfo> children = new ArrayList<ViewInfo>();
+ for (int i = 0; i < viewGroup.getChildCount(); i++) {
+ children.add(visit(viewGroup.getChildAt(i), offset));
+ }
+ return children;
+ }
+
+
+ private void invalidateRenderingSize() {
+ mMeasuredScreenWidth = mMeasuredScreenHeight = -1;
+ }
+
+ public BufferedImage getImage() {
+ return mImage;
+ }
+
+ public boolean isAlphaChannelImage() {
+ return mIsAlphaChannelImage;
+ }
+
+ public List<ViewInfo> getViewInfos() {
+ return mViewInfoList;
+ }
+
+ public Map<String, String> getDefaultProperties(Object viewObject) {
+ return getContext().getDefaultPropMap(viewObject);
+ }
+
+ public void setScene(RenderSession session) {
+ mScene = session;
+ }
+
+ public RenderSession getSession() {
+ return mScene;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
index f624753..649160e 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/ResourceHelper.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ResourceHelper.java
@@ -14,33 +14,45 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
-
-import com.android.layoutlib.api.IDensityBasedResourceValue;
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.api.IDensityBasedResourceValue.Density;
+package com.android.layoutlib.bridge.impl;
+
+import com.android.ide.common.rendering.api.DensityBasedResourceValue;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.RenderResources;
+import com.android.ide.common.rendering.api.ResourceValue;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.ninepatch.NinePatch;
+import com.android.ninepatch.NinePatchChunk;
+import com.android.resources.Density;
import org.kxml2.io.KXmlParser;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.res.ColorStateList;
import android.graphics.Bitmap;
+import android.graphics.Bitmap_Delegate;
+import android.graphics.NinePatch_Delegate;
+import android.graphics.Rect;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
+import android.graphics.drawable.NinePatchDrawable;
import android.util.TypedValue;
import java.io.File;
-import java.io.FileNotFoundException;
+import java.io.FileInputStream;
import java.io.FileReader;
import java.io.IOException;
+import java.io.InputStream;
import java.net.MalformedURLException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
- * Helper class to provide various convertion method used in handling android resources.
+ * Helper class to provide various conversion method used in handling android resources.
*/
public final class ResourceHelper {
@@ -55,17 +67,21 @@ public final class ResourceHelper {
* @return the color as an int
* @throw NumberFormatException if the conversion failed.
*/
- static int getColor(String value) {
+ public static int getColor(String value) {
if (value != null) {
if (value.startsWith("#") == false) {
- throw new NumberFormatException();
+ throw new NumberFormatException(
+ String.format("Color value '%s' must start with #", value));
}
value = value.substring(1);
// make sure it's not longer than 32bit
if (value.length() > 8) {
- throw new NumberFormatException();
+ throw new NumberFormatException(String.format(
+ "Color value '%s' is too long. Format is either" +
+ "#AARRGGBB, #RRGGBB, #RGB, or #ARGB",
+ value));
}
if (value.length() == 3) { // RGB format
@@ -97,48 +113,93 @@ public final class ResourceHelper {
throw new NumberFormatException();
}
+ public static ColorStateList getColorStateList(ResourceValue resValue, BridgeContext context) {
+ String value = resValue.getValue();
+ if (value != null) {
+ // first check if the value is a file (xml most likely)
+ File f = new File(value);
+ if (f.isFile()) {
+ try {
+ // let the framework inflate the ColorStateList from the XML file, by
+ // providing an XmlPullParser
+ KXmlParser parser = new KXmlParser();
+ parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+ parser.setInput(new FileReader(f));
+
+ BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
+ parser, context, resValue.isFramework());
+ try {
+ return ColorStateList.createFromXml(context.getResources(), blockParser);
+ } finally {
+ blockParser.ensurePopped();
+ }
+ } catch (XmlPullParserException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Failed to configure parser for " + value, e, null /*data*/);
+ // we'll return null below.
+ } catch (Exception e) {
+ // this is an error and not warning since the file existence is
+ // checked before attempting to parse it.
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+ "Failed to parse file " + value, e, null /*data*/);
+
+ return null;
+ }
+ } else {
+ // try to load the color state list from an int
+ try {
+ int color = ResourceHelper.getColor(value);
+ return ColorStateList.valueOf(color);
+ } catch (NumberFormatException e) {
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
+ "Failed to convert " + value + " into a ColorStateList", e,
+ null /*data*/);
+ return null;
+ }
+ }
+ }
+
+ return null;
+ }
+
/**
* Returns a drawable from the given value.
* @param value The value that contains a path to a 9 patch, a bitmap or a xml based drawable,
* or an hexadecimal color
- * @param context
- * @param isFramework indicates whether the resource is a framework resources.
- * Framework resources are cached, and loaded only once.
+ * @param context the current context
*/
- public static Drawable getDrawable(IResourceValue value, BridgeContext context, boolean isFramework) {
- Drawable d = null;
-
+ public static Drawable getDrawable(ResourceValue value, BridgeContext context) {
String stringValue = value.getValue();
+ if (RenderResources.REFERENCE_NULL.equals(stringValue)) {
+ return null;
+ }
String lowerCaseValue = stringValue.toLowerCase();
+ Density density = Density.MEDIUM;
+ if (value instanceof DensityBasedResourceValue) {
+ density =
+ ((DensityBasedResourceValue)value).getResourceDensity();
+ }
+
+
if (lowerCaseValue.endsWith(NinePatch.EXTENSION_9PATCH)) {
File file = new File(stringValue);
if (file.isFile()) {
- NinePatch ninePatch = Bridge.getCached9Patch(stringValue,
- isFramework ? null : context.getProjectKey());
-
- if (ninePatch == null) {
- try {
- ninePatch = NinePatch.load(file.toURL(), false /* convert */);
-
- Bridge.setCached9Patch(stringValue, ninePatch,
- isFramework ? null : context.getProjectKey());
- } catch (MalformedURLException e) {
- // URL is wrong, we'll return null below
- } catch (IOException e) {
- // failed to read the file, we'll return null below.
- }
- }
-
- if (ninePatch != null) {
- return new NinePatchDrawable(ninePatch);
+ try {
+ return getNinePatchDrawable(
+ new FileInputStream(file), density, value.isFramework(),
+ stringValue, context);
+ } catch (IOException e) {
+ // failed to read the file, we'll return null below.
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+ "Failed lot load " + file.getAbsolutePath(), e, null /*data*/);
}
}
return null;
} else if (lowerCaseValue.endsWith(".xml")) {
- // create a blockparser for the file
+ // create a block parser for the file
File f = new File(stringValue);
if (f.isFile()) {
try {
@@ -147,16 +208,23 @@ public final class ResourceHelper {
parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
parser.setInput(new FileReader(f));
- d = Drawable.createFromXml(context.getResources(),
- new BridgeXmlBlockParser(parser, context, isFramework));
- return d;
- } catch (XmlPullParserException e) {
- context.getLogger().error(e);
- } catch (FileNotFoundException e) {
- // will not happen, since we pre-check
- } catch (IOException e) {
- context.getLogger().error(e);
+ BridgeXmlBlockParser blockParser = new BridgeXmlBlockParser(
+ parser, context, value.isFramework());
+ try {
+ return Drawable.createFromXml(context.getResources(), blockParser);
+ } finally {
+ blockParser.ensurePopped();
+ }
+ } catch (Exception e) {
+ // this is an error and not warning since the file existence is checked before
+ // attempting to parse it.
+ Bridge.getLog().error(null, "Failed to parse file " + stringValue,
+ e, null /*data*/);
}
+ } else {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ String.format("File %s does not exist (or is not a file)", stringValue),
+ null /*data*/);
}
return null;
@@ -165,42 +233,20 @@ public final class ResourceHelper {
if (bmpFile.isFile()) {
try {
Bitmap bitmap = Bridge.getCachedBitmap(stringValue,
- isFramework ? null : context.getProjectKey());
+ value.isFramework() ? null : context.getProjectKey());
if (bitmap == null) {
- bitmap = new Bitmap(bmpFile);
- try {
- bitmap.setDensity(Density.MEDIUM.getValue());
- } catch (NoClassDefFoundError error) {
- // look like we're running in an older version of ADT that doesn't
- // include the new layoutlib_api. Let's just ignore this, the drawing
- // will just be wrong.
- }
+ bitmap = Bitmap_Delegate.createBitmap(bmpFile, false /*isMutable*/,
+ density);
Bridge.setCachedBitmap(stringValue, bitmap,
- isFramework ? null : context.getProjectKey());
- }
-
- try {
- if (value instanceof IDensityBasedResourceValue) {
- Density density = ((IDensityBasedResourceValue)value).getDensity();
- if (density != Density.MEDIUM) {
- // create a copy of the bitmap
- bitmap = Bitmap.createBitmap(bitmap);
-
- // apply the density
- bitmap.setDensity(density.getValue());
- }
- }
- } catch (NoClassDefFoundError error) {
- // look like we're running in an older version of ADT that doesn't include
- // the new layoutlib_api. Let's just ignore this, the drawing will just be
- // wrong.
+ value.isFramework() ? null : context.getProjectKey());
}
return new BitmapDrawable(context.getResources(), bitmap);
} catch (IOException e) {
// we'll return null below
- // TODO: log the error.
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_READ,
+ "Failed lot load " + bmpFile.getAbsolutePath(), e, null /*data*/);
}
} else {
// attempt to get a color from the value
@@ -209,7 +255,9 @@ public final class ResourceHelper {
return new ColorDrawable(color);
} catch (NumberFormatException e) {
// we'll return null below.
- // TODO: log the error
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
+ "Failed to convert " + stringValue + " into a drawable", e,
+ null /*data*/);
}
}
}
@@ -217,6 +265,52 @@ public final class ResourceHelper {
return null;
}
+ private static Drawable getNinePatchDrawable(InputStream inputStream, Density density,
+ boolean isFramework, String cacheKey, BridgeContext context) throws IOException {
+ // see if we still have both the chunk and the bitmap in the caches
+ NinePatchChunk chunk = Bridge.getCached9Patch(cacheKey,
+ isFramework ? null : context.getProjectKey());
+ Bitmap bitmap = Bridge.getCachedBitmap(cacheKey,
+ isFramework ? null : context.getProjectKey());
+
+ // if either chunk or bitmap is null, then we reload the 9-patch file.
+ if (chunk == null || bitmap == null) {
+ try {
+ NinePatch ninePatch = NinePatch.load(inputStream, true /*is9Patch*/,
+ false /* convert */);
+ if (ninePatch != null) {
+ if (chunk == null) {
+ chunk = ninePatch.getChunk();
+
+ Bridge.setCached9Patch(cacheKey, chunk,
+ isFramework ? null : context.getProjectKey());
+ }
+
+ if (bitmap == null) {
+ bitmap = Bitmap_Delegate.createBitmap(ninePatch.getImage(),
+ false /*isMutable*/,
+ density);
+
+ Bridge.setCachedBitmap(cacheKey, bitmap,
+ isFramework ? null : context.getProjectKey());
+ }
+ }
+ } catch (MalformedURLException e) {
+ // URL is wrong, we'll return null below
+ }
+ }
+
+ if (chunk != null && bitmap != null) {
+ int[] padding = chunk.getPadding();
+ Rect paddingRect = new Rect(padding[0], padding[1], padding[2], padding[3]);
+
+ return new NinePatchDrawable(context.getResources(), bitmap,
+ NinePatch_Delegate.serialize(chunk),
+ paddingRect, null);
+ }
+
+ return null;
+ }
// ------- TypedValue stuff
// This is taken from //device/libs/utils/ResourceTypes.cpp
@@ -267,7 +361,7 @@ public final class ResourceHelper {
*/
public static boolean stringToFloat(String s, TypedValue outValue) {
// remove the space before and after
- s.trim();
+ s = s.trim();
int len = s.length();
if (len <= 0) {
@@ -283,7 +377,7 @@ public final class ResourceHelper {
}
// check the first character
- if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.') {
+ if (buf[0] < '0' && buf[0] > '9' && buf[0] != '.' && buf[0] != '-') {
return false;
}
@@ -379,3 +473,4 @@ public final class ResourceHelper {
return false;
}
}
+
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Stack.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Stack.java
new file mode 100644
index 0000000..9bd0015
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/Stack.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.impl;
+
+import java.util.ArrayList;
+
+/**
+ * Custom Stack implementation on top of an {@link ArrayList} instead of
+ * using {@link java.util.Stack} which is on top of a vector.
+ *
+ * @param <T>
+ */
+public class Stack<T> extends ArrayList<T> {
+
+ private static final long serialVersionUID = 1L;
+
+ public Stack() {
+ super();
+ }
+
+ public Stack(int size) {
+ super(size);
+ }
+
+ /**
+ * Pushes the given object to the stack
+ * @param object the object to push
+ */
+ public void push(T object) {
+ add(object);
+ }
+
+ /**
+ * Remove the object at the top of the stack and returns it.
+ * @return the removed object or null if the stack was empty.
+ */
+ public T pop() {
+ if (size() > 0) {
+ return remove(size() - 1);
+ }
+
+ return null;
+ }
+
+ /**
+ * Returns the object at the top of the stack.
+ * @return the object at the top or null if the stack is empty.
+ */
+ public T peek() {
+ if (size() > 0) {
+ return get(size() - 1);
+ }
+
+ return null;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/Debug.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/Debug.java
new file mode 100644
index 0000000..82eab85
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/Debug.java
@@ -0,0 +1,23 @@
+/*
+ * 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.layoutlib.bridge.util;
+
+public class Debug {
+
+ public final static boolean DEBUG = false;
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
new file mode 100644
index 0000000..4d0c9ce
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
@@ -0,0 +1,376 @@
+/*
+ * 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.layoutlib.bridge.util;
+
+
+import com.android.internal.util.ArrayUtils;
+
+import android.util.SparseArray;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * This is a custom {@link SparseArray} that uses {@link WeakReference} around the objects added
+ * to it. When the array is compacted, not only deleted indices but also empty references
+ * are removed, making the array efficient at removing references that were reclaimed.
+ *
+ * The code is taken from {@link SparseArray} directly and adapted to use weak references.
+ *
+ * Because our usage means that we never actually call {@link #remove(int)} or {@link #delete(int)},
+ * we must manually check if there are reclaimed references to trigger an internal compact step
+ * (which is normally only triggered when an item is manually removed).
+ *
+ * SparseArrays map integers to Objects. Unlike a normal array of Objects,
+ * there can be gaps in the indices. It is intended to be more efficient
+ * than using a HashMap to map Integers to Objects.
+ */
+@SuppressWarnings("unchecked")
+public class SparseWeakArray<E> {
+
+ private static final Object DELETED_REF = new Object();
+ private static final WeakReference<?> DELETED = new WeakReference(DELETED_REF);
+ private boolean mGarbage = false;
+
+ /**
+ * Creates a new SparseArray containing no mappings.
+ */
+ public SparseWeakArray() {
+ this(10);
+ }
+
+ /**
+ * Creates a new SparseArray containing no mappings that will not
+ * require any additional memory allocation to store the specified
+ * number of mappings.
+ */
+ public SparseWeakArray(int initialCapacity) {
+ initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+
+ mKeys = new int[initialCapacity];
+ mValues = new WeakReference[initialCapacity];
+ mSize = 0;
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or <code>null</code>
+ * if no such mapping has been made.
+ */
+ public E get(int key) {
+ return get(key, null);
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or the specified Object
+ * if no such mapping has been made.
+ */
+ public E get(int key, E valueIfKeyNotFound) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i < 0 || mValues[i] == DELETED || mValues[i].get() == null) {
+ return valueIfKeyNotFound;
+ } else {
+ return (E) mValues[i].get();
+ }
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ if (mValues[i] != DELETED) {
+ mValues[i] = DELETED;
+ mGarbage = true;
+ }
+ }
+ }
+
+ /**
+ * Alias for {@link #delete(int)}.
+ */
+ public void remove(int key) {
+ delete(key);
+ }
+
+ /**
+ * Removes the mapping at the specified index.
+ */
+ public void removeAt(int index) {
+ if (mValues[index] != DELETED) {
+ mValues[index] = DELETED;
+ mGarbage = true;
+ }
+ }
+
+ private void gc() {
+ int n = mSize;
+ int o = 0;
+ int[] keys = mKeys;
+ WeakReference<?>[] values = mValues;
+
+ for (int i = 0; i < n; i++) {
+ WeakReference<?> val = values[i];
+
+ // Don't keep any non DELETED values, but only the one that still have a valid
+ // reference.
+ if (val != DELETED && val.get() != null) {
+ if (i != o) {
+ keys[o] = keys[i];
+ values[o] = val;
+ }
+
+ o++;
+ }
+ }
+
+ mGarbage = false;
+ mSize = o;
+
+ int newSize = ArrayUtils.idealIntArraySize(mSize);
+ if (newSize < mKeys.length) {
+ int[] nkeys = new int[newSize];
+ WeakReference<?>[] nvalues = new WeakReference[newSize];
+
+ System.arraycopy(mKeys, 0, nkeys, 0, newSize);
+ System.arraycopy(mValues, 0, nvalues, 0, newSize);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, E value) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ mValues[i] = new WeakReference(value);
+ } else {
+ i = ~i;
+
+ if (i < mSize && (mValues[i] == DELETED || mValues[i].get() == null)) {
+ mKeys[i] = key;
+ mValues[i] = new WeakReference(value);
+ return;
+ }
+
+ if (mSize >= mKeys.length && (mGarbage || hasReclaimedRefs())) {
+ gc();
+
+ // Search again because indices may have changed.
+ i = ~binarySearch(mKeys, 0, mSize, key);
+ }
+
+ if (mSize >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(mSize + 1);
+
+ int[] nkeys = new int[n];
+ WeakReference<?>[] nvalues = new WeakReference[n];
+
+ // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ if (mSize - i != 0) {
+ // Log.e("SparseArray", "move " + (mSize - i));
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+
+ mKeys[i] = key;
+ mValues[i] = new WeakReference(value);
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseArray
+ * currently stores.
+ */
+ public int size() {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mSize;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public int keyAt(int index) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mKeys[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public E valueAt(int index) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return (E) mValues[index].get();
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, sets a new
+ * value for the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public void setValueAt(int index, E value) {
+ if (mGarbage) {
+ gc();
+ }
+
+ mValues[index] = new WeakReference(value);
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return binarySearch(mKeys, 0, mSize, key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(E value) {
+ if (mGarbage) {
+ gc();
+ }
+
+ for (int i = 0; i < mSize; i++)
+ if (mValues[i].get() == value)
+ return i;
+
+ return -1;
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseArray.
+ */
+ public void clear() {
+ int n = mSize;
+ WeakReference<?>[] values = mValues;
+
+ for (int i = 0; i < n; i++) {
+ values[i] = null;
+ }
+
+ mSize = 0;
+ mGarbage = false;
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, E value) {
+ if (mSize != 0 && key <= mKeys[mSize - 1]) {
+ put(key, value);
+ return;
+ }
+
+ if (mSize >= mKeys.length && (mGarbage || hasReclaimedRefs())) {
+ gc();
+ }
+
+ int pos = mSize;
+ if (pos >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(pos + 1);
+
+ int[] nkeys = new int[n];
+ WeakReference<?>[] nvalues = new WeakReference[n];
+
+ // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ mKeys[pos] = key;
+ mValues[pos] = new WeakReference(value);
+ mSize = pos + 1;
+ }
+
+ private boolean hasReclaimedRefs() {
+ for (int i = 0 ; i < mSize ; i++) {
+ if (mValues[i].get() == null) { // DELETED.get() never returns null.
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static int binarySearch(int[] a, int start, int len, int key) {
+ int high = start + len, low = start - 1, guess;
+
+ while (high - low > 1) {
+ guess = (high + low) / 2;
+
+ if (a[guess] < key)
+ low = guess;
+ else
+ high = guess;
+ }
+
+ if (high == start + len)
+ return ~(start + len);
+ else if (a[high] == key)
+ return high;
+ else
+ return ~high;
+ }
+
+ private int[] mKeys;
+ private WeakReference<?>[] mValues;
+ private int mSize;
+}
diff --git a/tools/layoutlib/bridge/tests/.classpath b/tools/layoutlib/bridge/tests/.classpath
new file mode 100644
index 0000000..9cc2433
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/.classpath
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+ <classpathentry kind="src" path="src"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+ <classpathentry combineaccessrules="false" kind="src" path="/layoutlib_bridge"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/3"/>
+ <classpathentry kind="output" path="bin"/>
+</classpath>
diff --git a/tools/layoutlib/bridge/tests/.project b/tools/layoutlib/bridge/tests/.project
new file mode 100644
index 0000000..2325eed
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/.project
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>layoutlib_bridge-tests</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.eclipse.jdt.core.javabuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.eclipse.jdt.core.javanature</nature>
+ </natures>
+</projectDescription>
diff --git a/tools/layoutlib/bridge/tests/Android.mk b/tools/layoutlib/bridge/tests/Android.mk
new file mode 100644
index 0000000..e303638
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/Android.mk
@@ -0,0 +1,30 @@
+# 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.
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+# Only compile source java files in this lib.
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_MODULE := layoutlib-tests
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_JAVA_LIBRARIES := layoutlib kxml2-2.3.0 junit
+
+include $(BUILD_HOST_JAVA_LIBRARY)
+
+# Build all sub-directories
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java
deleted file mode 100644
index 23351ab..0000000
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/NinePatchTest.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge;
-
-import com.android.ninepatch.NinePatch;
-
-import java.net.URL;
-
-import junit.framework.TestCase;
-
-public class NinePatchTest extends TestCase {
-
- private NinePatch mPatch;
-
- @Override
- protected void setUp() throws Exception {
- URL url = this.getClass().getClassLoader().getResource(
- "com/android/layoutlib/testdata/button.9.png");
-
- mPatch = NinePatch.load(url, false /* convert */);
- }
-
- public void test9PatchLoad() throws Exception {
- assertNotNull(mPatch);
- }
-
- public void test9PatchMinSize() {
- int[] padding = new int[4];
- mPatch.getPadding(padding);
- assertEquals(13, padding[0]);
- assertEquals(3, padding[1]);
- assertEquals(13, padding[2]);
- assertEquals(4, padding[3]);
- assertEquals(36, mPatch.getWidth());
- assertEquals(25, mPatch.getHeight());
- }
-
-}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java
deleted file mode 100644
index e0dc55f..0000000
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 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.
- */
-
-package com.android.layoutlib.bridge;
-
-import java.lang.reflect.Method;
-
-import junit.framework.TestCase;
-
-public class TestClassReplacement extends TestCase {
-
- public void testClassReplacements() {
- // TODO: we want to test all the classes. For now only Paint passes the tests.
-// final String[] classes = CreateInfo.RENAMED_CLASSES;
- final String[] classes = new String[] {
- "android.graphics.Paint", "android.graphics._Original_Paint"
- };
- final int count = classes.length;
- for (int i = 0 ; i < count ; i += 2) {
- loadAndCompareClasses(classes[i], classes[i+1]);
- }
- }
-
- private void loadAndCompareClasses(String newClassName, String oldClassName) {
- // load the classes
- try {
- Class<?> newClass = TestClassReplacement.class.getClassLoader().loadClass(newClassName);
- Class<?> oldClass = TestClassReplacement.class.getClassLoader().loadClass(oldClassName);
-
- compare(newClass, oldClass);
- } catch (ClassNotFoundException e) {
- fail("Failed to load class: " + e.getMessage());
- }
- }
-
- private void compare(Class<?> newClass, Class<?> oldClass) {
- // first compare the methods.
- Method[] newClassMethods = newClass.getDeclaredMethods();
- Method[] oldClassMethods = oldClass.getDeclaredMethods();
-
- for (Method oldMethod : oldClassMethods) {
- // we ignore anything that starts with native
- if (oldMethod.getName().startsWith("native")) {
- continue;
- }
- boolean found = false;
- for (Method newMethod : newClassMethods) {
- if (compareMethods(newClass, newMethod, oldClass, oldMethod)) {
- found = true;
- break;
- }
- }
-
- if (found == false) {
- fail(String.format("Unable to find %1$s", oldMethod.toGenericString()));
- }
- }
-
- // TODO: check (somehow?) that the methods that were removed from the original class
- // have been put back in the new class!
- // For this we need the original unmodified class (ie renamed, but w/o the methods removed)
- }
-
- private boolean compareMethods(Class<?> newClass, Method newMethod,
- Class<?> oldClass, Method oldMethod) {
- // first check the name of the method
- if (newMethod.getName().equals(oldMethod.getName()) == false) {
- return false;
- }
-
- // check the return value
- Class<?> oldReturnType = oldMethod.getReturnType();
- // if it's the old class, or if it's a inner class of the oldclass, we need to change this.
- oldReturnType = adapt(oldReturnType, newClass, oldClass);
-
- // compare the return types
- Class<?> newReturnType = newMethod.getReturnType();
- if (newReturnType.equals(oldReturnType) == false) {
- return false;
- }
-
- // now check the parameters type.
- Class<?>[] oldParameters = oldMethod.getParameterTypes();
- Class<?>[] newParemeters = newMethod.getParameterTypes();
- if (oldParameters.length != newParemeters.length) {
- return false;
- }
-
- for (int i = 0 ; i < oldParameters.length ; i++) {
- if (newParemeters[i].equals(adapt(oldParameters[i], newClass, oldClass)) == false) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Adapts a class to deal with renamed classes.
- * <p/>For instance if old class is <code>android.graphics._Original_Paint</code> and the
- * new class is <code>android.graphics.Paint</code> and the class to adapt is
- * <code>android.graphics._Original_Paint$Cap</code>, then the method will return a
- * {@link Class} object representing <code>android.graphics.Paint$Cap</code>.
- * <p/>
- * This method will also ensure that all renamed classes contains all the proper inner classes
- * that they should be declaring.
- * @param theClass the class to adapt
- * @param newClass the new class object
- * @param oldClass the old class object
- * @return the adapted class.
- * @throws ClassNotFoundException
- */
- private Class<?> adapt(Class<?> theClass, Class<?> newClass, Class<?> oldClass) {
- // only look for a new class if it's not primitive as Class.forName() would fail otherwise.
- if (theClass.isPrimitive() == false) {
- String n = theClass.getName().replace(oldClass.getName(), newClass.getName());
- try {
- return Class.forName(n);
- } catch (ClassNotFoundException e) {
- fail("Missing class: " + n);
- }
- }
-
- return theClass;
- }
-}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/button.9.png b/tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/button.9.png
deleted file mode 100644
index 9d52f40..0000000
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/button.9.png
+++ /dev/null
Binary files differ
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java b/tools/layoutlib/bridge/tests/src/android/graphics/Matrix_DelegateTest.java
index 6e14e82..ec4edac 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/AndroidGraphicsTests.java
+++ b/tools/layoutlib/bridge/tests/src/android/graphics/Matrix_DelegateTest.java
@@ -14,19 +14,14 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
-
-import android.graphics.Matrix;
-import android.graphics.Paint;
-import android.graphics._Original_Paint;
-import android.text.TextPaint;
+package android.graphics;
import junit.framework.TestCase;
/**
*
*/
-public class AndroidGraphicsTests extends TestCase {
+public class Matrix_DelegateTest extends TestCase {
@Override
protected void setUp() throws Exception {
@@ -38,14 +33,17 @@ public class AndroidGraphicsTests extends TestCase {
super.tearDown();
}
- public void testMatrix() {
+ public void testIdentity() {
Matrix m1 = new Matrix();
assertTrue(m1.isIdentity());
m1.setValues(new float[] { 1,0,0, 0,1,0, 0,0,1 });
assertTrue(m1.isIdentity());
+ }
+ public void testCopyConstructor() {
+ Matrix m1 = new Matrix();
Matrix m2 = new Matrix(m1);
float[] v1 = new float[9];
@@ -57,17 +55,4 @@ public class AndroidGraphicsTests extends TestCase {
assertEquals(v1[i], v2[i]);
}
}
-
- public void testPaint() {
- _Original_Paint o = new _Original_Paint();
- assertNotNull(o);
-
- Paint p = new Paint();
- assertNotNull(p);
- }
-
- public void textTextPaint() {
- TextPaint p = new TextPaint();
- assertNotNull(p);
- }
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
new file mode 100644
index 0000000..d3218db
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/TestDelegates.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+import com.android.tools.layoutlib.create.CreateInfo;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
+
+import junit.framework.TestCase;
+
+/**
+ * Tests that native delegate classes implement all the required methods.
+ *
+ * This looks at {@link CreateInfo#DELEGATE_CLASS_NATIVES} to get the list of classes that
+ * have their native methods reimplemented through a delegate.
+ *
+ * Since the reimplemented methods are not native anymore, we look for the annotation
+ * {@link LayoutlibDelegate}, and look for a matching method in the delegate (named the same
+ * as the modified class with _Delegate added as a suffix).
+ * If the original native method is not static, then we make sure the delegate method also
+ * include the original class as first parameter (to access "this").
+ *
+ */
+public class TestDelegates extends TestCase {
+
+ public void testNativeDelegates() {
+
+ final String[] classes = CreateInfo.DELEGATE_CLASS_NATIVES;
+ final int count = classes.length;
+ for (int i = 0 ; i < count ; i++) {
+ loadAndCompareClasses(classes[i], classes[i] + "_Delegate");
+ }
+ }
+
+ public void testMethodDelegates() {
+ final String[] methods = CreateInfo.DELEGATE_METHODS;
+ final int count = methods.length;
+ for (int i = 0 ; i < count ; i++) {
+ String methodName = methods[i];
+
+ // extract the class name
+ String className = methodName.substring(0, methodName.indexOf('#'));
+ String targetClassName = className.replace('$', '_') + "_Delegate";
+
+ loadAndCompareClasses(className, targetClassName);
+ }
+ }
+
+ private void loadAndCompareClasses(String originalClassName, String delegateClassName) {
+ // load the classes
+ try {
+ ClassLoader classLoader = TestDelegates.class.getClassLoader();
+ Class<?> originalClass = classLoader.loadClass(originalClassName);
+ Class<?> delegateClass = classLoader.loadClass(delegateClassName);
+
+ compare(originalClass, delegateClass);
+ } catch (ClassNotFoundException e) {
+ fail("Failed to load class: " + e.getMessage());
+ } catch (SecurityException e) {
+ fail("Failed to load class: " + e.getMessage());
+ }
+ }
+
+ private void compare(Class<?> originalClass, Class<?> delegateClass) throws SecurityException {
+ List<Method> checkedDelegateMethods = new ArrayList<Method>();
+
+ // loop on the methods of the original class, and for the ones that are annotated
+ // with @LayoutlibDelegate, look for a matching method in the delegate class.
+ // The annotation is automatically added by layoutlib_create when it replace a method
+ // by a call to a delegate
+ Method[] originalMethods = originalClass.getDeclaredMethods();
+ for (Method originalMethod : originalMethods) {
+ // look for methods that are delegated: they have the LayoutlibDelegate annotation
+ if (originalMethod.getAnnotation(LayoutlibDelegate.class) == null) {
+ continue;
+ }
+
+ // get the signature.
+ Class<?>[] parameters = originalMethod.getParameterTypes();
+
+ // if the method is not static, then the class is added as the first parameter
+ // (for "this")
+ if ((originalMethod.getModifiers() & Modifier.STATIC) == 0) {
+
+ Class<?>[] newParameters = new Class<?>[parameters.length + 1];
+ newParameters[0] = originalClass;
+ System.arraycopy(parameters, 0, newParameters, 1, parameters.length);
+ parameters = newParameters;
+ }
+
+ // if the original class is an inner class that's not static, then
+ // we add this on the enclosing class at the beginning
+ if (originalClass.getEnclosingClass() != null &&
+ (originalClass.getModifiers() & Modifier.STATIC) == 0) {
+ Class<?>[] newParameters = new Class<?>[parameters.length + 1];
+ newParameters[0] = originalClass.getEnclosingClass();
+ System.arraycopy(parameters, 0, newParameters, 1, parameters.length);
+ parameters = newParameters;
+ }
+
+ try {
+ // try to load the method with the given parameter types.
+ Method delegateMethod = delegateClass.getDeclaredMethod(originalMethod.getName(),
+ parameters);
+
+ // check that the method has the annotation
+ assertNotNull(
+ String.format(
+ "Delegate method %1$s for class %2$s does not have the @LayoutlibDelegate annotation",
+ delegateMethod.getName(),
+ originalClass.getName()),
+ delegateMethod.getAnnotation(LayoutlibDelegate.class));
+
+ // check that the method is static
+ assertTrue(
+ String.format(
+ "Delegate method %1$s for class %2$s is not static",
+ delegateMethod.getName(),
+ originalClass.getName()),
+ (delegateMethod.getModifiers() & Modifier.STATIC) == Modifier.STATIC);
+
+ // add the method as checked.
+ checkedDelegateMethods.add(delegateMethod);
+ } catch (NoSuchMethodException e) {
+ String name = getMethodName(originalMethod, parameters);
+ fail(String.format("Missing %1$s.%2$s", delegateClass.getName(), name));
+ }
+ }
+
+ // look for dead (delegate) code.
+ // This looks for all methods in the delegate class, and if they have the
+ // @LayoutlibDelegate annotation, make sure they have been previously found as a
+ // match for a method in the original class.
+ // If not, this means the method is a delegate for a method that either doesn't exist
+ // anymore or is not delegated anymore.
+ Method[] delegateMethods = delegateClass.getDeclaredMethods();
+ for (Method delegateMethod : delegateMethods) {
+ // look for methods that are delegates: they have the LayoutlibDelegate annotation
+ if (delegateMethod.getAnnotation(LayoutlibDelegate.class) == null) {
+ continue;
+ }
+
+ assertTrue(
+ String.format(
+ "Delegate method %1$s.%2$s is not used anymore and must be removed",
+ delegateClass.getName(),
+ getMethodName(delegateMethod)),
+ checkedDelegateMethods.contains(delegateMethod));
+ }
+
+ }
+
+ private String getMethodName(Method method) {
+ return getMethodName(method, method.getParameterTypes());
+ }
+
+ private String getMethodName(Method method, Class<?>[] parameters) {
+ // compute a full class name that's long but not too long.
+ StringBuilder sb = new StringBuilder(method.getName() + "(");
+ for (int j = 0; j < parameters.length; j++) {
+ Class<?> theClass = parameters[j];
+ sb.append(theClass.getName());
+ int dimensions = 0;
+ while (theClass.isArray()) {
+ dimensions++;
+ theClass = theClass.getComponentType();
+ }
+ for (int i = 0; i < dimensions; i++) {
+ sb.append("[]");
+ }
+ if (j < (parameters.length - 1)) {
+ sb.append(",");
+ }
+ }
+ sb.append(")");
+
+ return sb.toString();
+ }
+}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
index db1262f..3252fb4 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/BridgeXmlBlockParserTest.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/android/BridgeXmlBlockParserTest.java
@@ -14,7 +14,9 @@
* limitations under the License.
*/
-package com.android.layoutlib.bridge;
+package com.android.layoutlib.bridge.android;
+
+import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import org.kxml2.io.KXmlParser;
import org.w3c.dom.Node;
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/layout1.xml b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/testdata/layout1.xml
index b8fc947..b8fc947 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/testdata/layout1.xml
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/testdata/layout1.xml
diff --git a/tools/layoutlib/create/README.txt b/tools/layoutlib/create/README.txt
index c59e20d..65a64cd 100644
--- a/tools/layoutlib/create/README.txt
+++ b/tools/layoutlib/create/README.txt
@@ -195,5 +195,22 @@ example, the inner class Paint$Style in the Paint class should be discarded and
bridge will provide its own implementation.
+- References -
+--------------
+
+
+The JVM Specification 2nd edition:
+ http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html
+
+Understanding bytecode:
+ http://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/
+
+Bytecode opcode list:
+ http://en.wikipedia.org/wiki/Java_bytecode_instruction_listings
+
+ASM user guide:
+ http://download.forge.objectweb.org/asm/asm-guide.pdf
+
+
--
end
diff --git a/core/java/android/nfc/INfcSecureElement.aidl b/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/LayoutlibDelegate.java
index aa98dd2..9a48ea6 100755..100644
--- a/core/java/android/nfc/INfcSecureElement.aidl
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/annotations/LayoutlibDelegate.java
@@ -14,15 +14,14 @@
* limitations under the License.
*/
-package android.nfc;
+package com.android.tools.layoutlib.annotations;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
- * {@hide}
+ * Denotes a method that has been converted to a delegate by layoutlib_create.
*/
-interface INfcSecureElement {
- int openSecureElementConnection();
- int closeSecureElementConnection(int nativeHandle);
- byte[] exchangeAPDU(int nativeHandle, in byte[] data);
- int[] getSecureElementTechList(int nativeHandle);
- byte[] getSecureElementUid(int nativeHandle);
-} \ No newline at end of file
+@Retention(RetentionPolicy.RUNTIME)
+public @interface LayoutlibDelegate {
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
index 7b55ed3e..a9ede26 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/AsmGenerator.java
@@ -28,9 +28,9 @@ import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
-import java.util.Map.Entry;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
@@ -60,38 +60,56 @@ public class AsmGenerator {
* old-FQCN to rename and they get erased as they get renamed. At the end, classes still
* left here are not in the code base anymore and thus were not renamed. */
private HashSet<String> mClassesNotRenamed;
- /** A map { FQCN => map { list of return types to delete from the FQCN } }. */
+ /** A map { FQCN => set { list of return types to delete from the FQCN } }. */
private HashMap<String, Set<String>> mDeleteReturns;
+ /** A map { FQCN => set { method names } } of methods to rewrite as delegates.
+ * The special name {@link DelegateClassAdapter#ALL_NATIVES} can be used as in internal set. */
+ private final HashMap<String, Set<String>> mDelegateMethods;
/**
* Creates a new generator that can generate the output JAR with the stubbed classes.
- *
+ *
* @param log Output logger.
* @param osDestJar The path of the destination JAR to create.
- * @param injectClasses The list of class from layoutlib_create to inject in layoutlib.
- * @param stubMethods The list of methods to stub out. Each entry must be in the form
- * "package.package.OuterClass$InnerClass#MethodName".
- * @param renameClasses The list of classes to rename, must be an even list: the binary FQCN
- * of class to replace followed by the new FQCN.
- * @param deleteReturns List of classes for which the methods returning them should be deleted.
- * The array contains a list of null terminated section starting with the name of the class
- * to rename in which the methods are deleted, followed by a list of return types identifying
- * the methods to delete.
+ * @param createInfo Creation parameters. Must not be null.
*/
- public AsmGenerator(Log log, String osDestJar,
- Class<?>[] injectClasses,
- String[] stubMethods,
- String[] renameClasses, String[] deleteReturns) {
+ public AsmGenerator(Log log, String osDestJar, ICreateInfo createInfo) {
mLog = log;
mOsDestJar = osDestJar;
- mInjectClasses = injectClasses != null ? injectClasses : new Class<?>[0];
- mStubMethods = stubMethods != null ? new HashSet<String>(Arrays.asList(stubMethods)) :
- new HashSet<String>();
+ mInjectClasses = createInfo.getInjectedClasses();
+ mStubMethods = new HashSet<String>(Arrays.asList(createInfo.getOverriddenMethods()));
+
+ // Create the map/set of methods to change to delegates
+ mDelegateMethods = new HashMap<String, Set<String>>();
+ for (String signature : createInfo.getDelegateMethods()) {
+ int pos = signature.indexOf('#');
+ if (pos <= 0 || pos >= signature.length() - 1) {
+ continue;
+ }
+ String className = binaryToInternalClassName(signature.substring(0, pos));
+ String methodName = signature.substring(pos + 1);
+ Set<String> methods = mDelegateMethods.get(className);
+ if (methods == null) {
+ methods = new HashSet<String>();
+ mDelegateMethods.put(className, methods);
+ }
+ methods.add(methodName);
+ }
+ for (String className : createInfo.getDelegateClassNatives()) {
+ className = binaryToInternalClassName(className);
+ Set<String> methods = mDelegateMethods.get(className);
+ if (methods == null) {
+ methods = new HashSet<String>();
+ mDelegateMethods.put(className, methods);
+ }
+ methods.add(DelegateClassAdapter.ALL_NATIVES);
+ }
// Create the map of classes to rename.
mRenameClasses = new HashMap<String, String>();
mClassesNotRenamed = new HashSet<String>();
- int n = renameClasses == null ? 0 : renameClasses.length;
+ String[] renameClasses = createInfo.getRenamedClasses();
+ int n = renameClasses.length;
for (int i = 0; i < n; i += 2) {
assert i + 1 < n;
// The ASM class names uses "/" separators, whereas regular FQCN use "."
@@ -100,38 +118,37 @@ public class AsmGenerator {
mRenameClasses.put(oldFqcn, newFqcn);
mClassesNotRenamed.add(oldFqcn);
}
-
+
// create the map of renamed class -> return type of method to delete.
mDeleteReturns = new HashMap<String, Set<String>>();
- if (deleteReturns != null) {
- Set<String> returnTypes = null;
- String renamedClass = null;
- for (String className : deleteReturns) {
- // if we reach the end of a section, add it to the main map
- if (className == null) {
- if (returnTypes != null) {
- mDeleteReturns.put(renamedClass, returnTypes);
- }
-
- renamedClass = null;
- continue;
- }
-
- // if the renamed class is null, this is the beginning of a section
- if (renamedClass == null) {
- renamedClass = binaryToInternalClassName(className);
- continue;
- }
-
- // just a standard return type, we add it to the list.
- if (returnTypes == null) {
- returnTypes = new HashSet<String>();
+ String[] deleteReturns = createInfo.getDeleteReturns();
+ Set<String> returnTypes = null;
+ String renamedClass = null;
+ for (String className : deleteReturns) {
+ // if we reach the end of a section, add it to the main map
+ if (className == null) {
+ if (returnTypes != null) {
+ mDeleteReturns.put(renamedClass, returnTypes);
}
- returnTypes.add(binaryToInternalClassName(className));
+
+ renamedClass = null;
+ continue;
}
+
+ // if the renamed class is null, this is the beginning of a section
+ if (renamedClass == null) {
+ renamedClass = binaryToInternalClassName(className);
+ continue;
+ }
+
+ // just a standard return type, we add it to the list.
+ if (returnTypes == null) {
+ returnTypes = new HashSet<String>();
+ }
+ returnTypes.add(binaryToInternalClassName(className));
}
}
-
+
/**
* Returns the list of classes that have not been renamed yet.
* <p/>
@@ -163,12 +180,12 @@ public class AsmGenerator {
public void setDeps(Map<String, ClassReader> deps) {
mDeps = deps;
}
-
+
/** Gets the map of classes to output as-is, except if they have native methods */
public Map<String, ClassReader> getKeep() {
return mKeep;
}
-
+
/** Gets the map of dependencies that must be completely stubbed */
public Map<String, ClassReader> getDeps() {
return mDeps;
@@ -177,7 +194,7 @@ public class AsmGenerator {
/** Generates the final JAR */
public void generate() throws FileNotFoundException, IOException {
TreeMap<String, byte[]> all = new TreeMap<String, byte[]>();
-
+
for (Class<?> clazz : mInjectClasses) {
String name = classToEntryPath(clazz);
InputStream is = ClassLoader.getSystemResourceAsStream(name);
@@ -186,7 +203,7 @@ public class AsmGenerator {
name = classNameToEntryPath(transformName(cr.getClassName()));
all.put(name, b);
}
-
+
for (Entry<String, ClassReader> entry : mDeps.entrySet()) {
ClassReader cr = entry.getValue();
byte[] b = transform(cr, true /* stubNativesOnly */);
@@ -211,8 +228,8 @@ public class AsmGenerator {
/**
* Writes the JAR file.
- *
- * @param outStream The file output stream were to write the JAR.
+ *
+ * @param outStream The file output stream were to write the JAR.
* @param all The map of all classes to output.
* @throws IOException if an I/O error has occurred
*/
@@ -236,7 +253,7 @@ public class AsmGenerator {
String classNameToEntryPath(String className) {
return className.replaceAll("\\.", "/").concat(".class");
}
-
+
/**
* Utility method to get the JAR entry path from a Class name.
* e.g. it returns someting like "com/foo/OuterClass$InnerClass1$InnerClass2.class"
@@ -248,30 +265,32 @@ public class AsmGenerator {
name = "$" + clazz.getSimpleName() + name;
clazz = parent;
}
- return classNameToEntryPath(clazz.getCanonicalName() + name);
+ return classNameToEntryPath(clazz.getCanonicalName() + name);
}
/**
* Transforms a class.
* <p/>
* There are 3 kind of transformations:
- *
+ *
* 1- For "mock" dependencies classes, we want to remove all code from methods and replace
* by a stub. Native methods must be implemented with this stub too. Abstract methods are
* left intact. Modified classes must be overridable (non-private, non-final).
* Native methods must be made non-final, non-private.
- *
+ *
* 2- For "keep" classes, we want to rewrite all native methods as indicated above.
* If a class has native methods, it must also be made non-private, non-final.
- *
+ *
* Note that unfortunately static methods cannot be changed to non-static (since static and
* non-static are invoked differently.)
*/
byte[] transform(ClassReader cr, boolean stubNativesOnly) {
boolean hasNativeMethods = hasNativeMethods(cr);
+
+ // Get the class name, as an internal name (e.g. com/android/SomeClass$InnerClass)
String className = cr.getClassName();
-
+
String newName = transformName(className);
// transformName returns its input argument if there's no need to rename the class
if (newName != className) {
@@ -288,16 +307,28 @@ public class AsmGenerator {
// Rewrite the new class from scratch, without reusing the constant pool from the
// original class reader.
ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
-
+
ClassVisitor rv = cw;
if (newName != className) {
rv = new RenameClassAdapter(cw, className, newName);
}
-
- TransformClassAdapter cv = new TransformClassAdapter(mLog, mStubMethods,
+
+ ClassVisitor cv = new TransformClassAdapter(mLog, mStubMethods,
mDeleteReturns.get(className),
newName, rv,
stubNativesOnly, stubNativesOnly || hasNativeMethods);
+
+ Set<String> delegateMethods = mDelegateMethods.get(className);
+ if (delegateMethods != null && !delegateMethods.isEmpty()) {
+ // If delegateMethods only contains one entry ALL_NATIVES and the class is
+ // known to have no native methods, just skip this step.
+ if (hasNativeMethods ||
+ !(delegateMethods.size() == 1 &&
+ delegateMethods.contains(DelegateClassAdapter.ALL_NATIVES))) {
+ cv = new DelegateClassAdapter(mLog, cv, className, delegateMethods);
+ }
+ }
+
cr.accept(cv, 0 /* flags */);
return cw.toByteArray();
}
@@ -323,7 +354,7 @@ public class AsmGenerator {
return newName + className.substring(pos);
}
}
-
+
return className;
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
index 2ed8641..4b62e43 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
@@ -16,51 +16,157 @@
package com.android.tools.layoutlib.create;
-public class CreateInfo {
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Describes the work to be done by {@link AsmGenerator}.
+ */
+public final class CreateInfo implements ICreateInfo {
+
+ /**
+ * Returns the list of class from layoutlib_create to inject in layoutlib.
+ * The list can be empty but must not be null.
+ */
+ public Class<?>[] getInjectedClasses() {
+ return INJECTED_CLASSES;
+ }
+
+ /**
+ * Returns the list of methods to rewrite as delegates.
+ * The list can be empty but must not be null.
+ */
+ public String[] getDelegateMethods() {
+ return DELEGATE_METHODS;
+ }
+
+ /**
+ * Returns the list of classes on which to delegate all native methods.
+ * The list can be empty but must not be null.
+ */
+ public String[] getDelegateClassNatives() {
+ return DELEGATE_CLASS_NATIVES;
+ }
+
+ /**
+ * Returns The list of methods to stub out. Each entry must be in the form
+ * "package.package.OuterClass$InnerClass#MethodName".
+ * The list can be empty but must not be null.
+ */
+ public String[] getOverriddenMethods() {
+ return OVERRIDDEN_METHODS;
+ }
+
+ /**
+ * Returns the list of classes to rename, must be an even list: the binary FQCN
+ * of class to replace followed by the new FQCN.
+ * The list can be empty but must not be null.
+ */
+ public String[] getRenamedClasses() {
+ return RENAMED_CLASSES;
+ }
+
+ /**
+ * Returns the list of classes for which the methods returning them should be deleted.
+ * The array contains a list of null terminated section starting with the name of the class
+ * to rename in which the methods are deleted, followed by a list of return types identifying
+ * the methods to delete.
+ * The list can be empty but must not be null.
+ */
+ public String[] getDeleteReturns() {
+ return DELETE_RETURNS;
+ }
+
+ //-----
+
/**
* The list of class from layoutlib_create to inject in layoutlib.
*/
- public final static Class<?>[] INJECTED_CLASSES = new Class<?>[] {
+ private final static Class<?>[] INJECTED_CLASSES = new Class<?>[] {
OverrideMethod.class,
MethodListener.class,
MethodAdapter.class,
- CreateInfo.class
+ ICreateInfo.class,
+ CreateInfo.class,
+ LayoutlibDelegate.class
};
/**
+ * The list of methods to rewrite as delegates.
+ */
+ private final static String[] DELEGATE_METHODS = new String[] {
+ "android.content.res.Resources$Theme#obtainStyledAttributes",
+ "android.content.res.Resources$Theme#resolveAttribute",
+ "android.graphics.BitmapFactory#finishDecode",
+ "android.os.Handler#sendMessageAtTime",
+ "android.os.Build#getString",
+ "android.view.LayoutInflater#parseInclude",
+ "android.view.View#isInEditMode",
+ "com.android.internal.util.XmlUtils#convertValueToInt",
+ // TODO: comment out once DelegateClass is working
+ };
+
+ /**
+ * The list of classes on which to delegate all native methods.
+ */
+ private final static String[] DELEGATE_CLASS_NATIVES = new String[] {
+ "android.graphics.AvoidXfermode",
+ "android.graphics.Bitmap",
+ "android.graphics.BitmapFactory",
+ "android.graphics.BitmapShader",
+ "android.graphics.BlurMaskFilter",
+ "android.graphics.Canvas",
+ "android.graphics.ColorFilter",
+ "android.graphics.ColorMatrixColorFilter",
+ "android.graphics.ComposePathEffect",
+ "android.graphics.ComposeShader",
+ "android.graphics.CornerPathEffect",
+ "android.graphics.DashPathEffect",
+ "android.graphics.DiscretePathEffect",
+ "android.graphics.DrawFilter",
+ "android.graphics.EmbossMaskFilter",
+ "android.graphics.LayerRasterizer",
+ "android.graphics.LightingColorFilter",
+ "android.graphics.LinearGradient",
+ "android.graphics.MaskFilter",
+ "android.graphics.Matrix",
+ "android.graphics.NinePatch",
+ "android.graphics.Paint",
+ "android.graphics.PaintFlagsDrawFilter",
+ "android.graphics.Path",
+ "android.graphics.PathDashPathEffect",
+ "android.graphics.PathEffect",
+ "android.graphics.PixelXorXfermode",
+ "android.graphics.PorterDuffColorFilter",
+ "android.graphics.PorterDuffXfermode",
+ "android.graphics.RadialGradient",
+ "android.graphics.Rasterizer",
+ "android.graphics.Region",
+ "android.graphics.Shader",
+ "android.graphics.SumPathEffect",
+ "android.graphics.SweepGradient",
+ "android.graphics.Typeface",
+ "android.graphics.Xfermode",
+ "android.os.SystemClock",
+ "android.util.FloatMath",
+ };
+
+ /**
* The list of methods to stub out. Each entry must be in the form
* "package.package.OuterClass$InnerClass#MethodName".
*/
- public final static String[] OVERRIDDEN_METHODS = new String[] {
- "android.view.View#isInEditMode",
- "android.content.res.Resources$Theme#obtainStyledAttributes",
- };
+ private final static String[] OVERRIDDEN_METHODS = new String[] {
+ };
/**
* The list of classes to rename, must be an even list: the binary FQCN
* of class to replace followed by the new FQCN.
*/
- public final static String[] RENAMED_CLASSES =
+ private final static String[] RENAMED_CLASSES =
new String[] {
- "android.graphics.Bitmap", "android.graphics._Original_Bitmap",
- "android.graphics.BitmapFactory", "android.graphics._Original_BitmapFactory",
- "android.graphics.BitmapShader", "android.graphics._Original_BitmapShader",
- "android.graphics.Canvas", "android.graphics._Original_Canvas",
- "android.graphics.ComposeShader", "android.graphics._Original_ComposeShader",
- "android.graphics.DashPathEffect", "android.graphics._Original_DashPathEffect",
- "android.graphics.LinearGradient", "android.graphics._Original_LinearGradient",
- "android.graphics.Matrix", "android.graphics._Original_Matrix",
- "android.graphics.Paint", "android.graphics._Original_Paint",
- "android.graphics.Path", "android.graphics._Original_Path",
- "android.graphics.PorterDuffXfermode", "android.graphics._Original_PorterDuffXfermode",
- "android.graphics.RadialGradient", "android.graphics._Original_RadialGradient",
- "android.graphics.Shader", "android.graphics._Original_Shader",
- "android.graphics.SweepGradient", "android.graphics._Original_SweepGradient",
- "android.graphics.Typeface", "android.graphics._Original_Typeface",
"android.os.ServiceManager", "android.os._Original_ServiceManager",
- "android.util.FloatMath", "android.util._Original_FloatMath",
"android.view.SurfaceView", "android.view._Original_SurfaceView",
"android.view.accessibility.AccessibilityManager", "android.view.accessibility._Original_AccessibilityManager",
+ "android.webkit.WebView", "android.webkit._Original_WebView",
};
/**
@@ -69,15 +175,8 @@ public class CreateInfo {
* to rename in which the methods are deleted, followed by a list of return types identifying
* the methods to delete.
*/
- public final static String[] REMOVED_METHODS =
+ private final static String[] DELETE_RETURNS =
new String[] {
- "android.graphics.Paint", // class to delete methods from
- "android.graphics.Paint$Align", // list of type identifying methods to delete
- "android.graphics.Paint$Style",
- "android.graphics.Paint$Join",
- "android.graphics.Paint$Cap",
- "android.graphics.Paint$FontMetrics",
- "android.graphics.Paint$FontMetricsInt",
null }; // separator, for next class/methods list.
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
new file mode 100644
index 0000000..9cba8a0
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import org.objectweb.asm.ClassAdapter;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+import java.util.Set;
+
+/**
+ * A {@link DelegateClassAdapter} can transform some methods from a class into
+ * delegates that defer the call to an associated delegate class.
+ * <p/>
+ * This is used to override specific methods and or all native methods in classes.
+ */
+public class DelegateClassAdapter extends ClassAdapter {
+
+ public final static String ALL_NATIVES = "<<all_natives>>";
+
+ private final String mClassName;
+ private final Set<String> mDelegateMethods;
+ private final Log mLog;
+
+ /**
+ * Creates a new {@link DelegateClassAdapter} that can transform some methods
+ * from a class into delegates that defer the call to an associated delegate class.
+ * <p/>
+ * This is used to override specific methods and or all native methods in classes.
+ *
+ * @param log The logger object. Must not be null.
+ * @param cv the class visitor to which this adapter must delegate calls.
+ * @param className The internal class name of the class to visit,
+ * e.g. <code>com/android/SomeClass$InnerClass</code>.
+ * @param delegateMethods The set of method names to modify and/or the
+ * special constant {@link #ALL_NATIVES} to convert all native methods.
+ */
+ public DelegateClassAdapter(Log log,
+ ClassVisitor cv,
+ String className,
+ Set<String> delegateMethods) {
+ super(cv);
+ mLog = log;
+ mClassName = className;
+ mDelegateMethods = delegateMethods;
+ }
+
+ //----------------------------------
+ // Methods from the ClassAdapter
+
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String desc,
+ String signature, String[] exceptions) {
+
+ boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
+ boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
+
+ boolean useDelegate = (isNative && mDelegateMethods.contains(ALL_NATIVES)) ||
+ mDelegateMethods.contains(name);
+
+ if (useDelegate) {
+ // remove native
+ access = access & ~Opcodes.ACC_NATIVE;
+ }
+
+ MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
+ if (useDelegate) {
+ DelegateMethodAdapter a = new DelegateMethodAdapter(mLog, mw, mClassName,
+ name, desc, isStatic);
+ if (isNative) {
+ // A native has no code to visit, so we need to generate it directly.
+ a.generateCode();
+ } else {
+ return a;
+ }
+ }
+ return mw;
+ }
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
new file mode 100644
index 0000000..8d7f016
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
@@ -0,0 +1,358 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.util.ArrayList;
+
+/**
+ * This method adapter rewrites a method by discarding the original code and generating
+ * a call to a delegate. Original annotations are passed along unchanged.
+ * <p/>
+ * Calls are delegated to a class named <code>&lt;className&gt;_Delegate</code> with
+ * static methods matching the methods to be overridden here. The methods have the
+ * same return type. The argument type list is the same except the "this" reference is
+ * passed first for non-static methods.
+ * <p/>
+ * A new annotation is added.
+ * <p/>
+ * Note that native methods have, by definition, no code so there's nothing a visitor
+ * can visit. That means the caller must call {@link #generateCode()} directly for
+ * a native and use the visitor pattern for non-natives.
+ * <p/>
+ * Instances of this class are not re-usable. You need a new instance for each method.
+ */
+class DelegateMethodAdapter implements MethodVisitor {
+
+ /**
+ * Suffix added to delegate classes.
+ */
+ public static final String DELEGATE_SUFFIX = "_Delegate";
+
+ private static String CONSTRUCTOR = "<init>";
+ private static String CLASS_INIT = "<clinit>";
+
+ /** The parent method writer */
+ private MethodVisitor mParentVisitor;
+ /** Flag to output the first line number. */
+ private boolean mOutputFirstLineNumber = true;
+ /** The original method descriptor (return type + argument types.) */
+ private String mDesc;
+ /** True if the original method is static. */
+ private final boolean mIsStatic;
+ /** The internal class name (e.g. <code>com/android/SomeClass$InnerClass</code>.) */
+ private final String mClassName;
+ /** The method name. */
+ private final String mMethodName;
+ /** Logger object. */
+ private final Log mLog;
+ /** True if {@link #visitCode()} has been invoked. */
+ private boolean mVisitCodeCalled;
+
+ /**
+ * Creates a new {@link DelegateMethodAdapter} that will transform this method
+ * into a delegate call.
+ * <p/>
+ * See {@link DelegateMethodAdapter} for more details.
+ *
+ * @param log The logger object. Must not be null.
+ * @param mv the method visitor to which this adapter must delegate calls.
+ * @param className The internal class name of the class to visit,
+ * e.g. <code>com/android/SomeClass$InnerClass</code>.
+ * @param methodName The simple name of the method.
+ * @param desc A method descriptor (c.f. {@link Type#getReturnType(String)} +
+ * {@link Type#getArgumentTypes(String)})
+ * @param isStatic True if the method is declared static.
+ */
+ public DelegateMethodAdapter(Log log,
+ MethodVisitor mv,
+ String className,
+ String methodName,
+ String desc,
+ boolean isStatic) {
+ mLog = log;
+ mParentVisitor = mv;
+ mClassName = className;
+ mMethodName = methodName;
+ mDesc = desc;
+ mIsStatic = isStatic;
+
+ if (CONSTRUCTOR.equals(methodName) || CLASS_INIT.equals(methodName)) {
+ // We're going to simplify by not supporting constructors.
+ // The only trick with a constructor is to find the proper super constructor
+ // and call it (and deciding if we should mirror the original method call to
+ // a custom constructor or call a default one.)
+ throw new UnsupportedOperationException(
+ String.format("Delegate doesn't support overriding constructor %1$s:%2$s(%3$s)",
+ className, methodName, desc));
+ }
+ }
+
+ /**
+ * Generates the new code for the method.
+ * <p/>
+ * For native methods, this must be invoked directly by {@link DelegateClassAdapter}
+ * (since they have no code to visit).
+ * <p/>
+ * Otherwise for non-native methods the {@link DelegateClassAdapter} simply needs to
+ * return this instance of {@link DelegateMethodAdapter} and let the normal visitor pattern
+ * invoke it as part of the {@link ClassReader#accept(ClassVisitor, int)} workflow and then
+ * this method will be invoked from {@link MethodVisitor#visitEnd()}.
+ */
+ public void generateCode() {
+ /*
+ * The goal is to generate a call to a static delegate method.
+ * If this method is non-static, the first parameter will be 'this'.
+ * All the parameters must be passed and then the eventual return type returned.
+ *
+ * Example, let's say we have a method such as
+ * public void method_1(int a, Object b, ArrayList<String> c) { ... }
+ *
+ * We'll want to create a body that calls a delegate method like this:
+ * TheClass_Delegate.method_1(this, a, b, c);
+ *
+ * If the method is non-static and the class name is an inner class (e.g. has $ in its
+ * last segment), we want to push the 'this' of the outer class first:
+ * OuterClass_InnerClass_Delegate.method_1(
+ * OuterClass.this,
+ * OuterClass$InnerClass.this,
+ * a, b, c);
+ *
+ * Only one level of inner class is supported right now, for simplicity and because
+ * we don't need more.
+ *
+ * The generated class name is the current class name with "_Delegate" appended to it.
+ * One thing to realize is that we don't care about generics -- since generic types
+ * are erased at runtime, they have no influence on the method name being called.
+ */
+
+ // Add our annotation
+ AnnotationVisitor aw = mParentVisitor.visitAnnotation(
+ Type.getObjectType(Type.getInternalName(LayoutlibDelegate.class)).toString(),
+ true); // visible at runtime
+ aw.visitEnd();
+
+ if (!mVisitCodeCalled) {
+ // If this is a direct call to generateCode() as done by DelegateClassAdapter
+ // for natives, visitCode() hasn't been called yet.
+ mParentVisitor.visitCode();
+ mVisitCodeCalled = true;
+ }
+
+ ArrayList<Type> paramTypes = new ArrayList<Type>();
+ String delegateClassName = mClassName + DELEGATE_SUFFIX;
+ boolean pushedArg0 = false;
+ int maxStack = 0;
+
+ // For an instance method (e.g. non-static), push the 'this' preceded
+ // by the 'this' of any outer class, if any.
+ if (!mIsStatic) {
+ // Check if the last segment of the class name has inner an class.
+ // Right now we only support one level of inner classes.
+ int slash = mClassName.lastIndexOf('/');
+ int dol = mClassName.lastIndexOf('$');
+ if (dol != -1 && dol > slash && dol == mClassName.indexOf('$')) {
+ String outerClass = mClassName.substring(0, dol);
+ Type outerType = Type.getObjectType(outerClass);
+
+ // Change a delegate class name to "com/foo/Outer_Inner_Delegate"
+ delegateClassName = delegateClassName.replace('$', '_');
+
+ // The first-level inner class has a package-protected member called 'this$0'
+ // that points to the outer class.
+
+ // Push this.getField("this$0") on the call stack.
+ mParentVisitor.visitVarInsn(Opcodes.ALOAD, 0); // var 0 = this
+ mParentVisitor.visitFieldInsn(Opcodes.GETFIELD,
+ mClassName, // class where the field is defined
+ "this$0", // field name
+ outerType.getDescriptor()); // type of the field
+ maxStack++;
+ paramTypes.add(outerType);
+ }
+
+ // Push "this" for the instance method, which is always ALOAD 0
+ mParentVisitor.visitVarInsn(Opcodes.ALOAD, 0);
+ maxStack++;
+ pushedArg0 = true;
+ paramTypes.add(Type.getObjectType(mClassName));
+ }
+
+ // Push all other arguments. Start at arg 1 if we already pushed 'this' above.
+ Type[] argTypes = Type.getArgumentTypes(mDesc);
+ int maxLocals = pushedArg0 ? 1 : 0;
+ for (Type t : argTypes) {
+ int size = t.getSize();
+ mParentVisitor.visitVarInsn(t.getOpcode(Opcodes.ILOAD), maxLocals);
+ maxLocals += size;
+ maxStack += size;
+ paramTypes.add(t);
+ }
+
+ // Construct the descriptor of the delegate based on the parameters
+ // we pushed on the call stack. The return type remains unchanged.
+ String desc = Type.getMethodDescriptor(
+ Type.getReturnType(mDesc),
+ paramTypes.toArray(new Type[paramTypes.size()]));
+
+ // Invoke the static delegate
+ mParentVisitor.visitMethodInsn(Opcodes.INVOKESTATIC,
+ delegateClassName,
+ mMethodName,
+ desc);
+
+ Type returnType = Type.getReturnType(mDesc);
+ mParentVisitor.visitInsn(returnType.getOpcode(Opcodes.IRETURN));
+
+ mParentVisitor.visitMaxs(maxStack, maxLocals);
+ mParentVisitor.visitEnd();
+
+ // For debugging now. Maybe we should collect these and store them in
+ // a text file for helping create the delegates. We could also compare
+ // the text file to a golden and break the build on unsupported changes
+ // or regressions. Even better we could fancy-print something that looks
+ // like the expected Java method declaration.
+ mLog.debug("Delegate: %1$s # %2$s %3$s", delegateClassName, mMethodName, desc);
+ }
+
+ /* Pass down to visitor writer. In this implementation, either do nothing. */
+ public void visitCode() {
+ mVisitCodeCalled = true;
+ mParentVisitor.visitCode();
+ }
+
+ /*
+ * visitMaxs is called just before visitEnd if there was any code to rewrite.
+ * Skip the original.
+ */
+ public void visitMaxs(int maxStack, int maxLocals) {
+ }
+
+ /**
+ * End of visiting. Generate the messaging code.
+ */
+ public void visitEnd() {
+ generateCode();
+ }
+
+ /* Writes all annotation from the original method. */
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return mParentVisitor.visitAnnotation(desc, visible);
+ }
+
+ /* Writes all annotation default values from the original method. */
+ public AnnotationVisitor visitAnnotationDefault() {
+ return mParentVisitor.visitAnnotationDefault();
+ }
+
+ public AnnotationVisitor visitParameterAnnotation(int parameter, String desc,
+ boolean visible) {
+ return mParentVisitor.visitParameterAnnotation(parameter, desc, visible);
+ }
+
+ /* Writes all attributes from the original method. */
+ public void visitAttribute(Attribute attr) {
+ mParentVisitor.visitAttribute(attr);
+ }
+
+ /*
+ * Only writes the first line number present in the original code so that source
+ * viewers can direct to the correct method, even if the content doesn't match.
+ */
+ public void visitLineNumber(int line, Label start) {
+ if (mOutputFirstLineNumber) {
+ mParentVisitor.visitLineNumber(line, start);
+ mOutputFirstLineNumber = false;
+ }
+ }
+
+ public void visitInsn(int opcode) {
+ // Skip original code.
+ }
+
+ public void visitLabel(Label label) {
+ // Skip original code.
+ }
+
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
+ // Skip original code.
+ }
+
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+ // Skip original code.
+ }
+
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ // Skip original code.
+ }
+
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+ // Skip original code.
+ }
+
+ public void visitIincInsn(int var, int increment) {
+ // Skip original code.
+ }
+
+ public void visitIntInsn(int opcode, int operand) {
+ // Skip original code.
+ }
+
+ public void visitJumpInsn(int opcode, Label label) {
+ // Skip original code.
+ }
+
+ public void visitLdcInsn(Object cst) {
+ // Skip original code.
+ }
+
+ public void visitLocalVariable(String name, String desc, String signature,
+ Label start, Label end, int index) {
+ // Skip original code.
+ }
+
+ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
+ // Skip original code.
+ }
+
+ public void visitMultiANewArrayInsn(String desc, int dims) {
+ // Skip original code.
+ }
+
+ public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
+ // Skip original code.
+ }
+
+ public void visitTypeInsn(int opcode, String type) {
+ // Skip original code.
+ }
+
+ public void visitVarInsn(int opcode, int var) {
+ // Skip original code.
+ }
+
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
new file mode 100644
index 0000000..40c1706
--- /dev/null
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/ICreateInfo.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+/**
+ * Interface describing the work to be done by {@link AsmGenerator}.
+ */
+public interface ICreateInfo {
+
+ /**
+ * Returns the list of class from layoutlib_create to inject in layoutlib.
+ * The list can be empty but must not be null.
+ */
+ public abstract Class<?>[] getInjectedClasses();
+
+ /**
+ * Returns the list of methods to rewrite as delegates.
+ * The list can be empty but must not be null.
+ */
+ public abstract String[] getDelegateMethods();
+
+ /**
+ * Returns the list of classes on which to delegate all native methods.
+ * The list can be empty but must not be null.
+ */
+ public abstract String[] getDelegateClassNatives();
+
+ /**
+ * Returns The list of methods to stub out. Each entry must be in the form
+ * "package.package.OuterClass$InnerClass#MethodName".
+ * The list can be empty but must not be null.
+ */
+ public abstract String[] getOverriddenMethods();
+
+ /**
+ * Returns the list of classes to rename, must be an even list: the binary FQCN
+ * of class to replace followed by the new FQCN.
+ * The list can be empty but must not be null.
+ */
+ public abstract String[] getRenamedClasses();
+
+ /**
+ * Returns the list of classes for which the methods returning them should be deleted.
+ * The array contains a list of null terminated section starting with the name of the class
+ * to rename in which the methods are deleted, followed by a list of return types identifying
+ * the methods to delete.
+ * The list can be empty but must not be null.
+ */
+ public abstract String[] getDeleteReturns();
+
+}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
index b30e9e5..0fce7ef 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/Main.java
@@ -21,7 +21,28 @@ import java.util.ArrayList;
import java.util.Set;
-
+/**
+ * Entry point for the layoutlib_create tool.
+ * <p/>
+ * The tool does not currently rely on any external configuration file.
+ * Instead the configuration is mostly done via the {@link CreateInfo} class.
+ * <p/>
+ * For a complete description of the tool and its implementation, please refer to
+ * the "README.txt" file at the root of this project.
+ * <p/>
+ * For a quick test, invoke this as follows:
+ * <pre>
+ * $ make layoutlib
+ * </pre>
+ * which does:
+ * <pre>
+ * $ make layoutlib_create &lt;bunch of framework jars&gt;
+ * $ out/host/linux-x86/framework/bin/layoutlib_create \
+ * out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar \
+ * out/target/common/obj/JAVA_LIBRARIES/core_intermediates/classes.jar \
+ * out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar
+ * </pre>
+ */
public class Main {
public static void main(String[] args) {
@@ -42,15 +63,12 @@ public class Main {
}
try {
- AsmGenerator agen = new AsmGenerator(log, osDestJar[0],
- CreateInfo.INJECTED_CLASSES,
- CreateInfo.OVERRIDDEN_METHODS,
- CreateInfo.RENAMED_CLASSES,
- CreateInfo.REMOVED_METHODS
- );
+ AsmGenerator agen = new AsmGenerator(log, osDestJar[0], new CreateInfo());
AsmAnalyzer aa = new AsmAnalyzer(log, osJarPath, agen,
- new String[] { "android.view.View" }, // derived from
+ new String[] { // derived from
+ "android.view.View",
+ },
new String[] { // include classes
"android.*", // for android.R
"android.util.*",
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java
index e294d56..f2d9755 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/TransformClassAdapter.java
@@ -26,7 +26,7 @@ import org.objectweb.asm.Type;
import java.util.Set;
/**
- * Class adapter that can stub some or all of the methods of the class.
+ * Class adapter that can stub some or all of the methods of the class.
*/
class TransformClassAdapter extends ClassAdapter {
@@ -41,12 +41,12 @@ class TransformClassAdapter extends ClassAdapter {
/**
* Creates a new class adapter that will stub some or all methods.
- * @param logger
- * @param stubMethods
+ * @param logger
+ * @param stubMethods list of method signatures to always stub out
* @param deleteReturns list of types that trigger the deletion of methods returning them.
* @param className The name of the class being modified
* @param cv The parent class writer visitor
- * @param stubNativesOnly True if only native methods should be stubbed. False if all
+ * @param stubNativesOnly True if only native methods should be stubbed. False if all
* methods should be stubbed.
* @param hasNative True if the method has natives, in which case its access should be
* changed.
@@ -67,10 +67,10 @@ class TransformClassAdapter extends ClassAdapter {
@Override
public void visit(int version, int access, String name,
String signature, String superName, String[] interfaces) {
-
+
// This class might be being renamed.
name = mClassName;
-
+
// remove protected or private and set as public
access = access & ~(Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED);
access |= Opcodes.ACC_PUBLIC;
@@ -82,7 +82,7 @@ class TransformClassAdapter extends ClassAdapter {
mIsInterface = ((access & Opcodes.ACC_INTERFACE) != 0);
super.visit(version, access, name, signature, superName, interfaces);
}
-
+
/* Visits the header of an inner class. */
@Override
public void visitInnerClass(String name, String outerName, String innerName, int access) {
@@ -101,7 +101,7 @@ class TransformClassAdapter extends ClassAdapter {
@Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
-
+
if (mDeleteReturns != null) {
Type t = Type.getReturnType(desc);
if (t.getSort() == Type.OBJECT) {
@@ -130,16 +130,16 @@ class TransformClassAdapter extends ClassAdapter {
(mStubAll ||
(access & Opcodes.ACC_NATIVE) != 0) ||
mStubMethods.contains(methodSignature)) {
-
+
boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
// remove abstract, final and native
access = access & ~(Opcodes.ACC_ABSTRACT | Opcodes.ACC_FINAL | Opcodes.ACC_NATIVE);
-
+
String invokeSignature = methodSignature + desc;
mLog.debug(" Stub: %s (%s)", invokeSignature, isNative ? "native" : "");
-
+
MethodVisitor mw = super.visitMethod(access, name, desc, signature, exceptions);
return new StubMethodAdapter(mw, name, returnType(desc), invokeSignature,
isStatic, isNative);
@@ -149,7 +149,7 @@ class TransformClassAdapter extends ClassAdapter {
return super.visitMethod(access, name, desc, signature, exceptions);
}
}
-
+
/* Visits a field. Makes it public. */
@Override
public FieldVisitor visitField(int access, String name, String desc, String signature,
@@ -157,7 +157,7 @@ class TransformClassAdapter extends ClassAdapter {
// change access to public
access &= ~(Opcodes.ACC_PROTECTED | Opcodes.ACC_PRIVATE);
access |= Opcodes.ACC_PUBLIC;
-
+
return super.visitField(access, name, desc, signature, value);
}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
index 603284e..d6dba6a 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmAnalyzerTest.java
@@ -22,7 +22,6 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import com.android.tools.layoutlib.create.AsmAnalyzer.DependencyVisitor;
-import com.android.tools.layoutlib.create.LogTest.MockLog;
import org.junit.After;
import org.junit.Before;
@@ -46,9 +45,9 @@ public class AsmAnalyzerTest {
@Before
public void setUp() throws Exception {
- mLog = new LogTest.MockLog();
+ mLog = new MockLog();
URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar");
-
+
mOsJarPath = new ArrayList<String>();
mOsJarPath.add(url.getFile());
@@ -69,9 +68,9 @@ public class AsmAnalyzerTest {
"mock_android.dummy.InnerTest$DerivingClass",
"mock_android.dummy.InnerTest$MyGenerics1",
"mock_android.dummy.InnerTest$MyIntEnum",
- "mock_android.dummy.InnerTest$MyStaticInnerClass",
- "mock_android.dummy.InnerTest$NotStaticInner1",
- "mock_android.dummy.InnerTest$NotStaticInner2",
+ "mock_android.dummy.InnerTest$MyStaticInnerClass",
+ "mock_android.dummy.InnerTest$NotStaticInner1",
+ "mock_android.dummy.InnerTest$NotStaticInner2",
"mock_android.view.View",
"mock_android.view.ViewGroup",
"mock_android.view.ViewGroup$LayoutParams",
@@ -83,7 +82,7 @@ public class AsmAnalyzerTest {
},
map.keySet().toArray());
}
-
+
@Test
public void testFindClass() throws IOException, LogAbortException {
Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
@@ -91,7 +90,7 @@ public class AsmAnalyzerTest {
ClassReader cr = mAa.findClass("mock_android.view.ViewGroup$LayoutParams",
zipClasses, found);
-
+
assertNotNull(cr);
assertEquals("mock_android/view/ViewGroup$LayoutParams", cr.getClassName());
assertArrayEquals(new String[] { "mock_android.view.ViewGroup$LayoutParams" },
@@ -172,14 +171,14 @@ public class AsmAnalyzerTest {
"mock_android.widget.TableLayout",
},
found.keySet().toArray());
-
+
for (String key : found.keySet()) {
ClassReader value = found.get(key);
assertNotNull("No value for " + key, value);
assertEquals(key, AsmAnalyzer.classReaderToClassName(value));
}
}
-
+
@Test
public void testDependencyVisitor() throws IOException, LogAbortException {
Map<String, ClassReader> zipClasses = mAa.parseZip(mOsJarPath);
@@ -190,7 +189,7 @@ public class AsmAnalyzerTest {
ClassReader cr = mAa.findClass("mock_android.widget.TableLayout", zipClasses, keep);
DependencyVisitor visitor = mAa.getVisitor(zipClasses, keep, new_keep, in_deps, out_deps);
-
+
// get first level dependencies
cr.accept(visitor, 0 /* flags */);
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
index 7cdf79a..f4ff389 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/AsmGeneratorTest.java
@@ -20,8 +20,6 @@ package com.android.tools.layoutlib.create;
import static org.junit.Assert.assertArrayEquals;
-import com.android.tools.layoutlib.create.LogTest.MockLog;
-
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
@@ -44,9 +42,9 @@ public class AsmGeneratorTest {
@Before
public void setUp() throws Exception {
- mLog = new LogTest.MockLog();
+ mLog = new MockLog();
URL url = this.getClass().getClassLoader().getResource("data/mock_android.jar");
-
+
mOsJarPath = new ArrayList<String>();
mOsJarPath.add(url.getFile());
@@ -65,16 +63,41 @@ public class AsmGeneratorTest {
@Test
public void testClassRenaming() throws IOException, LogAbortException {
-
- AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar,
- null, // classes to inject in the final JAR
- null, // methods to force override
- new String[] { // classes to rename (so that we can replace them)
- "mock_android.view.View", "mock_android.view._Original_View",
- "not.an.actual.ClassName", "anoter.fake.NewClassName",
- },
- null // methods deleted from their return type.
- );
+
+ ICreateInfo ci = new ICreateInfo() {
+ public Class<?>[] getInjectedClasses() {
+ // classes to inject in the final JAR
+ return new Class<?>[0];
+ }
+
+ public String[] getDelegateMethods() {
+ return new String[0];
+ }
+
+ public String[] getDelegateClassNatives() {
+ return new String[0];
+ }
+
+ public String[] getOverriddenMethods() {
+ // methods to force override
+ return new String[0];
+ }
+
+ public String[] getRenamedClasses() {
+ // classes to rename (so that we can replace them)
+ return new String[] {
+ "mock_android.view.View", "mock_android.view._Original_View",
+ "not.an.actual.ClassName", "anoter.fake.NewClassName",
+ };
+ }
+
+ public String[] getDeleteReturns() {
+ // methods deleted from their return type.
+ return new String[0];
+ }
+ };
+
+ AsmGenerator agen = new AsmGenerator(mLog, mOsDestJar, ci);
AsmAnalyzer aa = new AsmAnalyzer(mLog, mOsJarPath, agen,
null, // derived from
@@ -83,7 +106,7 @@ public class AsmGeneratorTest {
});
aa.analyze();
agen.generate();
-
+
Set<String> notRenamed = agen.getClassesNotRenamed();
assertArrayEquals(new String[] { "not/an/actual/ClassName" }, notRenamed.toArray());
}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java
index d6916ae..0135c40 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/ClassHasNativeVisitorTest.java
@@ -33,8 +33,9 @@ public class ClassHasNativeVisitorTest {
@Test
public void testHasNative() throws IOException {
MockClassHasNativeVisitor cv = new MockClassHasNativeVisitor();
- ClassReader cr = new ClassReader(
- "com.android.tools.layoutlib.create.ClassHasNativeVisitorTest$ClassWithNative");
+ String className =
+ this.getClass().getCanonicalName() + "$" + ClassWithNative.class.getSimpleName();
+ ClassReader cr = new ClassReader(className);
cr.accept(cv, 0 /* flags */);
assertArrayEquals(new String[] { "native_method" }, cv.getMethodsFound());
@@ -44,14 +45,17 @@ public class ClassHasNativeVisitorTest {
@Test
public void testHasNoNative() throws IOException {
MockClassHasNativeVisitor cv = new MockClassHasNativeVisitor();
- ClassReader cr = new ClassReader(
- "com.android.tools.layoutlib.create.ClassHasNativeVisitorTest$ClassWithoutNative");
+ String className =
+ this.getClass().getCanonicalName() + "$" + ClassWithoutNative.class.getSimpleName();
+ ClassReader cr = new ClassReader(className);
cr.accept(cv, 0 /* flags */);
assertArrayEquals(new String[0], cv.getMethodsFound());
assertFalse(cv.hasNativeMethods());
}
+ //-------
+
/**
* Overrides {@link ClassHasNativeVisitor} to collec the name of the native methods found.
*/
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
new file mode 100644
index 0000000..e8b3ea8
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
@@ -0,0 +1,409 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+
+import com.android.tools.layoutlib.create.dataclass.ClassWithNative;
+import com.android.tools.layoutlib.create.dataclass.OuterClass;
+import com.android.tools.layoutlib.create.dataclass.OuterClass.InnerClass;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.Set;
+
+public class DelegateClassAdapterTest {
+
+ private MockLog mLog;
+
+ private static final String NATIVE_CLASS_NAME = ClassWithNative.class.getCanonicalName();
+ private static final String OUTER_CLASS_NAME = OuterClass.class.getCanonicalName();
+ private static final String INNER_CLASS_NAME = OuterClass.class.getCanonicalName() + "$" +
+ InnerClass.class.getSimpleName();
+
+ @Before
+ public void setUp() throws Exception {
+ mLog = new MockLog();
+ mLog.setVerbose(true); // capture debug error too
+ }
+
+ /**
+ * Tests that a class not being modified still works.
+ */
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testNoOp() throws Throwable {
+ // create an instance of the class that will be modified
+ // (load the class in a distinct class loader so that we can trash its definition later)
+ ClassLoader cl1 = new ClassLoader(this.getClass().getClassLoader()) { };
+ Class<ClassWithNative> clazz1 = (Class<ClassWithNative>) cl1.loadClass(NATIVE_CLASS_NAME);
+ ClassWithNative instance1 = clazz1.newInstance();
+ assertEquals(42, instance1.add(20, 22));
+ try {
+ instance1.callNativeInstance(10, 3.1415, new Object[0] );
+ fail("Test should have failed to invoke callTheNativeMethod [1]");
+ } catch (UnsatisfiedLinkError e) {
+ // This is expected to fail since the native method is not implemented.
+ }
+
+ // Now process it but tell the delegate to not modify any method
+ ClassWriter cw = new ClassWriter(0 /*flags*/);
+
+ HashSet<String> delegateMethods = new HashSet<String>();
+ String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
+ DelegateClassAdapter cv = new DelegateClassAdapter(
+ mLog, cw, internalClassName, delegateMethods);
+
+ ClassReader cr = new ClassReader(NATIVE_CLASS_NAME);
+ cr.accept(cv, 0 /* flags */);
+
+ // Load the generated class in a different class loader and try it again
+
+ ClassLoader2 cl2 = null;
+ try {
+ cl2 = new ClassLoader2() {
+ @Override
+ public void testModifiedInstance() throws Exception {
+ Class<?> clazz2 = loadClass(NATIVE_CLASS_NAME);
+ Object i2 = clazz2.newInstance();
+ assertNotNull(i2);
+ assertEquals(42, callAdd(i2, 20, 22));
+
+ try {
+ callCallNativeInstance(i2, 10, 3.1415, new Object[0]);
+ fail("Test should have failed to invoke callTheNativeMethod [2]");
+ } catch (InvocationTargetException e) {
+ // This is expected to fail since the native method has NOT been
+ // overridden here.
+ assertEquals(UnsatisfiedLinkError.class, e.getCause().getClass());
+ }
+
+ // Check that the native method does NOT have the new annotation
+ Method[] m = clazz2.getDeclaredMethods();
+ assertEquals("native_instance", m[2].getName());
+ assertTrue(Modifier.isNative(m[2].getModifiers()));
+ Annotation[] a = m[2].getAnnotations();
+ assertEquals(0, a.length);
+ }
+ };
+ cl2.add(NATIVE_CLASS_NAME, cw);
+ cl2.testModifiedInstance();
+ } catch (Throwable t) {
+ throw dumpGeneratedClass(t, cl2);
+ }
+ }
+
+ /**
+ * {@link DelegateMethodAdapter} does not support overriding constructors yet,
+ * so this should fail with an {@link UnsupportedOperationException}.
+ *
+ * Although not tested here, the message of the exception should contain the
+ * constructor signature.
+ */
+ @Test(expected=UnsupportedOperationException.class)
+ public void testConstructorsNotSupported() throws IOException {
+ ClassWriter cw = new ClassWriter(0 /*flags*/);
+
+ String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
+
+ HashSet<String> delegateMethods = new HashSet<String>();
+ delegateMethods.add("<init>");
+ DelegateClassAdapter cv = new DelegateClassAdapter(
+ mLog, cw, internalClassName, delegateMethods);
+
+ ClassReader cr = new ClassReader(NATIVE_CLASS_NAME);
+ cr.accept(cv, 0 /* flags */);
+ }
+
+ @Test
+ public void testDelegateNative() throws Throwable {
+ ClassWriter cw = new ClassWriter(0 /*flags*/);
+ String internalClassName = NATIVE_CLASS_NAME.replace('.', '/');
+
+ HashSet<String> delegateMethods = new HashSet<String>();
+ delegateMethods.add(DelegateClassAdapter.ALL_NATIVES);
+ DelegateClassAdapter cv = new DelegateClassAdapter(
+ mLog, cw, internalClassName, delegateMethods);
+
+ ClassReader cr = new ClassReader(NATIVE_CLASS_NAME);
+ cr.accept(cv, 0 /* flags */);
+
+ // Load the generated class in a different class loader and try it
+ ClassLoader2 cl2 = null;
+ try {
+ cl2 = new ClassLoader2() {
+ @Override
+ public void testModifiedInstance() throws Exception {
+ Class<?> clazz2 = loadClass(NATIVE_CLASS_NAME);
+ Object i2 = clazz2.newInstance();
+ assertNotNull(i2);
+
+ // Use reflection to access inner methods
+ assertEquals(42, callAdd(i2, 20, 22));
+
+ Object[] objResult = new Object[] { null };
+ int result = callCallNativeInstance(i2, 10, 3.1415, objResult);
+ assertEquals((int)(10 + 3.1415), result);
+ assertSame(i2, objResult[0]);
+
+ // Check that the native method now has the new annotation and is not native
+ Method[] m = clazz2.getDeclaredMethods();
+ assertEquals("native_instance", m[2].getName());
+ assertFalse(Modifier.isNative(m[2].getModifiers()));
+ Annotation[] a = m[2].getAnnotations();
+ assertEquals("LayoutlibDelegate", a[0].annotationType().getSimpleName());
+ }
+ };
+ cl2.add(NATIVE_CLASS_NAME, cw);
+ cl2.testModifiedInstance();
+ } catch (Throwable t) {
+ throw dumpGeneratedClass(t, cl2);
+ }
+ }
+
+ @Test
+ public void testDelegateInner() throws Throwable {
+ // We'll delegate the "get" method of both the inner and outer class.
+ HashSet<String> delegateMethods = new HashSet<String>();
+ delegateMethods.add("get");
+
+ // Generate the delegate for the outer class.
+ ClassWriter cwOuter = new ClassWriter(0 /*flags*/);
+ String outerClassName = OUTER_CLASS_NAME.replace('.', '/');
+ DelegateClassAdapter cvOuter = new DelegateClassAdapter(
+ mLog, cwOuter, outerClassName, delegateMethods);
+ ClassReader cr = new ClassReader(OUTER_CLASS_NAME);
+ cr.accept(cvOuter, 0 /* flags */);
+
+ // Generate the delegate for the inner class.
+ ClassWriter cwInner = new ClassWriter(0 /*flags*/);
+ String innerClassName = INNER_CLASS_NAME.replace('.', '/');
+ DelegateClassAdapter cvInner = new DelegateClassAdapter(
+ mLog, cwInner, innerClassName, delegateMethods);
+ cr = new ClassReader(INNER_CLASS_NAME);
+ cr.accept(cvInner, 0 /* flags */);
+
+ // Load the generated classes in a different class loader and try them
+ ClassLoader2 cl2 = null;
+ try {
+ cl2 = new ClassLoader2() {
+ @Override
+ public void testModifiedInstance() throws Exception {
+
+ // Check the outer class
+ Class<?> outerClazz2 = loadClass(OUTER_CLASS_NAME);
+ Object o2 = outerClazz2.newInstance();
+ assertNotNull(o2);
+
+ // The original Outer.get returns 1+10+20,
+ // but the delegate makes it return 4+10+20
+ assertEquals(4+10+20, callGet(o2, 10, 20));
+
+ // Check the inner class. Since it's not a static inner class, we need
+ // to use the hidden constructor that takes the outer class as first parameter.
+ Class<?> innerClazz2 = loadClass(INNER_CLASS_NAME);
+ Constructor<?> innerCons = innerClazz2.getConstructor(
+ new Class<?>[] { outerClazz2 });
+ Object i2 = innerCons.newInstance(new Object[] { o2 });
+ assertNotNull(i2);
+
+ // The original Inner.get returns 3+10+20,
+ // but the delegate makes it return 6+10+20
+ assertEquals(6+10+20, callGet(i2, 10, 20));
+ }
+ };
+ cl2.add(OUTER_CLASS_NAME, cwOuter.toByteArray());
+ cl2.add(INNER_CLASS_NAME, cwInner.toByteArray());
+ cl2.testModifiedInstance();
+ } catch (Throwable t) {
+ throw dumpGeneratedClass(t, cl2);
+ }
+ }
+
+ //-------
+
+ /**
+ * A class loader than can define and instantiate our modified classes.
+ * <p/>
+ * The trick here is that this class loader will test our <em>modified</em> version
+ * of the classes, the one with the delegate calls.
+ * <p/>
+ * Trying to do so in the original class loader generates all sort of link issues because
+ * there are 2 different definitions of the same class name. This class loader will
+ * define and load the class when requested by name and provide helpers to access the
+ * instance methods via reflection.
+ */
+ private abstract class ClassLoader2 extends ClassLoader {
+
+ private final Map<String, byte[]> mClassDefs = new HashMap<String, byte[]>();
+
+ public ClassLoader2() {
+ super(null);
+ }
+
+ public ClassLoader2 add(String className, byte[] definition) {
+ mClassDefs.put(className, definition);
+ return this;
+ }
+
+ public ClassLoader2 add(String className, ClassWriter rewrittenClass) {
+ mClassDefs.put(className, rewrittenClass.toByteArray());
+ return this;
+ }
+
+ private Set<Entry<String, byte[]>> getByteCode() {
+ return mClassDefs.entrySet();
+ }
+
+ @SuppressWarnings("unused")
+ @Override
+ protected Class<?> findClass(String name) throws ClassNotFoundException {
+ try {
+ return super.findClass(name);
+ } catch (ClassNotFoundException e) {
+
+ byte[] def = mClassDefs.get(name);
+ if (def != null) {
+ // Load the modified ClassWithNative from its bytes representation.
+ return defineClass(name, def, 0, def.length);
+ }
+
+ try {
+ // Load everything else from the original definition into the new class loader.
+ ClassReader cr = new ClassReader(name);
+ ClassWriter cw = new ClassWriter(0);
+ cr.accept(cw, 0);
+ byte[] bytes = cw.toByteArray();
+ return defineClass(name, bytes, 0, bytes.length);
+
+ } catch (IOException ioe) {
+ throw new RuntimeException(ioe);
+ }
+ }
+ }
+
+ /**
+ * Accesses {@link OuterClass#get()} or {@link InnerClass#get() }via reflection.
+ */
+ public int callGet(Object instance, int a, long b) throws Exception {
+ Method m = instance.getClass().getMethod("get",
+ new Class<?>[] { int.class, long.class } );
+
+ Object result = m.invoke(instance, new Object[] { a, b });
+ return ((Integer) result).intValue();
+ }
+
+ /**
+ * Accesses {@link ClassWithNative#add(int, int)} via reflection.
+ */
+ public int callAdd(Object instance, int a, int b) throws Exception {
+ Method m = instance.getClass().getMethod("add",
+ new Class<?>[] { int.class, int.class });
+
+ Object result = m.invoke(instance, new Object[] { a, b });
+ return ((Integer) result).intValue();
+ }
+
+ /**
+ * Accesses {@link ClassWithNative#callNativeInstance(int, double, Object[])}
+ * via reflection.
+ */
+ public int callCallNativeInstance(Object instance, int a, double d, Object[] o)
+ throws Exception {
+ Method m = instance.getClass().getMethod("callNativeInstance",
+ new Class<?>[] { int.class, double.class, Object[].class });
+
+ Object result = m.invoke(instance, new Object[] { a, d, o });
+ return ((Integer) result).intValue();
+ }
+
+ public abstract void testModifiedInstance() throws Exception;
+ }
+
+ /**
+ * For debugging, it's useful to dump the content of the generated classes
+ * along with the exception that was generated.
+ *
+ * However to make it work you need to pull in the org.objectweb.asm.util.TraceClassVisitor
+ * class and associated utilities which are found in the ASM source jar. Since we don't
+ * want that dependency in the source code, we only put it manually for development and
+ * access the TraceClassVisitor via reflection if present.
+ *
+ * @param t The exception thrown by {@link ClassLoader2#testModifiedInstance()}
+ * @param cl2 The {@link ClassLoader2} instance with the generated bytecode.
+ * @return Either original {@code t} or a new wrapper {@link Throwable}
+ */
+ private Throwable dumpGeneratedClass(Throwable t, ClassLoader2 cl2) {
+ try {
+ // For debugging, dump the bytecode of the class in case of unexpected error
+ // if we can find the TraceClassVisitor class.
+ Class<?> tcvClass = Class.forName("org.objectweb.asm.util.TraceClassVisitor");
+
+ StringBuilder sb = new StringBuilder();
+ sb.append('\n').append(t.getClass().getCanonicalName());
+ if (t.getMessage() != null) {
+ sb.append(": ").append(t.getMessage());
+ }
+
+ for (Entry<String, byte[]> entry : cl2.getByteCode()) {
+ String className = entry.getKey();
+ byte[] bytes = entry.getValue();
+
+ StringWriter sw = new StringWriter();
+ PrintWriter pw = new PrintWriter(sw);
+ // next 2 lines do: TraceClassVisitor tcv = new TraceClassVisitor(pw);
+ Constructor<?> cons = tcvClass.getConstructor(new Class<?>[] { pw.getClass() });
+ Object tcv = cons.newInstance(new Object[] { pw });
+ ClassReader cr2 = new ClassReader(bytes);
+ cr2.accept((ClassVisitor) tcv, 0 /* flags */);
+
+ sb.append("\nBytecode dump: <").append(className).append(">:\n")
+ .append(sw.toString());
+ }
+
+ // Re-throw exception with new message
+ RuntimeException ex = new RuntimeException(sb.toString(), t);
+ return ex;
+ } catch (Throwable ignore) {
+ // In case of problem, just throw the original exception as-is.
+ return t;
+ }
+ }
+
+}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/LogTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/LogTest.java
index 3f13158..1a5f653 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/LogTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/LogTest.java
@@ -24,33 +24,8 @@ import org.junit.Test;
public class LogTest {
- public static class MockLog extends Log {
- StringBuilder mOut = new StringBuilder();
- StringBuilder mErr = new StringBuilder();
-
- public String getOut() {
- return mOut.toString();
- }
-
- public String getErr() {
- return mErr.toString();
- }
-
- @Override
- protected void outPrintln(String msg) {
- mOut.append(msg);
- mOut.append('\n');
- }
-
- @Override
- protected void errPrintln(String msg) {
- mErr.append(msg);
- mErr.append('\n');
- }
- }
-
private MockLog mLog;
-
+
@Before
public void setUp() throws Exception {
mLog = new MockLog();
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/MockLog.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/MockLog.java
new file mode 100644
index 0000000..de750a3
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/MockLog.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+
+public class MockLog extends Log {
+ StringBuilder mOut = new StringBuilder();
+ StringBuilder mErr = new StringBuilder();
+
+ public String getOut() {
+ return mOut.toString();
+ }
+
+ public String getErr() {
+ return mErr.toString();
+ }
+
+ @Override
+ protected void outPrintln(String msg) {
+ mOut.append(msg);
+ mOut.append('\n');
+ }
+
+ @Override
+ protected void errPrintln(String msg) {
+ mErr.append(msg);
+ mErr.append('\n');
+ }
+}
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative.java
new file mode 100644
index 0000000..c314853
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create.dataclass;
+
+import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
+
+/**
+ * Dummy test class with a native method.
+ * The native method is not defined and any attempt to invoke it will
+ * throw an {@link UnsatisfiedLinkError}.
+ *
+ * Used by {@link DelegateClassAdapterTest}.
+ */
+public class ClassWithNative {
+ public ClassWithNative() {
+ }
+
+ public int add(int a, int b) {
+ return a + b;
+ }
+
+ // Note: it's good to have a long or double for testing parameters since they take
+ // 2 slots in the stack/locals maps.
+
+ public int callNativeInstance(int a, double d, Object[] o) {
+ return native_instance(a, d, o);
+ }
+
+ private native int native_instance(int a, double d, Object[] o);
+}
+
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative_Delegate.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative_Delegate.java
new file mode 100644
index 0000000..a3d4dc6
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/ClassWithNative_Delegate.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create.dataclass;
+
+import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
+
+/**
+ * The delegate that receives the call to {@link ClassWithNative_Delegate}'s overridden methods.
+ *
+ * Used by {@link DelegateClassAdapterTest}.
+ */
+public class ClassWithNative_Delegate {
+ public static int native_instance(ClassWithNative instance, int a, double d, Object[] o) {
+ if (o != null && o.length > 0) {
+ o[0] = instance;
+ }
+ return (int)(a + d);
+ }
+}
+
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java
new file mode 100644
index 0000000..9dc2f69
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java
@@ -0,0 +1,48 @@
+/*
+ * 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.tools.layoutlib.create.dataclass;
+
+import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
+
+/**
+ * Test class with an inner class.
+ *
+ * Used by {@link DelegateClassAdapterTest}.
+ */
+public class OuterClass {
+ private int mOuterValue = 1;
+ public OuterClass() {
+ }
+
+ // Outer.get returns 1 + a + b
+ // Note: it's good to have a long or double for testing parameters since they take
+ // 2 slots in the stack/locals maps.
+ public int get(int a, long b) {
+ return mOuterValue + a + (int) b;
+ }
+
+ public class InnerClass {
+ public InnerClass() {
+ }
+
+ // Inner.get returns 1+2=3 + a + b
+ public int get(int a, long b) {
+ return 2 + mOuterValue + a + (int) b;
+ }
+ }
+}
+
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_Delegate.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_Delegate.java
new file mode 100644
index 0000000..3252d87
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_Delegate.java
@@ -0,0 +1,30 @@
+/*
+ * 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.tools.layoutlib.create.dataclass;
+
+import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
+
+/**
+ * Used by {@link DelegateClassAdapterTest}.
+ */
+public class OuterClass_Delegate {
+ // The delegate override of Outer.get returns 4 + a + b
+ public static int get(OuterClass instance, int a, long b) {
+ return 4 + a + (int) b;
+ }
+}
+
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_InnerClass_Delegate.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_InnerClass_Delegate.java
new file mode 100644
index 0000000..b472220
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_InnerClass_Delegate.java
@@ -0,0 +1,30 @@
+/*
+ * 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.tools.layoutlib.create.dataclass;
+
+import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
+import com.android.tools.layoutlib.create.dataclass.OuterClass.InnerClass;
+
+/**
+ * Used by {@link DelegateClassAdapterTest}.
+ */
+public class OuterClass_InnerClass_Delegate {
+ // The delegate override of Inner.get return 6 + a + b
+ public static int get(OuterClass outer, InnerClass inner, int a, long b) {
+ return 6 + a + (int) b;
+ }
+}
diff --git a/voip/jni/rtp/AudioGroup.cpp b/voip/jni/rtp/AudioGroup.cpp
index 2cbd023..ae071ce 100644
--- a/voip/jni/rtp/AudioGroup.cpp
+++ b/voip/jni/rtp/AudioGroup.cpp
@@ -30,6 +30,7 @@
#define LOG_TAG "AudioGroup"
#include <cutils/atomic.h>
+#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -619,6 +620,14 @@ bool AudioGroup::setMode(int mode)
if (mode < 0 || mode > LAST_MODE) {
return false;
}
+ //FIXME: temporary code to overcome echo and mic gain issues on herring board.
+ // Must be modified/removed when proper support for voice processing query and control
+ // is included in audio framework
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.product.board", value, "");
+ if (mode == NORMAL && !strcmp(value, "herring")) {
+ mode = ECHO_SUPPRESSION;
+ }
if (mode == ECHO_SUPPRESSION && AudioSystem::getParameters(
0, String8("ec_supported")) == "ec_supported=yes") {
mode = NORMAL;