From 076357b8567458d4b6dfdcf839ef751634cd2bfb Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 14:04:24 -0800 Subject: [PATCH] auto import from //depot/cupcake/@132589 --- api/current.xml | 1710 ++---- .../libcameraservice/CameraHardwareStub.cpp | 37 +- camera/libcameraservice/CameraHardwareStub.h | 4 +- camera/libcameraservice/CameraService.cpp | 48 +- camera/libcameraservice/CameraService.h | 3 - core/java/android/app/ApplicationContext.java | 39 +- .../android/app/ExpandableListActivity.java | 23 +- core/java/android/app/IntentService.java | 74 - core/java/android/app/ListActivity.java | 26 +- .../java/android/app/NotificationManager.java | 4 +- core/java/android/app/SearchDialog.java | 2 +- core/java/android/app/SearchManager.java | 8 - .../android/bluetooth/BluetoothDevice.java | 4 +- .../java/android/content/ContentProvider.java | 75 +- .../content/ContentProviderNative.java | 43 - .../java/android/content/ContentResolver.java | 360 +- .../android/content/ContentServiceNative.java | 7 - .../android/content/IContentProvider.java | 4 - core/java/android/content/Intent.java | 8 - .../android/content/pm/PackageManager.java | 20 - .../content/res/AssetFileDescriptor.java | 271 +- .../android/content/res/ColorStateList.java | 19 +- core/java/android/content/res/Resources.java | 180 +- .../java/android/content/res/StringBlock.java | 62 +- core/java/android/content/res/TypedArray.java | 28 - .../database/sqlite/SQLiteDatabase.java | 4 +- .../database/sqlite/SQLiteStatement.java | 22 - core/java/android/gadget/GadgetHost.java | 12 +- core/java/android/gadget/GadgetHostView.java | 255 +- core/java/android/gadget/GadgetManager.java | 16 - core/java/android/hardware/Camera.java | 1 + .../inputmethodservice/ExtractEditText.java | 7 - .../InputMethodService.java | 266 +- .../inputmethodservice/KeyboardView.java | 22 +- .../net/SSLCertificateSocketFactory.java | 78 +- .../android/net/http/AndroidHttpClient.java | 46 +- .../net/http/CertificateChainValidator.java | 154 +- core/java/android/os/BatteryStats.java | 135 +- .../java/android/os/ParcelFileDescriptor.java | 18 - core/java/android/pim/ICalendar.java | 15 +- core/java/android/provider/Checkin.java | 10 +- core/java/android/provider/Im.java | 33 - core/java/android/provider/Settings.java | 49 +- .../android/server/BluetoothA2dpService.java | 82 +- .../server/BluetoothDeviceService.java | 24 +- .../android/server/search/SearchableInfo.java | 18 +- core/java/android/speech/srec/package.html | 1 - core/java/android/text/InputType.java | 5 + core/java/android/text/Styled.java | 243 +- core/java/android/text/format/DateUtils.java | 216 +- .../text/method/NumberKeyListener.java | 5 - core/java/android/view/GestureDetector.java | 91 +- core/java/android/view/KeyEvent.java | 6 - core/java/android/view/View.java | 47 +- core/java/android/view/ViewConfiguration.java | 18 +- core/java/android/view/ViewRoot.java | 39 +- .../view/inputmethod/BaseInputConnection.java | 7 - .../android/view/inputmethod/EditorInfo.java | 106 +- .../view/inputmethod/InputConnection.java | 14 - .../view/inputmethod/InputMethodManager.java | 18 +- core/java/android/webkit/CallbackProxy.java | 8 +- core/java/android/webkit/TextDialog.java | 103 +- core/java/android/webkit/WebView.java | 100 +- core/java/android/webkit/WebViewCore.java | 4 +- core/java/android/widget/AbsListView.java | 29 +- core/java/android/widget/AbsSeekBar.java | 45 +- core/java/android/widget/AnalogClock.java | 17 +- .../android/widget/AutoCompleteTextView.java | 103 +- core/java/android/widget/BaseAdapter.java | 4 - core/java/android/widget/Chronometer.java | 19 +- core/java/android/widget/CursorAdapter.java | 20 +- core/java/android/widget/Filter.java | 14 +- core/java/android/widget/GridView.java | 29 +- .../android/widget/HorizontalScrollView.java | 2 +- core/java/android/widget/ImageView.java | 2 +- core/java/android/widget/ListView.java | 85 +- .../widget/MultiAutoCompleteTextView.java | 4 +- core/java/android/widget/PopupWindow.java | 63 +- core/java/android/widget/ProgressBar.java | 1 - .../android/widget/ResourceCursorAdapter.java | 22 +- core/java/android/widget/TextView.java | 359 +- .../android/widget/ZoomButtonsController.java | 478 -- core/java/android/widget/ZoomRing.java | 418 +- .../android/widget/ZoomRingController.java | 462 +- .../android/internal/app/IBatteryStats.aidl | 2 - .../internal/gadget/IGadgetService.aidl | 1 - .../internal/logging/AndroidConfig.java | 11 +- .../internal/logging/AndroidHandler.java | 69 +- .../internal/net/DbSSLSessionCache.java | 269 - .../android/internal/net/SSLSessionCache.java | 101 - .../android/internal/os/BatteryStatsImpl.java | 327 +- .../com/android/internal/os/ZygoteInit.java | 83 +- .../view/IInputConnectionWrapper.java | 16 +- .../android/internal/view/IInputContext.aidl | 2 - .../internal/view/InputConnectionWrapper.java | 9 - .../internal/view/menu/ExpandedMenuView.java | 5 - .../widget/EditableInputConnection.java | 15 +- .../internal/widget/TextProgressBar.java | 4 +- .../gdata/client/AndroidGDataClient.java | 21 +- .../google/android/net/GoogleHttpClient.java | 58 +- core/jni/android_database_SQLiteDatabase.cpp | 8 +- core/jni/android_hardware_Camera.cpp | 280 +- core/jni/android_media_AudioTrack.cpp | 34 +- core/jni/android_os_ParcelFileDescriptor.cpp | 30 +- .../jni/android_server_BluetoothEventLoop.cpp | 9 +- core/jni/android_util_Binder.cpp | 1 - ...com_android_server_AlarmManagerService.cpp | 7 +- core/res/AndroidManifest.xml | 2 +- core/res/res/drawable-land/title_bar.9.png | Bin 0 -> 5751 bytes .../res/res/drawable/activity_title_bar.9.png | Bin 205 -> 0 bytes core/res/res/drawable/btn_check_off.png | Bin 1172 -> 1158 bytes .../btn_check_off_disable_focused.png | Bin 1073 -> 1062 bytes .../res/drawable/btn_check_off_selected.png | Bin 1598 -> 1587 bytes .../drawable/btn_check_on_disable_focused.png | Bin 1138 -> 1132 bytes .../res/res/drawable/btn_default_normal.9.png | Bin 763 -> 819 bytes .../drawable/btn_default_normal_disable.9.png | Bin 474 -> 507 bytes .../btn_default_normal_disable_focused.9.png | Bin 673 -> 697 bytes .../res/drawable/btn_default_pressed.9.png | Bin 1083 -> 1245 bytes .../res/drawable/btn_default_selected.9.png | Bin 1099 -> 1294 bytes .../drawable/btn_default_small_normal.9.png | Bin 679 -> 789 bytes .../btn_default_small_normal_disable.9.png | Bin 456 -> 488 bytes ...default_small_normal_disable_focused.9.png | Bin 648 -> 688 bytes .../drawable/btn_default_small_pressed.9.png | Bin 936 -> 1099 bytes .../drawable/btn_default_small_selected.9.png | Bin 964 -> 1105 bytes core/res/res/drawable/btn_radio_on.png | Bin 1692 -> 1673 bytes .../drawable/btn_rating_star_off_normal.png | Bin 2760 -> 3036 bytes .../drawable/btn_rating_star_off_pressed.png | Bin 3613 -> 3882 bytes .../drawable/btn_rating_star_off_selected.png | Bin 3622 -> 3870 bytes .../drawable/btn_rating_star_on_normal.png | Bin 3290 -> 3469 bytes .../drawable/btn_rating_star_on_pressed.png | Bin 3756 -> 3905 bytes .../drawable/btn_rating_star_on_selected.png | Bin 3768 -> 3950 bytes core/res/res/drawable/btn_star_big_off.png | Bin 1316 -> 1460 bytes .../res/drawable/btn_star_big_off_pressed.png | Bin 1507 -> 4401 bytes .../drawable/btn_star_big_off_selected.png | Bin 1471 -> 4407 bytes core/res/res/drawable/btn_star_big_on.png | Bin 1521 -> 4449 bytes .../res/drawable/btn_star_big_on_pressed.png | Bin 1540 -> 4249 bytes .../res/drawable/btn_star_big_on_selected.png | Bin 1456 -> 4232 bytes .../res/drawable/ic_lock_airplane_mode.png | Bin 1119 -> 0 bytes .../drawable/ic_lock_airplane_mode_off.png | Bin 1570 -> 0 bytes core/res/res/drawable/ic_lock_power_off.png | Bin 1709 -> 1713 bytes core/res/res/drawable/ic_lock_silent_mode.png | Bin 1362 -> 1362 bytes .../res/drawable/ic_lock_silent_mode_off.png | Bin 1554 -> 1555 bytes .../keyboard_accessory_bg_landscape.9.png | Bin 197 -> 0 bytes core/res/res/drawable/textfield_default.9.png | Bin 758 -> 871 bytes .../res/res/drawable/textfield_disabled.9.png | Bin 545 -> 606 bytes .../textfield_disabled_selected.9.png | Bin 570 -> 751 bytes core/res/res/drawable/textfield_pressed.9.png | Bin 1040 -> 1145 bytes .../res/res/drawable/textfield_selected.9.png | Bin 790 -> 886 bytes .../drawable/timepicker_down_disabled.9.png | Bin 444 -> 956 bytes .../timepicker_down_disabled_focused.9.png | Bin 611 -> 938 bytes .../res/drawable/timepicker_down_normal.9.png | Bin 806 -> 884 bytes .../drawable/timepicker_down_pressed.9.png | Bin 1257 -> 1482 bytes .../drawable/timepicker_down_selected.9.png | Bin 1292 -> 1459 bytes .../drawable/timepicker_input_disabled.9.png | Bin 280 -> 484 bytes .../drawable/timepicker_input_normal.9.png | Bin 582 -> 567 bytes .../drawable/timepicker_input_pressed.9.png | Bin 604 -> 593 bytes .../drawable/timepicker_input_selected.9.png | Bin 517 -> 578 bytes .../res/drawable/timepicker_up_disabled.9.png | Bin 512 -> 1278 bytes .../timepicker_up_disabled_focused.9.png | Bin 724 -> 1258 bytes .../res/drawable/timepicker_up_normal.9.png | Bin 1058 -> 1173 bytes .../res/drawable/timepicker_up_pressed.9.png | Bin 1500 -> 1864 bytes .../res/drawable/timepicker_up_selected.9.png | Bin 1519 -> 1847 bytes core/res/res/drawable/title_bar.9.png | Bin 0 -> 4121 bytes core/res/res/drawable/title_bar.xml | 20 - .../res/drawable/zoom_ring_overview_tab.9.png | Bin 1792 -> 845 bytes .../res/drawable/zoom_ring_thumb_minus.png | Bin 201 -> 0 bytes .../drawable/zoom_ring_thumb_minus_arrow.png | Bin 1941 -> 3157 bytes .../res/res/drawable/zoom_ring_thumb_plus.png | Bin 317 -> 0 bytes .../drawable/zoom_ring_thumb_plus_arrow.png | Bin 2272 -> 3231 bytes core/res/res/drawable/zoom_ring_track.png | Bin 17749 -> 16980 bytes .../res/drawable/zoom_ring_track_absolute.png | Bin 18612 -> 19660 bytes .../res/layout/alert_dialog_simple_text.xml | 26 - core/res/res/layout/global_actions_item.xml | 60 +- .../res/layout/input_method_extract_view.xml | 43 +- .../layout/keyguard_screen_glogin_unlock.xml | 2 +- core/res/res/layout/keyguard_screen_lock.xml | 3 +- .../keyguard_screen_sim_pin_landscape.xml | 2 +- .../keyguard_screen_sim_pin_portrait.xml | 2 +- .../keyguard_screen_unlock_landscape.xml | 8 +- .../keyguard_screen_unlock_portrait.xml | 21 +- core/res/res/layout/search_bar.xml | 7 +- core/res/res/layout/select_dialog_item.xml | 3 +- .../status_bar_latest_event_content.xml | 4 - core/res/res/values-cs/strings.xml | 61 +- core/res/res/values-de/strings.xml | 47 +- core/res/res/values-es/strings.xml | 137 +- core/res/res/values-fr/strings.xml | 357 +- core/res/res/values-it/strings.xml | 281 +- core/res/res/values-ja-rJP/arrays.xml | 32 - core/res/res/values-ja/strings.xml | 47 +- core/res/res/values-ko/strings.xml | 47 +- core/res/res/values-nb/strings.xml | 69 +- core/res/res/values-nl/strings.xml | 79 +- core/res/res/values-pl/strings.xml | 109 +- core/res/res/values-ru/strings.xml | 47 +- core/res/res/values-zh-rCN/strings.xml | 47 +- core/res/res/values-zh-rTW/strings.xml | 47 +- core/res/res/values/arrays.xml | 165 +- core/res/res/values/attrs.xml | 108 +- core/res/res/values/public.xml | 7 +- core/res/res/values/strings.xml | 35 +- core/res/res/values/styles.xml | 3 +- docs/html/app.yaml | 29 +- docs/html/community/index.jd | 4 +- docs/html/guide/publishing/app-signing.jd | 2 +- docs/html/guide/publishing/preparing.jd | 36 +- docs/html/guide/publishing/publishing.jd | 2 +- .../guide/topics/manifest/manifest-intro.jd | 2 +- docs/html/guide/topics/ui/themes.jd | 43 +- .../tutorials/views/hello-autocomplete.jd | 2 +- .../guide/tutorials/views/hello-formstuff.jd | 20 +- .../guide/tutorials/views/hello-gridview.jd | 1 - .../guide/tutorials/views/hello-mapview.jd | 32 +- docs/html/sdk/1.0_r1/index.jd | 75 +- docs/html/sdk/1.0_r1/installing.jd | 171 +- docs/html/sdk/1.0_r1/upgrading.jd | 103 +- docs/html/sdk/1.0_r2/index.jd | 75 +- docs/html/sdk/1.0_r2/installing.jd | 171 +- docs/html/sdk/1.0_r2/requirements.jd | 44 - docs/html/sdk/1.0_r2/upgrading.jd | 103 +- docs/html/sdk/1.1_r1/index.jd | 12 +- docs/html/sdk/1.1_r1/installing.jd | 139 +- docs/html/sdk/sdk_toc.cs | 44 +- docs/html/search.jd | 68 +- docs/html/sitemap.txt | 5444 ----------------- .../android/graphics/drawable/Drawable.java | 2 - .../graphics/drawable/NinePatchDrawable.java | 81 +- .../graphics/drawable/StateListDrawable.java | 15 +- include/media/AudioRecord.h | 9 +- include/media/IMediaRecorder.h | 2 - include/media/PVMediaRecorder.h | 2 - include/media/mediarecorder.h | 39 +- include/ui/CameraHardwareInterface.h | 3 - include/utils/ResourceTypes.h | 16 +- libs/audioflinger/A2dpAudioInterface.cpp | 15 +- libs/audioflinger/A2dpAudioInterface.h | 1 + libs/audioflinger/AudioFlinger.cpp | 17 +- libs/audioflinger/AudioFlinger.h | 5 +- libs/audioflinger/AudioHardwareGeneric.h | 2 +- libs/ui/Camera.cpp | 2 - libs/utils/Threads.cpp | 4 +- .../android/internal/location/CellState.java | 11 +- .../location/INetworkLocationManager.java | 2 +- media/java/android/media/AudioRecord.java | 38 +- media/java/android/media/AudioTrack.java | 57 +- media/java/android/media/JetPlayer.java | 11 +- .../android/media/MediaMetadataRetriever.java | 14 +- media/java/android/media/MediaPlayer.java | 13 +- media/java/android/media/MediaRecorder.java | 238 +- media/java/android/media/Ringtone.java | 13 +- media/java/android/media/SoundPool.java | 7 +- media/jni/android_media_MediaRecorder.cpp | 153 +- media/libmedia/AudioRecord.cpp | 25 +- media/libmedia/AudioTrack.cpp | 13 +- media/libmedia/IMediaRecorder.cpp | 22 +- media/libmedia/mediarecorder.cpp | 75 - .../MediaPlayerService.cpp | 110 - .../MediaRecorderClient.cpp | 11 - .../MediaRecorderClient.h | 1 - .../MediaFrameworkTestRunner.java | 5 +- .../functional/CameraTest.java | 12 +- .../functional/MediaAudioTrackTest.java | 755 +-- .../performance/MediaPlayerPerformance.java | 465 +- opengl/java/android/opengl/Matrix.java | 57 +- opengl/java/android/opengl/Visibility.java | 1 + opengl/libagl/egl.cpp | 6 +- opengl/libs/EGL/egl.cpp | 8 +- .../providers/settings/DatabaseHelper.java | 32 +- .../AndroidManifest.xml | 5 +- .../SubscribedFeedsBroadcastReceiver.java | 41 - ...rvice.java => SubscribedFeedsService.java} | 106 +- preloaded-classes | 2 +- .../android/server/AlarmManagerService.java | 89 +- .../com/android/server/BatteryService.java | 116 +- .../com/android/server/GadgetService.java | 15 +- .../com/android/server/HardwareService.java | 2 - .../server/LocationManagerService.java | 116 +- .../java/com/android/server/MountService.java | 9 +- .../server/NotificationManagerService.java | 13 - .../android/server/PackageManagerService.java | 99 +- .../android/server/PowerManagerService.java | 10 +- .../java/com/android/server/SystemServer.java | 7 +- .../com/android/server/TelephonyRegistry.java | 20 +- .../android/server/WindowManagerService.java | 80 +- .../server/am/ActivityManagerService.java | 35 +- .../android/server/am/BaseErrorDialog.java | 2 - .../server/am/BatteryStatsService.java | 30 +- .../server/status/StatusBarPolicy.java | 7 +- .../server/status/StatusBarService.java | 15 +- .../android/telephony/gsm/SmsMessage.java | 28 +- .../telephony/gsm/DataConnectionTracker.java | 3 - .../internal/telephony/gsm/GSMPhone.java | 36 +- .../internal/telephony/gsm/GsmAlphabet.java | 4 +- .../test/mock/MockContentProvider.java | 7 - .../android/test/mock/MockPackageManager.java | 7 - .../com/android/unit_tests/AppCacheTest.java | 12 +- .../unit_tests/DbSSLSessionCacheTest.java | 273 - .../android/core/DatabaseSessionCache.java | 312 - .../android/core/SSLPerformanceTest.java | 432 -- .../CoreTests/android/core/SSLSocketTest.java | 243 +- .../LocationManagerProximityTest.java | 49 +- tests/CoreTests/run_core_test.sh | 4 +- .../imftest/samples/InputTypeActivity.java | 4 + .../res/layout/test_gadget.xml | 7 +- .../res/xml/gadget_info.xml | 6 +- tools/aapt/Images.cpp | 8 - .../android/layoutlib/api/ILayoutBridge.java | 57 +- .../com/android/layoutlib/bridge/Bridge.java | 42 +- .../layoutlib/bridge/BridgeContext.java | 21 +- tools/preload/Android.mk | 14 +- 310 files changed, 4072 insertions(+), 18131 deletions(-) delete mode 100644 core/java/android/app/IntentService.java delete mode 100644 core/java/android/widget/ZoomButtonsController.java delete mode 100644 core/java/com/android/internal/net/DbSSLSessionCache.java delete mode 100644 core/java/com/android/internal/net/SSLSessionCache.java create mode 100644 core/res/res/drawable-land/title_bar.9.png delete mode 100644 core/res/res/drawable/activity_title_bar.9.png delete mode 100755 core/res/res/drawable/ic_lock_airplane_mode.png delete mode 100755 core/res/res/drawable/ic_lock_airplane_mode_off.png delete mode 100644 core/res/res/drawable/keyboard_accessory_bg_landscape.9.png create mode 100644 core/res/res/drawable/title_bar.9.png delete mode 100644 core/res/res/drawable/title_bar.xml delete mode 100644 core/res/res/drawable/zoom_ring_thumb_minus.png delete mode 100644 core/res/res/drawable/zoom_ring_thumb_plus.png delete mode 100644 core/res/res/layout/alert_dialog_simple_text.xml delete mode 100644 core/res/res/values-ja-rJP/arrays.xml delete mode 100644 docs/html/sdk/1.0_r2/requirements.jd delete mode 100644 docs/html/sitemap.txt delete mode 100644 packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/SubscribedFeedsBroadcastReceiver.java rename packages/SubscribedFeedsProvider/src/com/android/providers/subscribedfeeds/{SubscribedFeedsIntentService.java => SubscribedFeedsService.java} (77%) delete mode 100644 tests/AndroidTests/src/com/android/unit_tests/DbSSLSessionCacheTest.java delete mode 100644 tests/CoreTests/android/core/DatabaseSessionCache.java delete mode 100644 tests/CoreTests/android/core/SSLPerformanceTest.java diff --git a/api/current.xml b/api/current.xml index 671ae21e5bc96..9ccb8f7945ecb 100644 --- a/api/current.xml +++ b/api/current.xml @@ -2836,17 +2836,6 @@ visibility="public" > - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -80036,17 +79460,6 @@ visibility="public" > - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - @@ -99981,21 +99848,6 @@ - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - CameraHardwareStub::getPreviewHeap() const { - return mPreviewHeap; -} - -sp CameraHardwareStub::getRawHeap() const -{ - return mRawHeap; + return mHeap; } // --------------------------------------------------------------------------- @@ -124,7 +114,7 @@ int CameraHardwareStub::previewThread() // Find the offset within the heap of the current buffer. ssize_t offset = mCurrentPreviewFrame * mPreviewFrameSize; - sp heap = mPreviewHeap; + sp heap = mHeap; // this assumes the internal state of fake camera doesn't change // (or is thread safe) @@ -265,9 +255,10 @@ int CameraHardwareStub::pictureThread() // In the meantime just make another fake camera picture. int w, h; mParameters.getPictureSize(&w, &h); - sp mem = new MemoryBase(mRawHeap, 0, w * 2 * h); + sp heap = new MemoryHeapBase(w * 2 * h); + sp mem = new MemoryBase(heap, 0, w * 2 * h); FakeCamera cam(w, h); - cam.getNextFrameAsYuv422((uint8_t *)mRawHeap->base()); + cam.getNextFrameAsYuv422((uint8_t *)heap->base()); if (mRawPictureCallback) mRawPictureCallback(mem, mPictureCallbackCookie); } diff --git a/camera/libcameraservice/CameraHardwareStub.h b/camera/libcameraservice/CameraHardwareStub.h index 0d26d47ececb3..cdd60116f36ef 100644 --- a/camera/libcameraservice/CameraHardwareStub.h +++ b/camera/libcameraservice/CameraHardwareStub.h @@ -30,7 +30,6 @@ namespace android { class CameraHardwareStub : public CameraHardwareInterface { public: virtual sp getPreviewHeap() const; - virtual sp getRawHeap() const; virtual status_t startPreview(preview_callback cb, void* user); virtual void stopPreview(); @@ -94,8 +93,7 @@ private: CameraParameters mParameters; - sp mPreviewHeap; - sp mRawHeap; + sp mHeap; sp mBuffers[kBufferCount]; FakeCamera *mFakeCamera; diff --git a/camera/libcameraservice/CameraService.cpp b/camera/libcameraservice/CameraService.cpp index 953e637ada3be..e5d42203f5142 100644 --- a/camera/libcameraservice/CameraService.cpp +++ b/camera/libcameraservice/CameraService.cpp @@ -152,7 +152,7 @@ void CameraService::removeClient(const sp& cameraClient) } CameraService::Client::Client(const sp& cameraService, - const sp& cameraClient, pid_t clientPid) + const sp& cameraClient, pid_t clientPid) { LOGD("Client E constructor"); mCameraService = cameraService; @@ -429,7 +429,7 @@ status_t CameraService::Client::startPreviewMode() ret = mHardware->startPreview(NULL, mCameraService.get()); if (ret != NO_ERROR) LOGE("mHardware->startPreview() failed with status %d\n", ret); - + } else { ret = mHardware->startPreview(previewCallback, mCameraService.get()); @@ -684,33 +684,13 @@ status_t CameraService::Client::takePicture() return INVALID_OPERATION; } + if (mSurface != NULL && !mUseOverlay) + mSurface->unregisterBuffers(); - Mutex::Autolock buffer_lock(mBufferLock); - result = mHardware->takePicture(shutterCallback, + return mHardware->takePicture(shutterCallback, yuvPictureCallback, jpegPictureCallback, mCameraService.get()); - - // It takes quite some time before yuvPicture callback to be called. - // Register the buffer for raw image here to reduce latency. - // But yuvPictureCallback is called from libcamera. So do not call into a - // libcamera function here that gets another lock, which may cause deadlock. - if (mSurface != 0 && !mUseOverlay) { - int w, h; - CameraParameters params(mHardware->getParameters()); - params.getPictureSize(&w, &h); - mSurface->unregisterBuffers(); - uint32_t transform = 0; - if (params.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) { - LOGV("portrait mode"); - transform = ISurface::BufferHeap::ROT_90; - } - ISurface::BufferHeap buffers(w, h, w, h, - PIXEL_FORMAT_YCbCr_420_SP, transform, 0, mHardware->getRawHeap()); - mSurface->registerBuffers(buffers); - } - - return result; } // picture callback - snapshot taken @@ -752,9 +732,23 @@ void CameraService::Client::yuvPictureCallback(const sp& mem, #endif // Put the YUV version of the snapshot in the preview display. - // Use lock to make sure buffer has been registered. - Mutex::Autolock clientLock(client->mBufferLock); + int w, h; + CameraParameters params(client->mHardware->getParameters()); + params.getPictureSize(&w, &h); + +// Mutex::Autolock clientLock(client->mLock); if (client->mSurface != 0 && !client->mUseOverlay) { + client->mSurface->unregisterBuffers(); + + uint32_t transform = 0; + if (params.getOrientation() == CameraParameters::CAMERA_ORIENTATION_PORTRAIT) { + LOGV("portrait mode"); + transform = ISurface::BufferHeap::ROT_90; + } + ISurface::BufferHeap buffers(w, h, w, h, + PIXEL_FORMAT_YCbCr_420_SP, transform, 0, heap); + + client->mSurface->registerBuffers(buffers); client->mSurface->postBuffer(offset); } diff --git a/camera/libcameraservice/CameraService.h b/camera/libcameraservice/CameraService.h index 812b9280aa0bf..d9b79276a72a8 100644 --- a/camera/libcameraservice/CameraService.h +++ b/camera/libcameraservice/CameraService.h @@ -172,9 +172,6 @@ private: // for a callback from CameraHardwareInterface. If this // happens, it will cause a deadlock. mutable Mutex mSurfaceLock; - // mBufferLock synchronizes buffer registration between takePicture() - // and yuvPictureCallback(). - mutable Mutex mBufferLock; mutable Condition mReady; sp mCameraService; sp mSurface; diff --git a/core/java/android/app/ApplicationContext.java b/core/java/android/app/ApplicationContext.java index 3b5ad862710f5..394b8e3b361c5 100644 --- a/core/java/android/app/ApplicationContext.java +++ b/core/java/android/app/ApplicationContext.java @@ -1487,7 +1487,7 @@ class ApplicationContext extends Context { static final class ApplicationPackageManager extends PackageManager { @Override public PackageInfo getPackageInfo(String packageName, int flags) - throws NameNotFoundException { + throws NameNotFoundException { try { PackageInfo pi = mPM.getPackageInfo(packageName, flags); if (pi != null) { @@ -1500,43 +1500,6 @@ class ApplicationContext extends Context { throw new NameNotFoundException(packageName); } - public Intent getLaunchIntentForPackage(String packageName) - throws NameNotFoundException { - // First see if the package has an INFO activity; the existence of - // such an activity is implied to be the desired front-door for the - // overall package (such as if it has multiple launcher entries). - Intent intent = getLaunchIntentForPackageCategory(this, packageName, - Intent.CATEGORY_INFO); - if (intent != null) { - return intent; - } - - // Otherwise, try to find a main launcher activity. - return getLaunchIntentForPackageCategory(this, packageName, - Intent.CATEGORY_LAUNCHER); - } - - // XXX This should be implemented as a call to the package manager, - // to reduce the work needed. - static Intent getLaunchIntentForPackageCategory(PackageManager pm, - String packageName, String category) { - Intent intent = new Intent(Intent.ACTION_MAIN); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - Intent intentToResolve = new Intent(Intent.ACTION_MAIN, null); - intentToResolve.addCategory(category); - final List apps = - pm.queryIntentActivities(intentToResolve, 0); - // I wish there were a way to directly get the "main" activity of a - // package but ... - for (ResolveInfo app : apps) { - if (app.activityInfo.packageName.equals(packageName)) { - intent.setClassName(packageName, app.activityInfo.name); - return intent; - } - } - return null; - } - @Override public int[] getPackageGids(String packageName) throws NameNotFoundException { diff --git a/core/java/android/app/ExpandableListActivity.java b/core/java/android/app/ExpandableListActivity.java index a2e048f53f484..75dfcae5a8f91 100644 --- a/core/java/android/app/ExpandableListActivity.java +++ b/core/java/android/app/ExpandableListActivity.java @@ -63,21 +63,21 @@ import java.util.Map; * *
  * <?xml version="1.0" encoding="UTF-8"?>
- * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ * <LinearLayout
  *         android:orientation="vertical"
  *         android:layout_width="fill_parent" 
  *         android:layout_height="fill_parent"
- *         android:paddingLeft="8dp"
- *         android:paddingRight="8dp">
+ *         android:paddingLeft="8"
+ *         android:paddingRight="8">
  * 
- *     <ExpandableListView android:id="@id/android:list"
+ *     <ExpandableListView id="android:list"
  *               android:layout_width="fill_parent" 
  *               android:layout_height="fill_parent"
  *               android:background="#00FF00"
  *               android:layout_weight="1"
  *               android:drawSelectorOnTop="false"/>
  * 
- *     <TextView android:id="@id/android:empty"
+ *     <TextView id="android:empty"
  *               android:layout_width="fill_parent" 
  *               android:layout_height="fill_parent"
  *               android:background="#FF0000"
@@ -113,19 +113,19 @@ import java.util.Map;
  * 
  * 
  * <?xml version="1.0" encoding="utf-8"?>
- * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ * <LinearLayout
  *     android:layout_width="fill_parent"
  *     android:layout_height="wrap_content"
  *     android:orientation="vertical">
  * 
- *     <TextView android:id="@+id/text1"
- *         android:textSize="16sp"
+ *     <TextView id="text1"
+ *         android:textSize="16"
  *         android:textStyle="bold"
  *         android:layout_width="fill_parent"
  *         android:layout_height="wrap_content"/>
  * 
- *     <TextView android:id="@+id/text2"
- *         android:textSize="16sp"
+ *     <TextView id="text2"
+ *         android:textSize="16"
  *         android:layout_width="fill_parent"
  *         android:layout_height="wrap_content"/>
  * </LinearLayout>
@@ -162,8 +162,7 @@ public class ExpandableListActivity extends Activity implements
 
     /**
      * Override this to populate the context menu when an item is long pressed. menuInfo
-     * will contain an {@link android.widget.ExpandableListView.ExpandableListContextMenuInfo}
-     * whose packedPosition is a packed position
+     * will contain a {@link AdapterContextMenuInfo} whose position is a packed position
      * that should be used with {@link ExpandableListView#getPackedPositionType(long)} and
      * the other similar methods.
      * 

diff --git a/core/java/android/app/IntentService.java b/core/java/android/app/IntentService.java deleted file mode 100644 index 2b12a2a1304d1..0000000000000 --- a/core/java/android/app/IntentService.java +++ /dev/null @@ -1,74 +0,0 @@ -package android.app; - -import android.content.Intent; -import android.os.Handler; -import android.os.HandlerThread; -import android.os.IBinder; -import android.os.Looper; -import android.os.Message; - -/** - * An abstract {@link Service} that serializes the handling of the Intents passed upon service - * start and handles them on a handler thread. - * - *

To use this class extend it and implement {@link #onHandleIntent}. The {@link Service} will - * automatically be stopped when the last enqueued {@link Intent} is handled. - */ -public abstract class IntentService extends Service { - private volatile Looper mServiceLooper; - private volatile ServiceHandler mServiceHandler; - private String mName; - - private final class ServiceHandler extends Handler { - public ServiceHandler(Looper looper) { - super(looper); - } - - @Override - public void handleMessage(Message msg) { - onHandleIntent((Intent)msg.obj); - stopSelf(msg.arg1); - } - } - - public IntentService(String name) { - super(); - mName = name; - } - - @Override - public void onCreate() { - super.onCreate(); - HandlerThread thread = new HandlerThread("IntentService[" + mName + "]"); - thread.start(); - - mServiceLooper = thread.getLooper(); - mServiceHandler = new ServiceHandler(mServiceLooper); - } - - @Override - public void onStart(Intent intent, int startId) { - super.onStart(intent, startId); - Message msg = mServiceHandler.obtainMessage(); - msg.arg1 = startId; - msg.obj = intent; - mServiceHandler.sendMessage(msg); - } - - @Override - public void onDestroy() { - mServiceLooper.quit(); - } - - @Override - public IBinder onBind(Intent intent) { - return null; - } - - /** - * Invoked on the Handler thread with the {@link Intent} that is passed to {@link #onStart}. - * Note that this will be invoked from a different thread than the one that handles the - * {@link #onStart} call. - */ - protected abstract void onHandleIntent(Intent intent); -} diff --git a/core/java/android/app/ListActivity.java b/core/java/android/app/ListActivity.java index 5523c185f21ae..281893734b0d9 100644 --- a/core/java/android/app/ListActivity.java +++ b/core/java/android/app/ListActivity.java @@ -53,22 +53,22 @@ import android.widget.ListView; *

* *
- * <?xml version="1.0" encoding="utf-8"?>
- * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ * <?xml version="1.0" encoding="UTF-8"?>
+ * <LinearLayout
  *         android:orientation="vertical"
  *         android:layout_width="fill_parent" 
  *         android:layout_height="fill_parent"
- *         android:paddingLeft="8dp"
- *         android:paddingRight="8dp">
+ *         android:paddingLeft="8"
+ *         android:paddingRight="8">
  * 
- *     <ListView android:id="@id/android:list"
+ *     <ListView id="android:list"
  *               android:layout_width="fill_parent" 
  *               android:layout_height="fill_parent"
  *               android:background="#00FF00"
  *               android:layout_weight="1"
  *               android:drawSelectorOnTop="false"/>
  * 
- *     <TextView id="@id/android:empty"
+ *     <TextView id="android:empty"
  *               android:layout_width="fill_parent" 
  *               android:layout_height="fill_parent"
  *               android:background="#FF0000"
@@ -99,19 +99,19 @@ import android.widget.ListView;
  * 
  * 
  * <?xml version="1.0" encoding="utf-8"?>
- * <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+ * <LinearLayout
  *     android:layout_width="fill_parent"
  *     android:layout_height="wrap_content"
  *     android:orientation="vertical">
  * 
- *     <TextView android:id="@+id/text1"
- *         android:textSize="16sp"
+ *     <TextView id="text1"
+ *         android:textSize="16"
  *         android:textStyle="bold"
  *         android:layout_width="fill_parent"
  *         android:layout_height="wrap_content"/>
  * 
- *     <TextView android:id="@+id/text2"
- *         android:textSize="16sp"
+ *     <TextView id="text2"
+ *         android:textSize="16"
  *         android:layout_width="fill_parent"
  *         android:layout_height="wrap_content"/>
  * </LinearLayout>
@@ -142,8 +142,8 @@ import android.widget.ListView;
  * public class MyListAdapter extends ListActivity {
  * 
  *     @Override
- *     protected void onCreate(Bundle savedInstanceState){
- *         super.onCreate(savedInstanceState);
+ *     protected void onCreate(Bundle icicle){
+ *         super.onCreate(icicle);
  * 
  *         // We'll define a custom screen layout here (the one shown above), but
  *         // typically, you could just use the standard ListActivity layout.
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 39edab70d1415..afb3827878ede 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -82,7 +82,9 @@ public class NotificationManager
      * @param id An identifier for this notification unique within your
      *        application.
      * @param notification A {@link Notification} object describing how to
-     *        notify the user, other than the view you're providing. Must not be null.
+     *        notify the user, other than the view you're providing.  If you
+     *        pass null, there will be no persistent notification and no
+     *        flashing, vibration, etc.
      */
     public void notify(int id, Notification notification)
     {
diff --git a/core/java/android/app/SearchDialog.java b/core/java/android/app/SearchDialog.java
index d447eb22d5df1..7b8256c46a008 100644
--- a/core/java/android/app/SearchDialog.java
+++ b/core/java/android/app/SearchDialog.java
@@ -448,7 +448,6 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
                 }
             }
             mSearchTextField.setInputType(inputType);
-            mSearchTextField.setImeOptions(mSearchable.getImeOptions());
         }
     }
 
@@ -794,6 +793,7 @@ public class SearchDialog extends Dialog implements OnItemClickListener, OnItemS
                 // otherwise, dispatch an "edit view" key
                 switch (keyCode) {
                 case KeyEvent.KEYCODE_ENTER:
+                case KeyEvent.KEYCODE_DPAD_CENTER:
                     if (event.getAction() == KeyEvent.ACTION_UP) {
                         v.cancelLongPress();
                         launchQuerySearch(KeyEvent.KEYCODE_UNKNOWN, null);                    
diff --git a/core/java/android/app/SearchManager.java b/core/java/android/app/SearchManager.java
index c1d66f4e7d7bc..2cc6de9515324 100644
--- a/core/java/android/app/SearchManager.java
+++ b/core/java/android/app/SearchManager.java
@@ -747,14 +747,6 @@ import android.view.KeyEvent;
  *             inputType attribute.
  *         No
  *     
- *     android:imeOptions
- *         If provided, supplies additional options for the input method.
- *             For most searches, in which free form text is expected, this attribute
- *             need not be provided, and will default to "actionSearch".
- *             Suitable values for this attribute are described in the
- *             imeOptions attribute.
- *         No
- *     
  *     
  *     
  * 
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 1ba1c1e86f7b9..56b231fa6b13f 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -63,10 +63,8 @@ public class BluetoothDevice {
     public static final int UNBOND_REASON_AUTH_CANCELED = 3;
     /** A bond attempt failed because we could not contact the remote device */
     public static final int UNBOND_REASON_REMOTE_DEVICE_DOWN = 4;
-    /** A bond attempt failed because a discovery is in progress */
-    public static final int UNBOND_REASON_DISCOVERY_IN_PROGRESS = 5;
     /** An existing bond was explicitly revoked */
-    public static final int UNBOND_REASON_REMOVED = 6;
+    public static final int UNBOND_REASON_REMOVED = 5;
 
     private static final String TAG = "BluetoothDevice";
     
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java
index 25544deac10d1..3a64ceebc4fc6 100644
--- a/core/java/android/content/ContentProvider.java
+++ b/core/java/android/content/ContentProvider.java
@@ -18,7 +18,6 @@ package android.content;
 
 import android.content.pm.PackageManager;
 import android.content.pm.ProviderInfo;
-import android.content.res.AssetFileDescriptor;
 import android.content.res.Configuration;
 import android.database.Cursor;
 import android.database.CursorToBulkCursorAdaptor;
@@ -163,13 +162,6 @@ public abstract class ContentProvider implements ComponentCallbacks {
             return ContentProvider.this.openFile(uri, mode);
         }
 
-        public AssetFileDescriptor openAssetFile(Uri uri, String mode)
-                throws FileNotFoundException {
-            if (mode != null && mode.startsWith("rw")) checkWritePermission(uri);
-            else checkReadPermission(uri);
-            return ContentProvider.this.openAssetFile(uri, mode);
-        }
-
         public ISyncAdapter getSyncAdapter() {
             checkWritePermission(null);
             return ContentProvider.this.getSyncAdapter().getISyncAdapter();
@@ -446,9 +438,8 @@ public abstract class ContentProvider implements ComponentCallbacks {
      * of this method should create a new ParcelFileDescriptor for each call.
      *
      * @param uri The URI whose file is to be opened.
-     * @param mode Access mode for the file.  May be "r" for read-only access,
-     * "rw" for read and write access, or "rwt" for read and write access
-     * that truncates any existing file.
+     * @param mode Access mode for the file.  May be "r" for read-only access
+     * or "rw" for read and write access.
      *
      * @return Returns a new ParcelFileDescriptor which you can use to access
      * the file.
@@ -457,66 +448,19 @@ public abstract class ContentProvider implements ComponentCallbacks {
      * no file associated with the given URI or the mode is invalid.
      * @throws SecurityException Throws SecurityException if the caller does
      * not have permission to access the file.
-     * 
-     * @see #openAssetFile(Uri, String)
-     * @see #openFileHelper(Uri, String)
-     */    
+     */
     public ParcelFileDescriptor openFile(Uri uri, String mode)
             throws FileNotFoundException {
         throw new FileNotFoundException("No files supported by provider at "
                 + uri);
     }
-    
-    /**
-     * This is like {@link #openFile}, but can be implemented by providers
-     * that need to be able to return sub-sections of files, often assets
-     * inside of their .apk.  Note that when implementing this your clients
-     * must be able to deal with such files, either directly with
-     * {@link ContentResolver#openAssetFileDescriptor
-     * ContentResolver.openAssetFileDescriptor}, or by using the higher-level
-     * {@link ContentResolver#openInputStream ContentResolver.openInputStream}
-     * or {@link ContentResolver#openOutputStream ContentResolver.openOutputStream}
-     * methods.
-     * 
-     * 

Note: if you are implementing this to return a full file, you - * should create the AssetFileDescriptor with - * {@link AssetFileDescriptor#UNKNOWN_LENGTH} to be compatible with - * applications that can not handle sub-sections of files.

- * - * @param uri The URI whose file is to be opened. - * @param mode Access mode for the file. May be "r" for read-only access, - * "w" for write-only access (erasing whatever data is currently in - * the file), "wa" for write-only access to append to any existing data, - * "rw" for read and write access on any existing data, and "rwt" for read - * and write access that truncates any existing file. - * - * @return Returns a new AssetFileDescriptor which you can use to access - * the file. - * - * @throws FileNotFoundException Throws FileNotFoundException if there is - * no file associated with the given URI or the mode is invalid. - * @throws SecurityException Throws SecurityException if the caller does - * not have permission to access the file. - * - * @see #openFile(Uri, String) - * @see #openFileHelper(Uri, String) - */ - public AssetFileDescriptor openAssetFile(Uri uri, String mode) - throws FileNotFoundException { - ParcelFileDescriptor fd = openFile(uri, mode); - return fd != null ? new AssetFileDescriptor(fd, 0, -1) : null; - } /** * Convenience for subclasses that wish to implement {@link #openFile} * by looking up a column named "_data" at the given URI. * * @param uri The URI to be opened. - * @param mode The file mode. May be "r" for read-only access, - * "w" for write-only access (erasing whatever data is currently in - * the file), "wa" for write-only access to append to any existing data, - * "rw" for read and write access on any existing data, and "rwt" for read - * and write access that truncates any existing file. + * @param mode The file mode. * * @return Returns a new ParcelFileDescriptor that can be used by the * client to access the file. @@ -545,7 +489,16 @@ public abstract class ContentProvider implements ComponentCallbacks { throw new FileNotFoundException("Column _data not found."); } - int modeBits = ContentResolver.modeToMode(uri, mode); + int modeBits; + if ("r".equals(mode)) { + modeBits = ParcelFileDescriptor.MODE_READ_ONLY; + } else if ("rw".equals(mode)) { + modeBits = ParcelFileDescriptor.MODE_READ_WRITE + | ParcelFileDescriptor.MODE_CREATE; + } else { + throw new FileNotFoundException("Bad mode for " + uri + ": " + + mode); + } return ParcelFileDescriptor.open(new File(path), modeBits); } diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index e5e3f749a8d75..ede2c9bee6e99 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -16,7 +16,6 @@ package android.content; -import android.content.res.AssetFileDescriptor; import android.database.BulkCursorNative; import android.database.BulkCursorToCursorAdaptor; import android.database.Cursor; @@ -188,25 +187,6 @@ abstract public class ContentProviderNative extends Binder implements IContentPr return true; } - case OPEN_ASSET_FILE_TRANSACTION: - { - data.enforceInterface(IContentProvider.descriptor); - Uri url = Uri.CREATOR.createFromParcel(data); - String mode = data.readString(); - - AssetFileDescriptor fd; - fd = openAssetFile(url, mode); - reply.writeNoException(); - if (fd != null) { - reply.writeInt(1); - fd.writeToParcel(reply, - Parcelable.PARCELABLE_WRITE_RETURN_VALUE); - } else { - reply.writeInt(0); - } - return true; - } - case GET_SYNC_ADAPTER_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); @@ -433,29 +413,6 @@ final class ContentProviderProxy implements IContentProvider return fd; } - public AssetFileDescriptor openAssetFile(Uri url, String mode) - throws RemoteException, FileNotFoundException { - Parcel data = Parcel.obtain(); - Parcel reply = Parcel.obtain(); - - data.writeInterfaceToken(IContentProvider.descriptor); - - url.writeToParcel(data, 0); - data.writeString(mode); - - mRemote.transact(IContentProvider.OPEN_ASSET_FILE_TRANSACTION, data, reply, 0); - - DatabaseUtils.readExceptionWithFileNotFoundExceptionFromParcel(reply); - int has = reply.readInt(); - AssetFileDescriptor fd = has != 0 - ? AssetFileDescriptor.CREATOR.createFromParcel(reply) : null; - - data.recycle(); - reply.recycle(); - - return fd; - } - public ISyncAdapter getSyncAdapter() throws RemoteException { Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 0d886ee23e8d1..52f55b633727e 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -17,7 +17,6 @@ package android.content; import android.content.pm.PackageManager.NameNotFoundException; -import android.content.res.AssetFileDescriptor; import android.content.res.Resources; import android.database.ContentObserver; import android.database.Cursor; @@ -29,7 +28,6 @@ import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.text.TextUtils; -import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; @@ -172,143 +170,6 @@ public abstract class ContentResolver { *
  • android.resource ({@link #SCHEME_ANDROID_RESOURCE})
  • *
  • file ({@link #SCHEME_FILE})
  • * - * - *

    See {@link #openAssetFileDescriptor(Uri, String)} for more information - * on these schemes. - * - * @param uri The desired URI. - * @return InputStream - * @throws FileNotFoundException if the provided URI could not be opened. - * @see #openAssetFileDescriptor(Uri, String) - */ - public final InputStream openInputStream(Uri uri) - throws FileNotFoundException { - String scheme = uri.getScheme(); - if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { - // Note: left here to avoid breaking compatibility. May be removed - // with sufficient testing. - OpenResourceIdResult r = getResourceId(uri); - try { - InputStream stream = r.r.openRawResource(r.id); - return stream; - } catch (Resources.NotFoundException ex) { - throw new FileNotFoundException("Resource does not exist: " + uri); - } - } else if (SCHEME_FILE.equals(scheme)) { - // Note: left here to avoid breaking compatibility. May be removed - // with sufficient testing. - return new FileInputStream(uri.getPath()); - } else { - AssetFileDescriptor fd = openAssetFileDescriptor(uri, "r"); - try { - return fd != null ? fd.createInputStream() : null; - } catch (IOException e) { - throw new FileNotFoundException("Unable to create stream"); - } - } - } - - /** - * Synonym for {@link #openOutputStream(Uri, String) - * openOutputStream(uri, "w")}. - * @throws FileNotFoundException if the provided URI could not be opened. - */ - public final OutputStream openOutputStream(Uri uri) - throws FileNotFoundException { - return openOutputStream(uri, "w"); - } - - /** - * Open a stream on to the content associated with a content URI. If there - * is no data associated with the URI, FileNotFoundException is thrown. - * - *

    Accepts the following URI schemes:
    - *
      - *
    • content ({@link #SCHEME_CONTENT})
    • - *
    • file ({@link #SCHEME_FILE})
    • - *
    - * - *

    See {@link #openAssetFileDescriptor(Uri, String)} for more information - * on these schemes. - * - * @param uri The desired URI. - * @param mode May be "w", "wa", "rw", or "rwt". - * @return OutputStream - * @throws FileNotFoundException if the provided URI could not be opened. - * @see #openAssetFileDescriptor(Uri, String) - */ - public final OutputStream openOutputStream(Uri uri, String mode) - throws FileNotFoundException { - AssetFileDescriptor fd = openAssetFileDescriptor(uri, mode); - try { - return fd != null ? fd.createOutputStream() : null; - } catch (IOException e) { - throw new FileNotFoundException("Unable to create stream"); - } - } - - /** - * Open a raw file descriptor to access data under a "content:" URI. This - * is like {@link #openAssetFileDescriptor(Uri, String)}, but uses the - * underlying {@link ContentProvider#openFile} - * ContentProvider.openFile()} method, so will not work with - * providers that return sub-sections of files. If at all possible, - * you should use {@link #openAssetFileDescriptor(Uri, String)}. You - * will receive a FileNotFoundException exception if the provider returns a - * sub-section of a file. - * - *

    Accepts the following URI schemes:
    - *
      - *
    • content ({@link #SCHEME_CONTENT})
    • - *
    • file ({@link #SCHEME_FILE})
    • - *
    - * - *

    See {@link #openAssetFileDescriptor(Uri, String)} for more information - * on these schemes. - * - * @param uri The desired URI to open. - * @param mode The file mode to use, as per {@link ContentProvider#openFile - * ContentProvider.openFile}. - * @return Returns a new ParcelFileDescriptor pointing to the file. You - * own this descriptor and are responsible for closing it when done. - * @throws FileNotFoundException Throws FileNotFoundException of no - * file exists under the URI or the mode is invalid. - * @see #openAssetFileDescriptor(Uri, String) - */ - public final ParcelFileDescriptor openFileDescriptor(Uri uri, - String mode) throws FileNotFoundException { - AssetFileDescriptor afd = openAssetFileDescriptor(uri, mode); - if (afd == null) { - return null; - } - - if (afd.getDeclaredLength() < 0) { - // This is a full file! - return afd.getParcelFileDescriptor(); - } - - // Client can't handle a sub-section of a file, so close what - // we got and bail with an exception. - try { - afd.close(); - } catch (IOException e) { - } - - throw new FileNotFoundException("Not a whole file"); - } - - /** - * Open a raw file descriptor to access data under a "content:" URI. This - * interacts with the underlying {@link ContentProvider#openAssetFile} - * ContentProvider.openAssetFile()} method of the provider associated with the - * given URI, to retrieve any file stored there. - * - *

    Accepts the following URI schemes:
    - *
      - *
    • content ({@link #SCHEME_CONTENT})
    • - *
    • android.resource ({@link #SCHEME_ANDROID_RESOURCE})
    • - *
    • file ({@link #SCHEME_FILE})
    • - *
    *
    The android.resource ({@link #SCHEME_ANDROID_RESOURCE}) Scheme
    *

    * A Uri object can be used to reference a resource in an APK file. The @@ -332,130 +193,129 @@ public abstract class ContentResolver { *

    Uri uri = Uri.parse("android.resource://com.example.myapp/raw/my_resource");
    * * + * @param uri The desired "content:" URI. + * @return InputStream + * @throws FileNotFoundException if the provided URI could not be opened. + */ + public final InputStream openInputStream(Uri uri) + throws FileNotFoundException { + String scheme = uri.getScheme(); + if (SCHEME_CONTENT.equals(scheme)) { + ParcelFileDescriptor fd = openFileDescriptor(uri, "r"); + return fd != null ? new ParcelFileDescriptor.AutoCloseInputStream(fd) : null; + } else if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { + String authority = uri.getAuthority(); + Resources r; + if (TextUtils.isEmpty(authority)) { + throw new FileNotFoundException("No authority: " + uri); + } else { + try { + r = mContext.getPackageManager().getResourcesForApplication(authority); + } catch (NameNotFoundException ex) { + throw new FileNotFoundException("No package found for authority: " + uri); + } + } + List path = uri.getPathSegments(); + if (path == null) { + throw new FileNotFoundException("No path: " + uri); + } + int len = path.size(); + int id; + if (len == 1) { + try { + id = Integer.parseInt(path.get(0)); + } catch (NumberFormatException e) { + throw new FileNotFoundException("Single path segment is not a resource ID: " + uri); + } + } else if (len == 2) { + id = r.getIdentifier(path.get(1), path.get(0), authority); + } else { + throw new FileNotFoundException("More than two path segments: " + uri); + } + if (id == 0) { + throw new FileNotFoundException("No resource found for: " + uri); + } + try { + InputStream stream = r.openRawResource(id); + return stream; + } catch (Resources.NotFoundException ex) { + throw new FileNotFoundException("Resource ID does not exist: " + uri); + } + } else if (SCHEME_FILE.equals(scheme)) { + return new FileInputStream(uri.getPath()); + } else { + throw new FileNotFoundException("Unknown scheme: " + uri); + } + } + + /** + * Open a stream on to the content associated with a content URI. If there + * is no data associated with the URI, FileNotFoundException is thrown. + * + *
    Accepts the following URI schemes:
    + *
      + *
    • content ({@link #SCHEME_CONTENT})
    • + *
    + * + * @param uri The desired "content:" URI. + * @return OutputStream + */ + public final OutputStream openOutputStream(Uri uri) + throws FileNotFoundException { + String scheme = uri.getScheme(); + if (SCHEME_CONTENT.equals(scheme)) { + ParcelFileDescriptor fd = openFileDescriptor(uri, "rw"); + return fd != null + ? new ParcelFileDescriptor.AutoCloseOutputStream(fd) : null; + } else { + throw new FileNotFoundException("Unknown scheme: " + uri); + } + } + + /** + * Open a raw file descriptor to access data under a "content:" URI. This + * interacts with the underlying {@link ContentProvider#openFile} + * ContentProvider.openFile()} method of the provider associated with the + * given URI, to retrieve any file stored there. + * + *
    Accepts the following URI schemes:
    + *
      + *
    • content ({@link #SCHEME_CONTENT})
    • + *
    * * @param uri The desired URI to open. - * @param mode The file mode to use, as per {@link ContentProvider#openAssetFile - * ContentProvider.openAssetFile}. + * @param mode The file mode to use, as per {@link ContentProvider#openFile + * ContentProvider.openFile}. * @return Returns a new ParcelFileDescriptor pointing to the file. You * own this descriptor and are responsible for closing it when done. * @throws FileNotFoundException Throws FileNotFoundException of no * file exists under the URI or the mode is invalid. */ - public final AssetFileDescriptor openAssetFileDescriptor(Uri uri, + public final ParcelFileDescriptor openFileDescriptor(Uri uri, String mode) throws FileNotFoundException { - String scheme = uri.getScheme(); - if (SCHEME_ANDROID_RESOURCE.equals(scheme)) { - if (!"r".equals(mode)) { - throw new FileNotFoundException("Can't write resources: " + uri); - } - OpenResourceIdResult r = getResourceId(uri); - try { - return r.r.openRawResourceFd(r.id); - } catch (Resources.NotFoundException ex) { - throw new FileNotFoundException("Resource does not exist: " + uri); - } - } else if (SCHEME_FILE.equals(scheme)) { - ParcelFileDescriptor pfd = ParcelFileDescriptor.open( - new File(uri.getPath()), modeToMode(uri, mode)); - return new AssetFileDescriptor(pfd, 0, -1); - } else { - IContentProvider provider = acquireProvider(uri); - if (provider == null) { - throw new FileNotFoundException("No content provider: " + uri); - } - try { - AssetFileDescriptor fd = provider.openAssetFile(uri, mode); - if(fd == null) { - releaseProvider(provider); - return null; - } - ParcelFileDescriptor pfd = new ParcelFileDescriptorInner( - fd.getParcelFileDescriptor(), provider); - return new AssetFileDescriptor(pfd, fd.getStartOffset(), - fd.getDeclaredLength()); - } catch (RemoteException e) { + IContentProvider provider = acquireProvider(uri); + if (provider == null) { + throw new FileNotFoundException("No content provider: " + uri); + } + try { + ParcelFileDescriptor fd = provider.openFile(uri, mode); + if(fd == null) { releaseProvider(provider); - throw new FileNotFoundException("Dead content provider: " + uri); - } catch (FileNotFoundException e) { - releaseProvider(provider); - throw e; - } catch (RuntimeException e) { - releaseProvider(provider); - throw e; + return null; } + return new ParcelFileDescriptorInner(fd, provider); + } catch (RemoteException e) { + releaseProvider(provider); + throw new FileNotFoundException("Dead content provider: " + uri); + } catch (FileNotFoundException e) { + releaseProvider(provider); + throw e; + } catch (RuntimeException e) { + releaseProvider(provider); + throw e; } } - class OpenResourceIdResult { - Resources r; - int id; - } - - OpenResourceIdResult getResourceId(Uri uri) throws FileNotFoundException { - String authority = uri.getAuthority(); - Resources r; - if (TextUtils.isEmpty(authority)) { - throw new FileNotFoundException("No authority: " + uri); - } else { - try { - r = mContext.getPackageManager().getResourcesForApplication(authority); - } catch (NameNotFoundException ex) { - throw new FileNotFoundException("No package found for authority: " + uri); - } - } - List path = uri.getPathSegments(); - if (path == null) { - throw new FileNotFoundException("No path: " + uri); - } - int len = path.size(); - int id; - if (len == 1) { - try { - id = Integer.parseInt(path.get(0)); - } catch (NumberFormatException e) { - throw new FileNotFoundException("Single path segment is not a resource ID: " + uri); - } - } else if (len == 2) { - id = r.getIdentifier(path.get(1), path.get(0), authority); - } else { - throw new FileNotFoundException("More than two path segments: " + uri); - } - if (id == 0) { - throw new FileNotFoundException("No resource found for: " + uri); - } - OpenResourceIdResult res = new OpenResourceIdResult(); - res.r = r; - res.id = id; - return res; - } - - /** @hide */ - static public int modeToMode(Uri uri, String mode) throws FileNotFoundException { - int modeBits; - if ("r".equals(mode)) { - modeBits = ParcelFileDescriptor.MODE_READ_ONLY; - } else if ("w".equals(mode) || "wt".equals(mode)) { - modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY - | ParcelFileDescriptor.MODE_CREATE - | ParcelFileDescriptor.MODE_TRUNCATE; - } else if ("wa".equals(mode)) { - modeBits = ParcelFileDescriptor.MODE_WRITE_ONLY - | ParcelFileDescriptor.MODE_CREATE - | ParcelFileDescriptor.MODE_APPEND; - } else if ("rw".equals(mode)) { - modeBits = ParcelFileDescriptor.MODE_READ_WRITE - | ParcelFileDescriptor.MODE_CREATE; - } else if ("rwt".equals(mode)) { - modeBits = ParcelFileDescriptor.MODE_READ_WRITE - | ParcelFileDescriptor.MODE_CREATE - | ParcelFileDescriptor.MODE_TRUNCATE; - } else { - throw new FileNotFoundException("Bad mode for " + uri + ": " - + mode); - } - return modeBits; - } - /** * Inserts a row into a table at the given URL. * diff --git a/core/java/android/content/ContentServiceNative.java b/core/java/android/content/ContentServiceNative.java index 364f9ee8a29d4..f05050190d670 100644 --- a/core/java/android/content/ContentServiceNative.java +++ b/core/java/android/content/ContentServiceNative.java @@ -75,13 +75,6 @@ abstract class ContentServiceNative extends Binder implements IContentService { try { switch (code) { - case 5038: { - data.readString(); // ignore the interface token that service generated - Uri uri = Uri.parse(data.readString()); - notifyChange(uri, null, false, false); - return true; - } - case REGISTER_CONTENT_OBSERVER_TRANSACTION: { Uri uri = Uri.CREATOR.createFromParcel(data); boolean notifyForDescendents = data.readInt() != 0; diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java index 06069569db974..a6ef46f420512 100644 --- a/core/java/android/content/IContentProvider.java +++ b/core/java/android/content/IContentProvider.java @@ -16,7 +16,6 @@ package android.content; -import android.content.res.AssetFileDescriptor; import android.database.Cursor; import android.database.CursorWindow; import android.database.IBulkCursor; @@ -53,8 +52,6 @@ public interface IContentProvider extends IInterface { String[] selectionArgs) throws RemoteException; public ParcelFileDescriptor openFile(Uri url, String mode) throws RemoteException, FileNotFoundException; - public AssetFileDescriptor openAssetFile(Uri url, String mode) - throws RemoteException, FileNotFoundException; public ISyncAdapter getSyncAdapter() throws RemoteException; /* IPC constants */ @@ -68,5 +65,4 @@ public interface IContentProvider extends IInterface { static final int GET_SYNC_ADAPTER_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 10; static final int BULK_INSERT_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 12; static final int OPEN_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 13; - static final int OPEN_ASSET_FILE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 14; } diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java index e1c1f648bf734..c1c3b499b0082 100644 --- a/core/java/android/content/Intent.java +++ b/core/java/android/content/Intent.java @@ -522,7 +522,6 @@ import java.util.Set; *
  • {@link #CATEGORY_ALTERNATIVE} *
  • {@link #CATEGORY_SELECTED_ALTERNATIVE} *
  • {@link #CATEGORY_LAUNCHER} - *
  • {@link #CATEGORY_INFO} *
  • {@link #CATEGORY_HOME} *
  • {@link #CATEGORY_PREFERENCE} *
  • {@link #CATEGORY_GADGET} @@ -1546,13 +1545,6 @@ public class Intent implements Parcelable { */ @SdkConstant(SdkConstantType.INTENT_CATEGORY) public static final String CATEGORY_LAUNCHER = "android.intent.category.LAUNCHER"; - /** - * Provides information about the package it is in; typically used if - * a package does not contain a {@link #CATEGORY_LAUNCHER} to provide - * a front-door to the user without having to be shown in the all apps list. - */ - @SdkConstant(SdkConstantType.INTENT_CATEGORY) - public static final String CATEGORY_INFO = "android.intent.category.INFO"; /** * This is the home activity, that is the first activity that is displayed * when the device boots. diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 7287d9cd58e93..698f27fc0a3fc 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -479,26 +479,6 @@ public abstract class PackageManager { public abstract PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException; - /** - * Return a "good" intent to launch a front-door activity in a package, - * for use for example to implement an "open" button when browsing through - * packages. The current implementation will look first for a main - * activity in the category {@link Intent#CATEGORY_INFO}, next for a - * main activity in the category {@link Intent#CATEGORY_LAUNCHER}, or return - * null if neither are found. - * - *

    Throws {@link NameNotFoundException} if a package with the given - * name can not be found on the system. - * - * @param packageName The name of the package to inspect. - * - * @return Returns either a fully-qualified Intent that can be used to - * launch the main activity in the package, or null if the package does - * not contain such an activity. - */ - public abstract Intent getLaunchIntentForPackage(String packageName) - throws NameNotFoundException; - /** * Return an array of all of the secondary group-ids that have been * assigned to a package. diff --git a/core/java/android/content/res/AssetFileDescriptor.java b/core/java/android/content/res/AssetFileDescriptor.java index 231e3e24a27c8..4a073f7566421 100644 --- a/core/java/android/content/res/AssetFileDescriptor.java +++ b/core/java/android/content/res/AssetFileDescriptor.java @@ -16,13 +16,9 @@ package android.content.res; -import android.os.Parcel; import android.os.ParcelFileDescriptor; -import android.os.Parcelable; import java.io.FileDescriptor; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; /** @@ -30,32 +26,16 @@ import java.io.IOException; * opened FileDescriptor that can be used to read the data, as well as the * offset and length of that entry's data in the file. */ -public class AssetFileDescriptor implements Parcelable { - /** - * Length used with {@link #AssetFileDescriptor(ParcelFileDescriptor, long, long)} - * and {@link #getDeclaredLength} when a length has not been declared. This means - * the data extends to the end of the file. - */ - public static final long UNKNOWN_LENGTH = -1; - +public class AssetFileDescriptor { private final ParcelFileDescriptor mFd; private final long mStartOffset; private final long mLength; /** * Create a new AssetFileDescriptor from the given values. - * @param fd The underlying file descriptor. - * @param startOffset The location within the file that the asset starts. - * This must be 0 if length is UNKNOWN_LENGTH. - * @param length The number of bytes of the asset, or - * {@link #UNKNOWN_LENGTH if it extends to the end of the file. */ public AssetFileDescriptor(ParcelFileDescriptor fd, long startOffset, long length) { - if (length < 0 && startOffset != 0) { - throw new IllegalArgumentException( - "startOffset must be 0 when using UNKNOWN_LENGTH"); - } mFd = fd; mStartOffset = startOffset; mLength = length; @@ -86,33 +66,9 @@ public class AssetFileDescriptor implements Parcelable { } /** - * Returns the total number of bytes of this asset entry's data. May be - * {@link #UNKNOWN_LENGTH} if the asset extends to the end of the file. - * If the AssetFileDescriptor was constructed with {@link #UNKNOWN_LENGTH}, - * this will use {@link ParcelFileDescriptor#getStatSize() - * ParcelFileDescriptor.getStatSize()} to find the total size of the file, - * returning that number if found or {@link #UNKNOWN_LENGTH} if it could - * not be determined. - * - * @see #getDeclaredLength() + * Returns the total number of bytes of this asset entry's data. */ public long getLength() { - if (mLength >= 0) { - return mLength; - } - long len = mFd.getStatSize(); - return len >= 0 ? len : UNKNOWN_LENGTH; - } - - /** - * Return the actual number of bytes that were declared when the - * AssetFileDescriptor was constructed. Will be - * {@link #UNKNOWN_LENGTH} if the length was not declared, meaning data - * should be read to the end of the file. - * - * @see #getDeclaredLength() - */ - public long getDeclaredLength() { return mLength; } @@ -122,227 +78,4 @@ public class AssetFileDescriptor implements Parcelable { public void close() throws IOException { mFd.close(); } - - /** - * Create and return a new auto-close input stream for this asset. This - * will either return a full asset {@link AutoCloseInputStream}, or - * an underlying {@link ParcelFileDescriptor.AutoCloseInputStream - * ParcelFileDescriptor.AutoCloseInputStream} depending on whether the - * the object represents a complete file or sub-section of a file. You - * should only call this once for a particular asset. - */ - public FileInputStream createInputStream() throws IOException { - if (mLength < 0) { - return new ParcelFileDescriptor.AutoCloseInputStream(mFd); - } - return new AutoCloseInputStream(this); - } - - /** - * Create and return a new auto-close output stream for this asset. This - * will either return a full asset {@link AutoCloseOutputStream}, or - * an underlying {@link ParcelFileDescriptor.AutoCloseOutputStream - * ParcelFileDescriptor.AutoCloseOutputStream} depending on whether the - * the object represents a complete file or sub-section of a file. You - * should only call this once for a particular asset. - */ - public FileOutputStream createOutputStream() throws IOException { - if (mLength < 0) { - return new ParcelFileDescriptor.AutoCloseOutputStream(mFd); - } - return new AutoCloseOutputStream(this); - } - - @Override - public String toString() { - return "{AssetFileDescriptor: " + mFd - + " start=" + mStartOffset + " len=" + mLength + "}"; - } - - /** - * An InputStream you can create on a ParcelFileDescriptor, which will - * take care of calling {@link ParcelFileDescriptor#close - * ParcelFileDescritor.close()} for you when the stream is closed. - */ - public static class AutoCloseInputStream - extends ParcelFileDescriptor.AutoCloseInputStream { - private long mRemaining; - - public AutoCloseInputStream(AssetFileDescriptor fd) throws IOException { - super(fd.getParcelFileDescriptor()); - super.skip(fd.getStartOffset()); - mRemaining = (int)fd.getLength(); - } - - @Override - public int available() throws IOException { - return mRemaining >= 0 - ? (mRemaining < 0x7fffffff ? (int)mRemaining : 0x7fffffff) - : super.available(); - } - - @Override - public int read() throws IOException { - if (mRemaining >= 0) { - if (mRemaining == 0) return -1; - int res = super.read(); - if (res >= 0) mRemaining--; - return res; - } - - return super.read(); - } - - @Override - public int read(byte[] buffer, int offset, int count) throws IOException { - if (mRemaining >= 0) { - if (mRemaining == 0) return -1; - if (count > mRemaining) count = (int)mRemaining; - int res = super.read(buffer, offset, count); - if (res >= 0) mRemaining -= res; - return res; - } - - return super.read(buffer, offset, count); - } - - @Override - public int read(byte[] buffer) throws IOException { - if (mRemaining >= 0) { - if (mRemaining == 0) return -1; - int count = buffer.length; - if (count > mRemaining) count = (int)mRemaining; - int res = super.read(buffer, 0, count); - if (res >= 0) mRemaining -= res; - return res; - } - - return super.read(buffer); - } - - @Override - public long skip(long count) throws IOException { - if (mRemaining >= 0) { - if (mRemaining == 0) return -1; - if (count > mRemaining) count = mRemaining; - long res = super.skip(count); - if (res >= 0) mRemaining -= res; - return res; - } - - // TODO Auto-generated method stub - return super.skip(count); - } - - @Override - public void mark(int readlimit) { - if (mRemaining >= 0) { - // Not supported. - return; - } - super.mark(readlimit); - } - - @Override - public boolean markSupported() { - if (mRemaining >= 0) { - return false; - } - return super.markSupported(); - } - - @Override - public synchronized void reset() throws IOException { - if (mRemaining >= 0) { - // Not supported. - return; - } - super.reset(); - } - } - - /** - * An OutputStream you can create on a ParcelFileDescriptor, which will - * take care of calling {@link ParcelFileDescriptor#close - * ParcelFileDescritor.close()} for you when the stream is closed. - */ - public static class AutoCloseOutputStream - extends ParcelFileDescriptor.AutoCloseOutputStream { - private long mRemaining; - - public AutoCloseOutputStream(AssetFileDescriptor fd) throws IOException { - super(fd.getParcelFileDescriptor()); - if (fd.getParcelFileDescriptor().seekTo(fd.getStartOffset()) < 0) { - throw new IOException("Unable to seek"); - } - mRemaining = (int)fd.getLength(); - } - - @Override - public void write(byte[] buffer, int offset, int count) throws IOException { - if (mRemaining >= 0) { - if (mRemaining == 0) return; - if (count > mRemaining) count = (int)mRemaining; - super.write(buffer, offset, count); - mRemaining -= count; - return; - } - - super.write(buffer, offset, count); - } - - @Override - public void write(byte[] buffer) throws IOException { - if (mRemaining >= 0) { - if (mRemaining == 0) return; - int count = buffer.length; - if (count > mRemaining) count = (int)mRemaining; - super.write(buffer); - mRemaining -= count; - return; - } - - super.write(buffer); - } - - @Override - public void write(int oneByte) throws IOException { - if (mRemaining >= 0) { - if (mRemaining == 0) return; - super.write(oneByte); - mRemaining--; - return; - } - - super.write(oneByte); - } - } - - - /* Parcelable interface */ - public int describeContents() { - return mFd.describeContents(); - } - - public void writeToParcel(Parcel out, int flags) { - mFd.writeToParcel(out, flags); - out.writeLong(mStartOffset); - out.writeLong(mLength); - } - - AssetFileDescriptor(Parcel src) { - mFd = ParcelFileDescriptor.CREATOR.createFromParcel(src); - mStartOffset = src.readLong(); - mLength = src.readLong(); - } - - public static final Parcelable.Creator CREATOR - = new Parcelable.Creator() { - public AssetFileDescriptor createFromParcel(Parcel in) { - return new AssetFileDescriptor(in); - } - public AssetFileDescriptor[] newArray(int size) { - return new AssetFileDescriptor[size]; - } - }; } diff --git a/core/java/android/content/res/ColorStateList.java b/core/java/android/content/res/ColorStateList.java index 0f3f2708c6017..17cb68745d8be 100644 --- a/core/java/android/content/res/ColorStateList.java +++ b/core/java/android/content/res/ColorStateList.java @@ -16,6 +16,8 @@ package android.content.res; +import com.google.android.collect.Lists; + import com.android.internal.util.ArrayUtils; import org.xmlpull.v1.XmlPullParser; @@ -111,8 +113,7 @@ public class ColorStateList implements Parcelable { * Create a ColorStateList from an XML document, given a set of {@link Resources}. */ public static ColorStateList createFromXml(Resources r, XmlPullParser parser) - throws XmlPullParserException, IOException { - + throws XmlPullParserException, IOException { AttributeSet attrs = Xml.asAttributeSet(parser); int type; @@ -124,16 +125,19 @@ public class ColorStateList implements Parcelable { throw new XmlPullParserException("No start tag found"); } - return createFromXmlInner(r, parser, attrs); + final ColorStateList colorStateList = createFromXmlInner(r, parser, attrs); + + return colorStateList; } /* Create from inside an XML document. Called on a parser positioned at * a tag in an XML document, tries to create a ColorStateList from that tag. * Returns null if the tag is not a valid ColorStateList. */ - private static ColorStateList createFromXmlInner(Resources r, XmlPullParser parser, - AttributeSet attrs) throws XmlPullParserException, IOException { - + private static ColorStateList createFromXmlInner(Resources r, + XmlPullParser parser, + AttributeSet attrs) + throws XmlPullParserException, IOException { ColorStateList colorStateList; final String name = parser.getName(); @@ -142,7 +146,8 @@ public class ColorStateList implements Parcelable { colorStateList = new ColorStateList(); } else { throw new XmlPullParserException( - parser.getPositionDescription() + ": invalid drawable tag " + name); + parser.getPositionDescription() + ": invalid drawable tag " + + name); } colorStateList.inflate(r, parser, attrs); diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java index 1a963f6390b06..5a0daeaeac98d 100644 --- a/core/java/android/content/res/Resources.java +++ b/core/java/android/content/res/Resources.java @@ -46,7 +46,6 @@ public class Resources { static final String TAG = "Resources"; private static final boolean DEBUG_LOAD = false; private static final boolean DEBUG_CONFIG = false; - private static final boolean TRACE_FOR_PRELOAD = false; private static final int sSdkVersion = SystemProperties.getInt( "ro.build.version.sdk", 0); @@ -58,8 +57,6 @@ public class Resources { // single-threaded, and after that these are immutable. private static final SparseArray mPreloadedDrawables = new SparseArray(); - private static final SparseArray mPreloadedColorStateLists - = new SparseArray(); private static boolean mPreloaded; /*package*/ final TypedValue mTmpValue = new TypedValue(); @@ -81,7 +78,7 @@ public class Resources { private final Configuration mConfiguration = new Configuration(); /*package*/ final DisplayMetrics mMetrics = new DisplayMetrics(); PluralRules mPluralRule; - + /** * This exception is thrown by the resource APIs when a requested resource * can not be found. @@ -93,7 +90,7 @@ public class Resources { public NotFoundException(String name) { super(name); } - } + }; /** * Create a new Resources object on top of an existing set of assets in an @@ -1232,9 +1229,7 @@ public class Resources { width = mMetrics.widthPixels; height = mMetrics.heightPixels; } else { - //noinspection SuspiciousNameCombination width = mMetrics.heightPixels; - //noinspection SuspiciousNameCombination height = mMetrics.widthPixels; } int keyboardHidden = mConfiguration.keyboardHidden; @@ -1347,7 +1342,6 @@ public class Resources { try { return Integer.parseInt(name); } catch (Exception e) { - // Ignore } return mAssets.getResourceIdentifier(name, defType, defPackage); } @@ -1581,18 +1575,21 @@ public class Resources { /*package*/ Drawable loadDrawable(TypedValue value, int id) throws NotFoundException { - - if (TRACE_FOR_PRELOAD) { - // Log only framework resources - if ((id >>> 24) == 0x1) { - final String name = getResourceName(id); - if (name != null) android.util.Log.d("PreloadDrawable", name); - } + if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT + && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { + // Should we be caching these? If we use constant colors much + // at all, most likely... + //System.out.println("Creating drawable for color: #" + + // Integer.toHexString(value.data)); + Drawable dr = new ColorDrawable(value.data); + dr.setChangingConfigurations(value.changingConfigurations); + return dr; } - final int key = (value.assetCookie << 24) | value.data; + final int key = (value.assetCookie<<24)|value.data; Drawable dr = getCachedDrawable(key); - + //System.out.println("Cached drawable @ #" + + // Integer.toHexString(key.intValue()) + ": " + dr); if (dr != null) { return dr; } @@ -1600,52 +1597,46 @@ public class Resources { Drawable.ConstantState cs = mPreloadedDrawables.get(key); if (cs != null) { dr = cs.newDrawable(); + } else { - if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT && - value.type <= TypedValue.TYPE_LAST_COLOR_INT) { - dr = new ColorDrawable(value.data); + if (value.string == null) { + throw new NotFoundException( + "Resource is not a Drawable (color or path): " + value); } - - if (dr == null) { - if (value.string == null) { - throw new NotFoundException( - "Resource is not a Drawable (color or path): " + value); + + String file = value.string.toString(); + + if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie " + + value.assetCookie + ": " + file); + + if (file.endsWith(".xml")) { + try { + XmlResourceParser rp = loadXmlResourceParser( + file, id, value.assetCookie, "drawable"); + dr = Drawable.createFromXml(this, rp); + rp.close(); + } catch (Exception e) { + NotFoundException rnf = new NotFoundException( + "File " + file + " from drawable resource ID #0x" + + Integer.toHexString(id)); + rnf.initCause(e); + throw rnf; } - - String file = value.string.toString(); - - if (DEBUG_LOAD) Log.v(TAG, "Loading drawable for cookie " - + value.assetCookie + ": " + file); - - if (file.endsWith(".xml")) { - try { - XmlResourceParser rp = loadXmlResourceParser( - file, id, value.assetCookie, "drawable"); - dr = Drawable.createFromXml(this, rp); - rp.close(); - } catch (Exception e) { - NotFoundException rnf = new NotFoundException( - "File " + file + " from drawable resource ID #0x" - + Integer.toHexString(id)); - rnf.initCause(e); - throw rnf; - } - - } else { - try { - InputStream is = mAssets.openNonAsset( - value.assetCookie, file, AssetManager.ACCESS_BUFFER); - // System.out.println("Opened file " + file + ": " + is); - dr = Drawable.createFromResourceStream(this, value, is, file); - is.close(); - // System.out.println("Created stream: " + dr); - } catch (Exception e) { - NotFoundException rnf = new NotFoundException( - "File " + file + " from drawable resource ID #0x" - + Integer.toHexString(id)); - rnf.initCause(e); - throw rnf; - } + + } else { + try { + InputStream is = mAssets.openNonAsset( + value.assetCookie, file, AssetManager.ACCESS_BUFFER); + // System.out.println("Opened file " + file + ": " + is); + dr = Drawable.createFromResourceStream(this, value, is, file); + is.close(); + // System.out.println("Created stream: " + dr); + } catch (Exception e) { + NotFoundException rnf = new NotFoundException( + "File " + file + " from drawable resource ID #0x" + + Integer.toHexString(id)); + rnf.initCause(e); + throw rnf; } } } @@ -1656,13 +1647,13 @@ public class Resources { if (cs != null) { if (mPreloading) { mPreloadedDrawables.put(key, cs); - } else { - synchronized (mTmpValue) { - //Log.i(TAG, "Saving cached drawable @ #" + - // Integer.toHexString(key.intValue()) - // + " in " + this + ": " + cs); - mDrawableCache.put(key, new WeakReference(cs)); - } + } + synchronized (mTmpValue) { + //Log.i(TAG, "Saving cached drawable @ #" + + // Integer.toHexString(key.intValue()) + // + " in " + this + ": " + cs); + mDrawableCache.put( + key, new WeakReference(cs)); } } } @@ -1670,7 +1661,7 @@ public class Resources { return dr; } - private Drawable getCachedDrawable(int key) { + private final Drawable getCachedDrawable(int key) { synchronized (mTmpValue) { WeakReference wr = mDrawableCache.get(key); if (wr != null) { // we have the key @@ -1691,40 +1682,13 @@ public class Resources { /*package*/ ColorStateList loadColorStateList(TypedValue value, int id) throws NotFoundException { - if (TRACE_FOR_PRELOAD) { - // Log only framework resources - if ((id >>> 24) == 0x1) { - final String name = getResourceName(id); - if (name != null) android.util.Log.d("PreloadColorStateList", name); - } + if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT + && value.type <= TypedValue.TYPE_LAST_COLOR_INT) { + return ColorStateList.valueOf(value.data); } - final int key = (value.assetCookie << 24) | value.data; - - ColorStateList csl; - - if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT && - value.type <= TypedValue.TYPE_LAST_COLOR_INT) { - - csl = mPreloadedColorStateLists.get(key); - if (csl != null) { - return csl; - } - - csl = ColorStateList.valueOf(value.data); - if (mPreloading) { - mPreloadedColorStateLists.put(key, csl); - } - - return csl; - } - - csl = getCachedColorStateList(key); - if (csl != null) { - return csl; - } - - csl = mPreloadedColorStateLists.get(key); + final int key = (value.assetCookie<<24)|value.data; + ColorStateList csl = getCachedColorStateList(key); if (csl != null) { return csl; } @@ -1756,16 +1720,12 @@ public class Resources { } if (csl != null) { - if (mPreloading) { - mPreloadedColorStateLists.put(key, csl); - } else { - synchronized (mTmpValue) { - //Log.i(TAG, "Saving cached color state list @ #" + - // Integer.toHexString(key.intValue()) - // + " in " + this + ": " + csl); - mColorStateListCache.put( - key, new WeakReference(csl)); - } + synchronized (mTmpValue) { + //Log.i(TAG, "Saving cached color state list @ #" + + // Integer.toHexString(key.intValue()) + // + " in " + this + ": " + csl); + mColorStateListCache.put( + key, new WeakReference(csl)); } } diff --git a/core/java/android/content/res/StringBlock.java b/core/java/android/content/res/StringBlock.java index e684cb8018df9..3df770889d66f 100644 --- a/core/java/android/content/res/StringBlock.java +++ b/core/java/android/content/res/StringBlock.java @@ -141,8 +141,6 @@ final class StringBlock { int type = style[i]; if (localLOGV) Log.v(TAG, "Applying style span id=" + type + ", start=" + style[i+1] + ", end=" + style[i+2]); - - if (type == ids.boldId) { buffer.setSpan(new StyleSpan(Typeface.BOLD), style[i+1], style[i+2]+1, @@ -180,8 +178,9 @@ final class StringBlock { style[i+1], style[i+2]+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } else if (type == ids.listItemId) { - addParagraphSpan(buffer, new BulletSpan(10), - style[i+1], style[i+2]+1); + buffer.setSpan(new BulletSpan(10), + style[i+1], style[i+2]+1, + Spannable.SPAN_PARAGRAPH); } else if (type == ids.marqueeId) { buffer.setSpan(TextUtils.TruncateAt.MARQUEE, style[i+1], style[i+2]+1, @@ -195,8 +194,9 @@ final class StringBlock { sub = subtag(tag, ";height="); if (sub != null) { int size = Integer.parseInt(sub); - addParagraphSpan(buffer, new Height(size), - style[i+1], style[i+2]+1); + buffer.setSpan(new Height(size), + style[i+1], style[i+2]+1, + Spannable.SPAN_PARAGRAPH); } sub = subtag(tag, ";size="); @@ -231,28 +231,6 @@ final class StringBlock { style[i+1], style[i+2]+1, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); } - } else if (tag.startsWith("annotation;")) { - int len = tag.length(); - int next; - - for (int t = tag.indexOf(';'); t < len; t = next) { - int eq = tag.indexOf('=', t); - if (eq < 0) { - break; - } - - next = tag.indexOf(';', eq); - if (next < 0) { - next = len; - } - - String key = tag.substring(t + 1, eq); - String value = tag.substring(eq + 1, next); - - buffer.setSpan(new Annotation(key, value), - style[i+1], style[i+2]+1, - Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - } } } @@ -261,34 +239,6 @@ final class StringBlock { return new SpannedString(buffer); } - /** - * If a translator has messed up the edges of paragraph-level markup, - * fix it to actually cover the entire paragraph that it is attached to - * instead of just whatever range they put it on. - */ - private static void addParagraphSpan(Spannable buffer, Object what, - int start, int end) { - int len = buffer.length(); - - if (start != 0 && start != len && buffer.charAt(start - 1) != '\n') { - for (start--; start > 0; start--) { - if (buffer.charAt(start - 1) == '\n') { - break; - } - } - } - - if (end != 0 && end != len && buffer.charAt(end - 1) != '\n') { - for (end++; end < len; end++) { - if (buffer.charAt(end - 1) == '\n') { - break; - } - } - } - - buffer.setSpan(what, start, end, Spannable.SPAN_PARAGRAPH); - } - private static String subtag(String full, String attribute) { int start = full.indexOf(attribute); if (start < 0) { diff --git a/core/java/android/content/res/TypedArray.java b/core/java/android/content/res/TypedArray.java index 3a32c03122025..82a57dd1b0adf 100644 --- a/core/java/android/content/res/TypedArray.java +++ b/core/java/android/content/res/TypedArray.java @@ -438,34 +438,6 @@ public class TypedArray { throw new RuntimeException(getPositionDescription() + ": You must supply a " + name + " attribute."); } - - /** - * Special version of {@link #getDimensionPixelSize} for retrieving - * {@link android.view.ViewGroup}'s layout_width and layout_height - * attributes. This is only here for performance reasons; applications - * should use {@link #getDimensionPixelSize}. - * - * @param index Index of the attribute to retrieve. - * @param defValue The default value to return if this attribute is not - * default or contains the wrong type of data. - * - * @return Attribute dimension value multiplied by the appropriate - * metric and truncated to integer pixels. - */ - public int getLayoutDimension(int index, int defValue) { - index *= AssetManager.STYLE_NUM_ENTRIES; - final int[] data = mData; - final int type = data[index+AssetManager.STYLE_TYPE]; - if (type >= TypedValue.TYPE_FIRST_INT - && type <= TypedValue.TYPE_LAST_INT) { - return data[index+AssetManager.STYLE_DATA]; - } else if (type == TypedValue.TYPE_DIMENSION) { - return TypedValue.complexToDimensionPixelSize( - data[index+AssetManager.STYLE_DATA], mResources.mMetrics); - } - - return defValue; - } /** * Retrieve a fractional unit attribute at index. diff --git a/core/java/android/database/sqlite/SQLiteDatabase.java b/core/java/android/database/sqlite/SQLiteDatabase.java index 2af080ae19bad..87bb277aced97 100644 --- a/core/java/android/database/sqlite/SQLiteDatabase.java +++ b/core/java/android/database/sqlite/SQLiteDatabase.java @@ -778,9 +778,9 @@ public class SQLiteDatabase extends SQLiteClosable { } /** - * Returns the current database page size, in bytes. + * Returns the maximum size the database may grow to. * - * @return the database page size, in bytes + * @return the new maximum database size */ public long getPageSize() { SQLiteStatement prog = null; diff --git a/core/java/android/database/sqlite/SQLiteStatement.java b/core/java/android/database/sqlite/SQLiteStatement.java index 5889ad90aaad7..d169259566995 100644 --- a/core/java/android/database/sqlite/SQLiteStatement.java +++ b/core/java/android/database/sqlite/SQLiteStatement.java @@ -17,7 +17,6 @@ package android.database.sqlite; import android.os.SystemClock; -import android.util.Log; /** * A pre-compiled statement against a {@link SQLiteDatabase} that can be reused. @@ -27,10 +26,6 @@ import android.util.Log; */ public class SQLiteStatement extends SQLiteProgram { - private static final String TAG = "SQLiteStatement"; - - private final String mSql; - /** * Don't use SQLiteStatement constructor directly, please use * {@link SQLiteDatabase#compileStatement(String)} @@ -39,11 +34,6 @@ public class SQLiteStatement extends SQLiteProgram */ /* package */ SQLiteStatement(SQLiteDatabase db, String sql) { super(db, sql); - if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { - mSql = sql; - } else { - mSql = null; - } } /** @@ -60,9 +50,6 @@ public class SQLiteStatement extends SQLiteProgram acquireReference(); try { - if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { - Log.v(TAG, "execute() for [" + mSql + "]"); - } native_execute(); if (logStats) { mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime()); @@ -90,9 +77,6 @@ public class SQLiteStatement extends SQLiteProgram acquireReference(); try { - if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { - Log.v(TAG, "executeInsert() for [" + mSql + "]"); - } native_execute(); if (logStats) { mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime()); @@ -119,9 +103,6 @@ public class SQLiteStatement extends SQLiteProgram acquireReference(); try { - if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { - Log.v(TAG, "simpleQueryForLong() for [" + mSql + "]"); - } long retValue = native_1x1_long(); if (logStats) { mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime()); @@ -148,9 +129,6 @@ public class SQLiteStatement extends SQLiteProgram acquireReference(); try { - if (SQLiteDebug.DEBUG_SQL_STATEMENTS) { - Log.v(TAG, "simpleQueryForString() for [" + mSql + "]"); - } String retValue = native_1x1_string(); if (logStats) { mDatabase.logTimeStat(false /* write */, startTime, SystemClock.elapsedRealtime()); diff --git a/core/java/android/gadget/GadgetHost.java b/core/java/android/gadget/GadgetHost.java index 3d88b58499bb3..31aed32a1e2bf 100644 --- a/core/java/android/gadget/GadgetHost.java +++ b/core/java/android/gadget/GadgetHost.java @@ -19,7 +19,6 @@ package android.gadget; import android.content.Context; import android.os.Handler; import android.os.IBinder; -import android.os.Looper; import android.os.Message; import android.os.RemoteException; import android.os.ServiceManager; @@ -63,11 +62,7 @@ public class GadgetHost { } } - class UpdateHandler extends Handler { - public UpdateHandler(Looper looper) { - super(looper); - } - + Handler mHandler = new Handler() { public void handleMessage(Message msg) { switch (msg.what) { case HANDLE_UPDATE: { @@ -80,9 +75,7 @@ public class GadgetHost { } } } - } - - Handler mHandler; + }; int mHostId; Callbacks mCallbacks = new Callbacks(); @@ -91,7 +84,6 @@ public class GadgetHost { public GadgetHost(Context context, int hostId) { mContext = context; mHostId = hostId; - mHandler = new UpdateHandler(context.getMainLooper()); synchronized (sServiceLock) { if (sService == null) { IBinder b = ServiceManager.getService(Context.GADGET_SERVICE); diff --git a/core/java/android/gadget/GadgetHostView.java b/core/java/android/gadget/GadgetHostView.java index 5cbd98828ef65..a985bd415559c 100644 --- a/core/java/android/gadget/GadgetHostView.java +++ b/core/java/android/gadget/GadgetHostView.java @@ -18,13 +18,7 @@ package android.gadget; import android.content.Context; import android.content.pm.PackageManager; -import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Color; -import android.graphics.Paint; -import android.os.Handler; -import android.os.Message; -import android.os.SystemClock; import android.util.Config; import android.util.Log; import android.view.Gravity; @@ -35,23 +29,16 @@ import android.view.animation.Animation; import android.widget.FrameLayout; import android.widget.RemoteViews; import android.widget.TextView; +import android.widget.ViewAnimator; /** * Provides the glue to show gadget views. This class offers automatic animation * between updates, and will try recycling old views for each incoming * {@link RemoteViews}. */ -public class GadgetHostView extends FrameLayout { +public class GadgetHostView extends ViewAnimator implements Animation.AnimationListener { static final String TAG = "GadgetHostView"; - static final boolean LOGD = false; - static final boolean CROSSFADE = false; - - static final int VIEW_MODE_NOINIT = 0; - static final int VIEW_MODE_CONTENT = 1; - static final int VIEW_MODE_ERROR = 2; - static final int VIEW_MODE_DEFAULT = 3; - - static final int FADE_DURATION = 1000; + static final boolean LOGD = Config.LOGD || true; // When we're inflating the initialLayout for a gadget, we only allow // views that are allowed in RemoteViews. @@ -60,17 +47,28 @@ public class GadgetHostView extends FrameLayout { return clazz.isAnnotationPresent(RemoteViews.RemoteView.class); } }; - - Context mContext; + + Context mLocalContext; int mGadgetId; GadgetProviderInfo mInfo; - View mView; - int mViewMode = VIEW_MODE_NOINIT; - int mLayoutId = -1; - long mFadeStartTime = -1; - Bitmap mOld; - Paint mOldPaint = new Paint(); + + View mActiveView = null; + View mStaleView = null; + + int mActiveLayoutId = -1; + int mStaleLayoutId = -1; + + /** + * Last set of {@link RemoteViews} applied to {@link #mActiveView} + */ + RemoteViews mActiveActions = null; + + /** + * Flag indicating that {@link #mActiveActions} has been applied to + * {@link #mStaleView}, meaning it's readyto recycle. + */ + boolean mStalePrepared = false; /** * Create a host view. Uses default fade animations. @@ -88,13 +86,27 @@ public class GadgetHostView extends FrameLayout { */ public GadgetHostView(Context context, int animationIn, int animationOut) { super(context); - mContext = context; + mLocalContext = context; + + // Prepare our default transition animations + setAnimateFirstView(true); + setInAnimation(context, animationIn); + setOutAnimation(context, animationOut); + + // Watch for animation events to prepare recycling + Animation inAnimation = getInAnimation(); + if (inAnimation != null) { + inAnimation.setAnimationListener(this); + } } /** * Set the gadget that will be displayed by this view. */ public void setGadget(int gadgetId, GadgetProviderInfo info) { + if (mInfo != null) { + // TODO: remove the old view, or whatever + } mGadgetId = gadgetId; mInfo = info; } @@ -107,141 +119,92 @@ public class GadgetHostView extends FrameLayout { return mInfo; } + public void onAnimationEnd(Animation animation) { + // When our transition animation finishes, we should try bringing our + // newly-stale view up to the current view. + if (mActiveActions != null && + mStaleLayoutId == mActiveActions.getLayoutId()) { + if (LOGD) Log.d(TAG, "after animation, layoutId matched so we're recycling old view"); + mActiveActions.reapply(mLocalContext, mStaleView); + mStalePrepared = true; + } + } + + public void onAnimationRepeat(Animation animation) { + } + + public void onAnimationStart(Animation animation) { + } + /** * Process a set of {@link RemoteViews} coming in as an update from the * gadget provider. Will animate into these new views as needed. */ public void updateGadget(RemoteViews remoteViews) { - if (LOGD) Log.d(TAG, "updateGadget called mOld=" + mOld); + if (LOGD) Log.d(TAG, "updateGadget called"); boolean recycled = false; - View content = null; + View newContent = null; Exception exception = null; - // Capture the old view into a bitmap so we can do the crossfade. - if (CROSSFADE) { - if (mFadeStartTime < 0) { - if (mView != null) { - final int width = mView.getWidth(); - final int height = mView.getHeight(); - try { - mOld = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888); - } catch (OutOfMemoryError e) { - // we just won't do the fade - mOld = null; - } - if (mOld != null) { - //mView.drawIntoBitmap(mOld); - } - } - } - } - if (remoteViews == null) { - if (mViewMode == VIEW_MODE_DEFAULT) { - // We've already done this -- nothing to do. - return; - } - content = getDefaultView(); - mLayoutId = -1; - mViewMode = VIEW_MODE_DEFAULT; - } else { - int layoutId = remoteViews.getLayoutId(); - - // If our stale view has been prepared to match active, and the new - // layout matches, try recycling it - if (content == null && layoutId == mLayoutId) { - try { - remoteViews.reapply(mContext, mView); - content = mView; - recycled = true; - if (LOGD) Log.d(TAG, "was able to recycled existing layout"); - } catch (RuntimeException e) { - exception = e; - } - } - - // Try normal RemoteView inflation - if (content == null) { - try { - content = remoteViews.apply(mContext, this); - if (LOGD) Log.d(TAG, "had to inflate new layout"); - } catch (RuntimeException e) { - exception = e; - } - } - - mLayoutId = layoutId; - mViewMode = VIEW_MODE_CONTENT; + newContent = getDefaultView(); } - if (content == null) { - if (mViewMode == VIEW_MODE_ERROR) { - // We've already done this -- nothing to do. - return ; + // If our stale view has been prepared to match active, and the new + // layout matches, try recycling it + if (newContent == null && mStalePrepared && + remoteViews.getLayoutId() == mStaleLayoutId) { + try { + remoteViews.reapply(mLocalContext, mStaleView); + newContent = mStaleView; + recycled = true; + if (LOGD) Log.d(TAG, "was able to recycled existing layout"); + } catch (RuntimeException e) { + exception = e; } - Log.w(TAG, "updateGadget couldn't find any view, using error view", exception); - content = getErrorView(); - mViewMode = VIEW_MODE_ERROR; + } + + // Try normal RemoteView inflation + if (newContent == null) { + try { + newContent = remoteViews.apply(mLocalContext, this); + if (LOGD) Log.d(TAG, "had to inflate new layout"); + } catch (RuntimeException e) { + exception = e; + } + } + + if (exception != null && LOGD) { + Log.w(TAG, "Error inflating gadget " + getGadgetInfo(), exception); + } + + if (newContent == null) { + // TODO: Should we throw an exception here for the host activity to catch? + // Maybe we should show a generic error widget. + if (LOGD) Log.d(TAG, "updateGadget couldn't find any view, so inflating error"); + newContent = getErrorView(); } if (!recycled) { - prepareView(content); - addView(content); + prepareView(newContent); + addView(newContent); } - - if (mView != content) { - removeView(mView); - mView = content; - } - - if (CROSSFADE) { - if (mFadeStartTime < 0) { - // if there is already an animation in progress, don't do anything -- - // the new view will pop in on top of the old one during the cross fade, - // and that looks okay. - mFadeStartTime = SystemClock.uptimeMillis(); - invalidate(); - } - } - } - - protected boolean drawChild(Canvas canvas, View child, long drawingTime) { - if (CROSSFADE) { - int alpha; - int l = child.getLeft(); - int t = child.getTop(); - if (mFadeStartTime > 0) { - alpha = (int)(((drawingTime-mFadeStartTime)*255)/FADE_DURATION); - if (alpha > 255) { - alpha = 255; - } - Log.d(TAG, "drawChild alpha=" + alpha + " l=" + l + " t=" + t - + " w=" + child.getWidth()); - if (alpha != 255 && mOld != null) { - mOldPaint.setAlpha(255-alpha); - //canvas.drawBitmap(mOld, l, t, mOldPaint); - } - } else { - alpha = 255; - } - int restoreTo = canvas.saveLayerAlpha(l, t, child.getWidth(), child.getHeight(), alpha, - Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); - boolean rv = super.drawChild(canvas, child, drawingTime); - canvas.restoreToCount(restoreTo); - if (alpha < 255) { - invalidate(); - } else { - mFadeStartTime = -1; - if (mOld != null) { - mOld.recycle(); - mOld = null; - } - } - return rv; - } else { - return super.drawChild(canvas, child, drawingTime); + + showNext(); + + if (!recycled) { + removeView(mStaleView); } + + mStalePrepared = false; + mActiveActions = remoteViews; + + mStaleView = mActiveView; + mActiveView = newContent; + + mStaleLayoutId = mActiveLayoutId; + mActiveLayoutId = (remoteViews == null) ? -1 : remoteViews.getLayoutId(); } /** @@ -271,7 +234,7 @@ public class GadgetHostView extends FrameLayout { try { if (mInfo != null) { - Context theirContext = mContext.createPackageContext( + Context theirContext = mLocalContext.createPackageContext( mInfo.provider.getPackageName(), 0 /* no flags */); LayoutInflater inflater = (LayoutInflater) theirContext.getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -303,9 +266,9 @@ public class GadgetHostView extends FrameLayout { * Inflate and return a view that represents an error state. */ protected View getErrorView() { - TextView tv = new TextView(mContext); - tv.setText(com.android.internal.R.string.gadget_host_error_inflating); - // TODO: get this color from somewhere. + TextView tv = new TextView(mLocalContext); + // TODO: move this error string and background color into resources + tv.setText("Error inflating gadget"); tv.setBackgroundColor(Color.argb(127, 0, 0, 0)); return tv; } diff --git a/core/java/android/gadget/GadgetManager.java b/core/java/android/gadget/GadgetManager.java index d2c4055e3d232..a9a2c80105964 100644 --- a/core/java/android/gadget/GadgetManager.java +++ b/core/java/android/gadget/GadgetManager.java @@ -300,21 +300,5 @@ public class GadgetManager { throw new RuntimeException("system server dead?", e); } } - - /** - * Get the list of gadgetIds that have been bound to the given gadget - * provider. - * - * @param provider The {@link android.content.BroadcastReceiver} that is the - * gadget provider to find gadgetIds for. - */ - public int[] getGadgetIds(ComponentName provider) { - try { - return sService.getGadgetIds(provider); - } - catch (RemoteException e) { - throw new RuntimeException("system server dead?", e); - } - } } diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java index 106c9200b680c..40a5b478e5f0a 100644 --- a/core/java/android/hardware/Camera.java +++ b/core/java/android/hardware/Camera.java @@ -48,6 +48,7 @@ public class Camera { private static final int ERROR_CALLBACK = 5; private int mNativeContext; // accessed by native methods + private int mListenerContext; private EventHandler mEventHandler; private ShutterCallback mShutterCallback; private PictureCallback mRawImageCallback; diff --git a/core/java/android/inputmethodservice/ExtractEditText.java b/core/java/android/inputmethodservice/ExtractEditText.java index 0295f695784f2..52f8209289002 100644 --- a/core/java/android/inputmethodservice/ExtractEditText.java +++ b/core/java/android/inputmethodservice/ExtractEditText.java @@ -97,13 +97,6 @@ public class ExtractEditText extends EditText { return true; } - /** - * Return true if the edit text is currently showing a scroll bar. - */ - public boolean hasVerticalScrollBar() { - return computeVerticalScrollRange() > computeVerticalScrollExtent(); - } - /** * Pretend like the window this view is in always has focus, so its * highlight and cursor will be displayed. diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java index 1e2e2f3e7b565..4be1fc798f883 100644 --- a/core/java/android/inputmethodservice/InputMethodService.java +++ b/core/java/android/inputmethodservice/InputMethodService.java @@ -26,9 +26,7 @@ import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.IBinder; -import android.os.SystemClock; import android.provider.Settings; -import android.text.InputType; import android.text.Layout; import android.text.Spannable; import android.text.method.MovementMethod; @@ -51,7 +49,6 @@ import android.view.inputmethod.InputConnection; import android.view.inputmethod.InputMethod; import android.view.inputmethod.InputMethodManager; import android.view.inputmethod.EditorInfo; -import android.widget.Button; import android.widget.FrameLayout; import java.io.FileDescriptor; @@ -244,8 +241,6 @@ public class InputMethodService extends AbstractInputMethodService { boolean mIsFullscreen; View mExtractView; ExtractEditText mExtractEditText; - ViewGroup mExtractAccessories; - Button mExtractAction; ExtractedText mExtractedText; int mExtractedToken; @@ -276,21 +271,6 @@ public class InputMethodService extends AbstractInputMethodService { } }; - final View.OnClickListener mActionClickListener = new View.OnClickListener() { - public void onClick(View v) { - final EditorInfo ei = getCurrentInputEditorInfo(); - final InputConnection ic = getCurrentInputConnection(); - if (ei != null && ic != null) { - if (ei.actionId != 0) { - ic.performEditorAction(ei.actionId); - } else if ((ei.imeOptions&EditorInfo.IME_MASK_ACTION) - != EditorInfo.IME_ACTION_NONE) { - ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION); - } - } - } - }; - /** * Concrete implementation of * {@link AbstractInputMethodService.AbstractInputMethodImpl} that provides @@ -542,8 +522,6 @@ public class InputMethodService extends AbstractInputMethodService { mExtractFrame = (FrameLayout)mRootView.findViewById(android.R.id.extractArea); mExtractView = null; mExtractEditText = null; - mExtractAccessories = null; - mExtractAction = null; mFullscreenApplied = false; mCandidatesFrame = (FrameLayout)mRootView.findViewById(android.R.id.candidatesArea); @@ -725,7 +703,7 @@ public class InputMethodService extends AbstractInputMethodService { setExtractView(v); } } - startExtractingText(false); + startExtractingText(); } } @@ -929,17 +907,9 @@ public class InputMethodService extends AbstractInputMethodService { mExtractEditText = (ExtractEditText)view.findViewById( com.android.internal.R.id.inputExtractEditText); mExtractEditText.setIME(this); - mExtractAction = (Button)view.findViewById( - com.android.internal.R.id.inputExtractAction); - if (mExtractAction != null) { - mExtractAccessories = (ViewGroup)view.findViewById( - com.android.internal.R.id.inputExtractAccessories); - } - startExtractingText(false); + startExtractingText(); } else { mExtractEditText = null; - mExtractAccessories = null; - mExtractAction = null; } } @@ -1196,7 +1166,7 @@ public class InputMethodService extends AbstractInputMethodService { } if (doShowInput) { - startExtractingText(false); + startExtractingText(); } if (!wasVisible) { @@ -1306,7 +1276,7 @@ public class InputMethodService extends AbstractInputMethodService { if (DEBUG) Log.v(TAG, "CALL: onStartInputView"); mInputViewStarted = true; onStartInputView(mInputEditorInfo, restarting); - startExtractingText(true); + startExtractingText(); } else if (mCandidatesVisibility == View.VISIBLE) { if (DEBUG) Log.v(TAG, "CALL: onStartCandidatesView"); mCandidatesViewStarted = true; @@ -1483,25 +1453,6 @@ public class InputMethodService extends AbstractInputMethodService { static final int MOVEMENT_DOWN = -1; static final int MOVEMENT_UP = -2; - void reportExtractedMovement(int keyCode, int count) { - int dx = 0, dy = 0; - switch (keyCode) { - case KeyEvent.KEYCODE_DPAD_LEFT: - dx = -count; - break; - case KeyEvent.KEYCODE_DPAD_RIGHT: - dx = count; - break; - case KeyEvent.KEYCODE_DPAD_UP: - dy = -count; - break; - case KeyEvent.KEYCODE_DPAD_DOWN: - dy = count; - break; - } - onExtractedCursorMovement(dx, dy); - } - boolean doMovementKey(int keyCode, KeyEvent event, int count) { final ExtractEditText eet = mExtractEditText; if (isFullscreenMode() && isInputViewShown() && eet != null) { @@ -1516,7 +1467,6 @@ public class InputMethodService extends AbstractInputMethodService { if (count == MOVEMENT_DOWN) { if (movement.onKeyDown(eet, (Spannable)eet.getText(), keyCode, event)) { - reportExtractedMovement(keyCode, 1); return true; } } else if (count == MOVEMENT_UP) { @@ -1525,9 +1475,7 @@ public class InputMethodService extends AbstractInputMethodService { return true; } } else { - if (movement.onKeyOther(eet, (Spannable)eet.getText(), event)) { - reportExtractedMovement(keyCode, count); - } else { + if (!movement.onKeyOther(eet, (Spannable)eet.getText(), event)) { KeyEvent down = new KeyEvent(event, KeyEvent.ACTION_DOWN); if (movement.onKeyDown(eet, (Spannable)eet.getText(), keyCode, down)) { @@ -1540,7 +1488,6 @@ public class InputMethodService extends AbstractInputMethodService { movement.onKeyUp(eet, (Spannable)eet.getText(), keyCode, up); } - reportExtractedMovement(keyCode, count); } } } @@ -1559,97 +1506,6 @@ public class InputMethodService extends AbstractInputMethodService { return false; } - /** - * Send the given key event code (as defined by {@link KeyEvent}) to the - * current input connection is a key down + key up event pair. The sent - * events have {@link KeyEvent#FLAG_SOFT_KEYBOARD KeyEvent.FLAG_SOFT_KEYBOARD} - * set, so that the recipient can identify them as coming from a software - * input method, and - * {@link KeyEvent#FLAG_KEEP_TOUCH_MODE KeyEvent.FLAG_KEEP_TOUCH_MODE}, so - * that they don't impact the current touch mode of the UI. - * - * @param keyEventCode The raw key code to send, as defined by - * {@link KeyEvent}. - */ - public void sendDownUpKeyEvents(int keyEventCode) { - InputConnection ic = getCurrentInputConnection(); - if (ic == null) return; - long eventTime = SystemClock.uptimeMillis(); - ic.sendKeyEvent(new KeyEvent(eventTime, eventTime, - KeyEvent.ACTION_DOWN, keyEventCode, 0, 0, 0, 0, - KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)); - ic.sendKeyEvent(new KeyEvent(SystemClock.uptimeMillis(), eventTime, - KeyEvent.ACTION_UP, keyEventCode, 0, 0, 0, 0, - KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE)); - } - - /** - * Ask the input target to execute its default action via - * {@link InputConnection#performEditorAction - * InputConnection.performEditorAction()}. - * - * @param fromEnterKey If true, this will be executed as if the user had - * pressed an enter key on the keyboard, that is it will not - * be done if the editor has set {@link EditorInfo#IME_FLAG_NO_ENTER_ACTION - * EditorInfo.IME_FLAG_NO_ENTER_ACTION}. If false, the action will be - * sent regardless of how the editor has set that flag. - * - * @return Returns a boolean indicating whether an action has been sent. - * If false, either the editor did not specify a default action or it - * does not want an action from the enter key. If true, the action was - * sent (or there was no input connection at all). - */ - public boolean sendDefaultEditorAction(boolean fromEnterKey) { - EditorInfo ei = getCurrentInputEditorInfo(); - if (ei != null && - (!fromEnterKey || (ei.imeOptions & - EditorInfo.IME_FLAG_NO_ENTER_ACTION) == 0) && - (ei.imeOptions & EditorInfo.IME_MASK_ACTION) != - EditorInfo.IME_ACTION_NONE) { - // If the enter key was pressed, and the editor has a default - // action associated with pressing enter, then send it that - // explicit action instead of the key event. - InputConnection ic = getCurrentInputConnection(); - if (ic != null) { - ic.performEditorAction(ei.imeOptions&EditorInfo.IME_MASK_ACTION); - } - return true; - } - - return false; - } - - /** - * Send the given UTF-16 character to the current input connection. Most - * characters will be delivered simply by calling - * {@link InputConnection#commitText InputConnection.commitText()} with - * the character; some, however, may be handled different. In particular, - * the enter character ('\n') will either be delivered as an action code - * or a raw key event, as appropriate. - * - * @param charCode The UTF-16 character code to send. - */ - public void sendKeyChar(char charCode) { - switch (charCode) { - case '\n': // Apps may be listening to an enter key to perform an action - if (!sendDefaultEditorAction(true)) { - sendDownUpKeyEvents(KeyEvent.KEYCODE_ENTER); - } - break; - default: - // Make sure that digits go through any text watcher on the client side. - if (charCode >= '0' && charCode <= '9') { - sendDownUpKeyEvents(charCode - '0' + KeyEvent.KEYCODE_0); - } else { - InputConnection ic = getCurrentInputConnection(); - if (ic != null) { - ic.commitText(String.valueOf((char) charCode), 1); - } - } - break; - } - } - /** * This is called when the user has moved the cursor in the extracted * text view, when running in fullsreen mode. The default implementation @@ -1666,36 +1522,11 @@ public class InputMethodService extends AbstractInputMethodService { /** * This is called when the user has clicked on the extracted text view, * when running in fullscreen mode. The default implementation hides - * the candidates view when this happens, but only if the extracted text - * editor has a vertical scroll bar because its text doesn't fit. - * Re-implement this to provide whatever behavior you want. + * the candidates view when this happens. Re-implement this to provide + * whatever behavior you want. */ public void onExtractedTextClicked() { - if (mExtractEditText == null) { - return; - } - if (mExtractEditText.hasVerticalScrollBar()) { - setCandidatesViewShown(false); - } - } - - /** - * This is called when the user has performed a cursor movement in the - * extracted text view, when it is running in fullscreen mode. The default - * implementation hides the candidates view when a vertical movement - * happens, but only if the extracted text editor has a vertical scroll bar - * because its text doesn't fit. - * Re-implement this to provide whatever behavior you want. - * @param dx The amount of cursor movement in the x dimension. - * @param dy The amount of cursor movement in the y dimension. - */ - public void onExtractedCursorMovement(int dx, int dy) { - if (mExtractEditText == null || dy == 0) { - return; - } - if (mExtractEditText.hasVerticalScrollBar()) { - setCandidatesViewShown(false); - } + setCandidatesViewShown(false); } /** @@ -1714,74 +1545,7 @@ public class InputMethodService extends AbstractInputMethodService { return true; } - /** - * Return text that can be used as a button label for the given - * {@link EditorInfo#imeOptions EditorInfo.imeOptions}. Returns null - * if there is no action requested. Note that there is no guarantee that - * the returned text will be relatively short, so you probably do not - * want to use it as text on a soft keyboard key label. - * - * @param imeOptions The value from @link EditorInfo#imeOptions EditorInfo.imeOptions}. - * - * @return Returns a label to use, or null if there is no action. - */ - public CharSequence getTextForImeAction(int imeOptions) { - switch (imeOptions&EditorInfo.IME_MASK_ACTION) { - case EditorInfo.IME_ACTION_NONE: - return null; - case EditorInfo.IME_ACTION_GO: - return getText(com.android.internal.R.string.ime_action_go); - case EditorInfo.IME_ACTION_SEARCH: - return getText(com.android.internal.R.string.ime_action_search); - case EditorInfo.IME_ACTION_SEND: - return getText(com.android.internal.R.string.ime_action_send); - case EditorInfo.IME_ACTION_NEXT: - return getText(com.android.internal.R.string.ime_action_next); - default: - return getText(com.android.internal.R.string.ime_action_default); - } - } - - /** - * Called when it is time to update the actions available from a full-screen - * IME. You do not need to deal with this if you are using the standard - * full screen extract UI. If replacing it, you will need to re-implement - * this to put the action in your own UI and handle it. - */ - public void onUpdateExtractingAccessories(EditorInfo ei) { - if (mExtractAccessories == null) { - return; - } - final boolean hasAction = ei.actionLabel != null || ( - (ei.imeOptions&EditorInfo.IME_MASK_ACTION) != EditorInfo.IME_ACTION_NONE && - (ei.imeOptions&EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0); - if (hasAction) { - mExtractAccessories.setVisibility(View.VISIBLE); - if (ei.actionLabel != null) { - mExtractAction.setText(ei.actionLabel); - } else { - mExtractAction.setText(getTextForImeAction(ei.imeOptions)); - } - mExtractAction.setOnClickListener(mActionClickListener); - } else { - mExtractAccessories.setVisibility(View.GONE); - mExtractAction.setOnClickListener(null); - } - } - - /** - * This is called when, while currently displayed in extract mode, the - * current input target changes. The default implementation will - * auto-hide the IME if the new target is not a full editor, since this - * can be an confusing experience for the user. - */ - public void onExtractingInputChanged(EditorInfo ei) { - if (ei.inputType == InputType.TYPE_NULL) { - dismissSoftInput(InputMethodManager.HIDE_NOT_ALWAYS); - } - } - - void startExtractingText(boolean inputChanged) { + void startExtractingText() { final ExtractEditText eet = mExtractEditText; if (eet != null && getCurrentInputStarted() && isFullscreenMode()) { @@ -1793,13 +1557,9 @@ public class InputMethodService extends AbstractInputMethodService { req.hintMaxChars = 10000; mExtractedText = getCurrentInputConnection().getExtractedText(req, InputConnection.GET_EXTRACTED_TEXT_MONITOR); - - final EditorInfo ei = getCurrentInputEditorInfo(); - try { eet.startInternalChanges(); - onUpdateExtractingAccessories(ei); - int inputType = ei.inputType; + int inputType = getCurrentInputEditorInfo().inputType; if ((inputType&EditorInfo.TYPE_MASK_CLASS) == EditorInfo.TYPE_CLASS_TEXT) { if ((inputType&EditorInfo.TYPE_TEXT_FLAG_IME_MULTI_LINE) != 0) { @@ -1807,7 +1567,7 @@ public class InputMethodService extends AbstractInputMethodService { } } eet.setInputType(inputType); - eet.setHint(ei.hintText); + eet.setHint(mInputEditorInfo.hintText); if (mExtractedText != null) { eet.setEnabled(true); eet.setExtractedText(mExtractedText); @@ -1818,10 +1578,6 @@ public class InputMethodService extends AbstractInputMethodService { } finally { eet.finishInternalChanges(); } - - if (inputChanged) { - onExtractingInputChanged(ei); - } } } diff --git a/core/java/android/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java index c838779e5a3cd..886e68829e1de 100755 --- a/core/java/android/inputmethodservice/KeyboardView.java +++ b/core/java/android/inputmethodservice/KeyboardView.java @@ -74,6 +74,7 @@ public class KeyboardView extends View implements View.OnClickListener { * For keys that repeat, this is only called once. * @param primaryCode the unicode of the key being pressed. If the touch is not on a valid * key, the value will be zero. + * @hide Pending API Council approval */ void onPress(int primaryCode); @@ -81,6 +82,7 @@ public class KeyboardView extends View implements View.OnClickListener { * Called when the user releases a key. This is sent after the {@link #onKey} is called. * For keys that repeat, this is only called once. * @param primaryCode the code of the key that was released + * @hide Pending API Council approval */ void onRelease(int primaryCode); @@ -96,12 +98,6 @@ public class KeyboardView extends View implements View.OnClickListener { */ void onKey(int primaryCode, int[] keyCodes); - /** - * Sends a sequence of characters to the listener. - * @param text the sequence of characters to be displayed. - */ - void onText(CharSequence text); - /** * Called when the user quickly moves the finger from right to left. */ @@ -398,7 +394,6 @@ public class KeyboardView extends View implements View.OnClickListener { requestLayout(); invalidate(); computeProximityThreshold(keyboard); - mMiniKeyboardCache.clear(); // Not really necessary to do every time, but will free up views } /** @@ -704,7 +699,9 @@ public class KeyboardView extends View implements View.OnClickListener { if (index != NOT_A_KEY && index < mKeys.length) { final Key key = mKeys[index]; if (key.text != null) { - mKeyboardActionListener.onText(key.text); + for (int i = 0; i < key.text.length(); i++) { + mKeyboardActionListener.onKey(key.text.charAt(i), key.codes); + } mKeyboardActionListener.onRelease(NOT_A_KEY); } else { int code = key.codes[0]; @@ -795,7 +792,7 @@ public class KeyboardView extends View implements View.OnClickListener { mPreviewText.setCompoundDrawables(null, null, null, null); mPreviewText.setText(getPreviewText(key)); if (key.label.length() > 1 && key.codes.length < 2) { - mPreviewText.setTextSize(mKeyTextSize); + mPreviewText.setTextSize(mLabelTextSize); mPreviewText.setTypeface(Typeface.DEFAULT_BOLD); } else { mPreviewText.setTextSize(mPreviewTextSizeLarge); @@ -899,11 +896,6 @@ public class KeyboardView extends View implements View.OnClickListener { dismissPopupKeyboard(); } - public void onText(CharSequence text) { - mKeyboardActionListener.onText(text); - dismissPopupKeyboard(); - } - public void swipeLeft() { } public void swipeRight() { } public void swipeUp() { } @@ -1110,8 +1102,6 @@ public class KeyboardView extends View implements View.OnClickListener { mHandler.removeMessages(MSG_SHOW_PREVIEW); dismissPopupKeyboard(); - - mMiniKeyboardCache.clear(); } @Override diff --git a/core/java/android/net/SSLCertificateSocketFactory.java b/core/java/android/net/SSLCertificateSocketFactory.java index ccef97e337e3b..f816caa6da2f7 100644 --- a/core/java/android/net/SSLCertificateSocketFactory.java +++ b/core/java/android/net/SSLCertificateSocketFactory.java @@ -16,46 +16,39 @@ package android.net; -import android.content.Context; +import android.util.Log; +import android.util.Config; import android.net.http.DomainNameChecker; import android.os.SystemProperties; -import android.util.Config; -import android.util.Log; - -import com.android.internal.net.SSLSessionCache; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.Socket; -import java.security.GeneralSecurityException; -import java.security.KeyManagementException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.Certificate; -import java.security.cert.X509Certificate; import javax.net.SocketFactory; +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSocket; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; -/** - * SSLSocketFactory that allows skipping the certificate chain validation - * based on system setting (socket.relaxsslcheck=yes, ro.secure=1 - for - * testing only). - * - * It also adds a readTimeout that will be set on each created socket. - * The factory will use SSL session persistence if enabled by config. - */ +import java.io.IOException; +import java.net.InetAddress; +import java.net.Socket; +import java.security.NoSuchAlgorithmException; +import java.security.KeyManagementException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.GeneralSecurityException; +import java.security.cert.Certificate; +import java.security.cert.X509Certificate; + public class SSLCertificateSocketFactory extends SSLSocketFactory { + private static final boolean DBG = true; private static final String LOG_TAG = "SSLCertificateSocketFactory"; private static X509TrustManager sDefaultTrustManager; + private final int socketReadTimeoutForSslHandshake; + static { try { TrustManagerFactory tmf = TrustManagerFactory.getInstance("X509"); @@ -90,36 +83,14 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { } }; - private static SSLSocketFactory factory; - - /** - * Initialize a single default factory to be used for all returned - * sockets. - * - * Because of the signature of getDefault(int timeout) it needs to create - * a new instance which encapsulates the timeout on each call. We want - * to share a single SSLContext and SSLSessionCache. - * - * Can be called multiple times - but only the first will initialize the factory. - * - * @param androidContext will be used for SSL session persistence. Null for backward - * compatibility, no SSL persistence. - * @hide - */ - public static synchronized void setupDefaultFactory(Context androidContext) { - if ( factory != null) { - // Can only be initialized once, to avoid having multiple caches. - return; - } - factory = SSLSessionCache.getSocketFactory(androidContext, TRUST_MANAGER); - } - - private final int socketReadTimeoutForSslHandshake; + private SSLSocketFactory factory; public SSLCertificateSocketFactory(int socketReadTimeoutForSslHandshake) throws NoSuchAlgorithmException, KeyManagementException { - this.socketReadTimeoutForSslHandshake - = socketReadTimeoutForSslHandshake; + SSLContext context = SSLContext.getInstance("TLS"); + context.init(null, TRUST_MANAGER, new java.security.SecureRandom()); + factory = (SSLSocketFactory) context.getSocketFactory(); + this.socketReadTimeoutForSslHandshake = socketReadTimeoutForSslHandshake; } /** @@ -132,11 +103,6 @@ public class SSLCertificateSocketFactory extends SSLSocketFactory { */ public static SocketFactory getDefault(int socketReadTimeoutForSslHandshake) { try { - if (factory == null) { - // The delegated factory was not initialized explicitely with a context. - // Use a default one. - setupDefaultFactory(null); - } return new SSLCertificateSocketFactory(socketReadTimeoutForSslHandshake); } catch (NoSuchAlgorithmException e) { Log.e(LOG_TAG, diff --git a/core/java/android/net/http/AndroidHttpClient.java b/core/java/android/net/http/AndroidHttpClient.java index 0c4fcda6bbd3e..4fb14991d9fd5 100644 --- a/core/java/android/net/http/AndroidHttpClient.java +++ b/core/java/android/net/http/AndroidHttpClient.java @@ -47,8 +47,6 @@ import org.apache.http.params.HttpProtocolParams; import org.apache.http.protocol.BasicHttpProcessor; import org.apache.http.protocol.HttpContext; import org.apache.http.protocol.BasicHttpContext; -import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache; -import org.apache.harmony.xnet.provider.jsse.SSLContextImpl; import java.io.IOException; import java.io.InputStream; @@ -57,7 +55,6 @@ import java.io.OutputStream; import java.util.zip.GZIPInputStream; import java.util.zip.GZIPOutputStream; import java.net.URI; -import java.security.KeyManagementException; import android.util.Log; import android.content.ContentResolver; @@ -101,13 +98,10 @@ public final class AndroidHttpClient implements HttpClient { /** * Create a new HttpClient with reasonable defaults (which you can update). - * * @param userAgent to report in your HTTP requests. - * @param sessionCache persistent session cache * @return AndroidHttpClient for you to use for all your requests. */ - public static AndroidHttpClient newInstance(String userAgent, - SSLClientSessionCache sessionCache) { + public static AndroidHttpClient newInstance(String userAgent) { HttpParams params = new BasicHttpParams(); // Turn off stale checking. Our connections break all the time anyway, @@ -129,8 +123,7 @@ public final class AndroidHttpClient implements HttpClient { schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80)); schemeRegistry.register(new Scheme("https", - socketFactoryWithCache(sessionCache), 443)); - + SSLSocketFactory.getSocketFactory(), 443)); ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry); @@ -139,41 +132,6 @@ public final class AndroidHttpClient implements HttpClient { return new AndroidHttpClient(manager, params); } - /** - * Returns a socket factory backed by the given persistent session cache. - * - * @param sessionCache to retrieve sessions from, null for no cache - */ - private static SSLSocketFactory socketFactoryWithCache( - SSLClientSessionCache sessionCache) { - if (sessionCache == null) { - // Use the default factory which doesn't support persistent - // caching. - return SSLSocketFactory.getSocketFactory(); - } - - // Create a new SSL context backed by the cache. - // TODO: Keep a weak *identity* hash map of caches to engines. In the - // mean time, if we have two engines for the same cache, they'll still - // share sessions but will have to do so through the persistent cache. - SSLContextImpl sslContext = new SSLContextImpl(); - try { - sslContext.engineInit(null, null, null, sessionCache, null); - } catch (KeyManagementException e) { - throw new AssertionError(e); - } - return new SSLSocketFactory(sslContext.engineGetSocketFactory()); - } - - /** - * Create a new HttpClient with reasonable defaults (which you can update). - * @param userAgent to report in your HTTP requests. - * @return AndroidHttpClient for you to use for all your requests. - */ - public static AndroidHttpClient newInstance(String userAgent) { - return newInstance(userAgent, null /* session cache */); - } - private final HttpClient delegate; private RuntimeException mLeakedException = new IllegalStateException( diff --git a/core/java/android/net/http/CertificateChainValidator.java b/core/java/android/net/http/CertificateChainValidator.java index 0edbe5b7e1a18..b7f7368ae24eb 100644 --- a/core/java/android/net/http/CertificateChainValidator.java +++ b/core/java/android/net/http/CertificateChainValidator.java @@ -16,6 +16,8 @@ package android.net.http; +import android.os.SystemClock; + import java.io.IOException; import java.security.cert.Certificate; @@ -26,13 +28,23 @@ import java.security.cert.X509Certificate; import java.security.GeneralSecurityException; import java.security.KeyStore; +import java.util.Arrays; +import java.util.Date; +import java.util.Enumeration; + +import javax.net.ssl.SSLContext; import javax.net.ssl.SSLHandshakeException; +import javax.net.ssl.SSLPeerUnverifiedException; import javax.net.ssl.SSLSession; import javax.net.ssl.SSLSocket; import javax.net.ssl.TrustManager; import javax.net.ssl.TrustManagerFactory; import javax.net.ssl.X509TrustManager; +import org.apache.http.HttpHost; + +import org.bouncycastle.asn1.x509.X509Name; + /** * Class responsible for all server certificate validation functionality * @@ -40,6 +52,9 @@ import javax.net.ssl.X509TrustManager; */ class CertificateChainValidator { + private static long sTotal = 0; + private static long sTotalReused = 0; + /** * The singleton instance of the certificate chain validator */ @@ -95,42 +110,91 @@ class CertificateChainValidator { * @return An SSL error object if there is an error and null otherwise */ public SslError doHandshakeAndValidateServerCertificates( - HttpsConnection connection, SSLSocket sslSocket, String domain) - throws IOException { - X509Certificate[] serverCertificates = null; + HttpsConnection connection, SSLSocket sslSocket, String domain) + throws SSLHandshakeException, IOException { - // start handshake, close the socket if we fail - try { - sslSocket.setUseClientMode(true); - sslSocket.startHandshake(); - } catch (IOException e) { - closeSocketThrowException( - sslSocket, e.getMessage(), - "failed to perform SSL handshake"); + ++sTotal; + + SSLContext sslContext = HttpsConnection.getContext(); + if (sslContext == null) { + closeSocketThrowException(sslSocket, "SSL context is null"); } - // retrieve the chain of the server peer certificates - Certificate[] peerCertificates = - sslSocket.getSession().getPeerCertificates(); + X509Certificate[] serverCertificates = null; - if (peerCertificates == null || peerCertificates.length <= 0) { - closeSocketThrowException( - sslSocket, "failed to retrieve peer certificates"); - } else { - serverCertificates = - new X509Certificate[peerCertificates.length]; - for (int i = 0; i < peerCertificates.length; ++i) { - serverCertificates[i] = - (X509Certificate)(peerCertificates[i]); + long sessionBeforeHandshakeLastAccessedTime = 0; + byte[] sessionBeforeHandshakeId = null; + + SSLSession sessionAfterHandshake = null; + + synchronized(sslContext) { + // get SSL session before the handshake + SSLSession sessionBeforeHandshake = + getSSLSession(sslContext, connection.getHost()); + if (sessionBeforeHandshake != null) { + sessionBeforeHandshakeLastAccessedTime = + sessionBeforeHandshake.getLastAccessedTime(); + + sessionBeforeHandshakeId = + sessionBeforeHandshake.getId(); } - // update the SSL certificate associated with the connection - if (connection != null) { - if (serverCertificates[0] != null) { - connection.setCertificate( - new SslCertificate(serverCertificates[0])); + // start handshake, close the socket if we fail + try { + sslSocket.setUseClientMode(true); + sslSocket.startHandshake(); + } catch (IOException e) { + closeSocketThrowException( + sslSocket, e.getMessage(), + "failed to perform SSL handshake"); + } + + // retrieve the chain of the server peer certificates + Certificate[] peerCertificates = + sslSocket.getSession().getPeerCertificates(); + + if (peerCertificates == null || peerCertificates.length <= 0) { + closeSocketThrowException( + sslSocket, "failed to retrieve peer certificates"); + } else { + serverCertificates = + new X509Certificate[peerCertificates.length]; + for (int i = 0; i < peerCertificates.length; ++i) { + serverCertificates[i] = + (X509Certificate)(peerCertificates[i]); + } + + // update the SSL certificate associated with the connection + if (connection != null) { + if (serverCertificates[0] != null) { + connection.setCertificate( + new SslCertificate(serverCertificates[0])); + } } } + + // get SSL session after the handshake + sessionAfterHandshake = + getSSLSession(sslContext, connection.getHost()); + } + + if (sessionBeforeHandshakeLastAccessedTime != 0 && + sessionAfterHandshake != null && + Arrays.equals( + sessionBeforeHandshakeId, sessionAfterHandshake.getId()) && + sessionBeforeHandshakeLastAccessedTime < + sessionAfterHandshake.getLastAccessedTime()) { + + if (HttpLog.LOGV) { + HttpLog.v("SSL session was reused: total reused: " + + sTotalReused + + " out of total of: " + sTotal); + + ++sTotalReused; + } + + // no errors!!! + return null; } // check if the first certificate in the chain is for this site @@ -152,6 +216,7 @@ class CertificateChainValidator { } } + // // first, we validate the chain using the standard validation // solution; if we do not find any errors, we are done; if we // fail the standard validation, we re-validate again below, @@ -328,14 +393,14 @@ class CertificateChainValidator { } private void closeSocketThrowException( - SSLSocket socket, String errorMessage, String defaultErrorMessage) - throws IOException { + SSLSocket socket, String errorMessage, String defaultErrorMessage) + throws SSLHandshakeException, IOException { closeSocketThrowException( socket, errorMessage != null ? errorMessage : defaultErrorMessage); } - private void closeSocketThrowException(SSLSocket socket, - String errorMessage) throws IOException { + private void closeSocketThrowException(SSLSocket socket, String errorMessage) + throws SSLHandshakeException, IOException { if (HttpLog.LOGV) { HttpLog.v("validation error: " + errorMessage); } @@ -351,4 +416,29 @@ class CertificateChainValidator { throw new SSLHandshakeException(errorMessage); } + + /** + * @param sslContext The SSL context shared accross all the SSL sessions + * @param host The host associated with the session + * @return A suitable SSL session from the SSL context + */ + private SSLSession getSSLSession(SSLContext sslContext, HttpHost host) { + if (sslContext != null && host != null) { + Enumeration en = sslContext.getClientSessionContext().getIds(); + while (en.hasMoreElements()) { + byte[] id = (byte[]) en.nextElement(); + if (id != null) { + SSLSession session = + sslContext.getClientSessionContext().getSession(id); + if (session.isValid() && + host.getHostName().equals(session.getPeerHost()) && + host.getPort() == session.getPeerPort()) { + return session; + } + } + } + } + + return null; + } } diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java index 7590bfef45355..6f9d6c674d015 100644 --- a/core/java/android/os/BatteryStats.java +++ b/core/java/android/os/BatteryStats.java @@ -16,8 +16,6 @@ import android.util.SparseArray; */ public abstract class BatteryStats implements Parcelable { - private static final boolean LOCAL_LOGV = false; - /** * A constant indicating a partial wake lock timer. */ @@ -74,7 +72,6 @@ public abstract class BatteryStats implements Parcelable { private static final String WAKELOCK_DATA = "wakelock"; private static final String NETWORK_DATA = "network"; private static final String BATTERY_DATA = "battery"; - private static final String MISC_DATA = "misc"; private final StringBuilder mFormatBuilder = new StringBuilder(8); private final Formatter mFormatter = new Formatter(mFormatBuilder); @@ -96,11 +93,11 @@ public abstract class BatteryStats implements Parcelable { * Returns the total time in microseconds associated with this Timer for the * selected type of statistics. * - * @param batteryRealtime system realtime on battery in microseconds + * @param now system uptime time in microseconds * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT * @return a time in microseconds */ - public abstract long getTotalTime(long batteryRealtime, int which); + public abstract long getTotalTime(long now, int which); /** * Temporary for debugging. @@ -225,11 +222,11 @@ public abstract class BatteryStats implements Parcelable { /** * Returns the amount of time spent started. * - * @param batteryUptime elapsed uptime on battery in microseconds. + * @param now elapsed realtime in microseconds. * @param which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. * @return */ - public abstract long getStartTime(long batteryUptime, int which); + public abstract long getStartTime(long now, int which); /** * Returns the total number of times startService() has been called. @@ -259,16 +256,16 @@ public abstract class BatteryStats implements Parcelable { * * {@hide} */ - public abstract long getScreenOnTime(long batteryRealtime, int which); + public abstract long getBatteryScreenOnTime(); /** - * Returns the time in milliseconds that the phone has been on while the device was - * running on battery. + * Returns the time in milliseconds that the screen has been on while the device was + * plugged in. * * {@hide} */ - public abstract long getPhoneOnTime(long batteryRealtime, int which); - + public abstract long getPluggedScreenOnTime(); + /** * Return whether we are currently running on battery. */ @@ -385,18 +382,18 @@ public abstract class BatteryStats implements Parcelable { * * @param sb a StringBuilder object. * @param timer a Timer object contining the wakelock times. - * @param batteryRealtime the current on-battery time in microseconds. + * @param now the current time in microseconds. * @param name the name of the wakelock. * @param which which one of STATS_TOTAL, STATS_LAST, or STATS_CURRENT. * @param linePrefix a String to be prepended to each line of output. * @return the line prefix */ - private static final String printWakeLock(StringBuilder sb, Timer timer, - long batteryRealtime, String name, int which, String linePrefix) { + private static final String printWakeLock(StringBuilder sb, Timer timer, long now, + String name, int which, String linePrefix) { if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTimeMicros = timer.getTotalTime(batteryRealtime, which); + long totalTimeMicros = timer.getTotalTime(now, which); long totalTimeMillis = (totalTimeMicros + 500) / 1000; int count = timer.getCount(which); @@ -473,30 +470,26 @@ public abstract class BatteryStats implements Parcelable { * @param which */ private final void dumpCheckinLocked(PrintWriter pw, int which) { - final long rawUptime = SystemClock.uptimeMillis() * 1000; - final long rawRealtime = SystemClock.elapsedRealtime() * 1000; - final long batteryUptime = getBatteryUptime(rawUptime); - final long batteryRealtime = getBatteryRealtime(rawRealtime); - final long whichBatteryUptime = computeBatteryUptime(rawUptime, which); - final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which); - final long totalRealtime = computeRealtime(rawRealtime, which); - final long totalUptime = computeUptime(rawUptime, which); - final long screenOnTime = getScreenOnTime(batteryRealtime, which); - final long phoneOnTime = getPhoneOnTime(batteryRealtime, which); + long uSecTime = SystemClock.elapsedRealtime() * 1000; + final long uSecNow = getBatteryUptime(uSecTime); StringBuilder sb = new StringBuilder(128); + long batteryUptime = computeBatteryUptime(uSecNow, which); + long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which); + long elapsedRealtime = computeRealtime(uSecTime, which); + long uptime = computeUptime(SystemClock.uptimeMillis() * 1000, which); String category = STAT_NAMES[which]; // Dump "battery" stat dumpLine(pw, 0 /* uid */, category, BATTERY_DATA, which == STATS_TOTAL ? getStartCount() : "N/A", - whichBatteryUptime / 1000, whichBatteryRealtime / 1000, - totalUptime / 1000, totalRealtime / 1000); - - // Dump misc stats - dumpLine(pw, 0 /* uid */, category, MISC_DATA, - screenOnTime / 1000, phoneOnTime / 1000); + batteryUptime / 1000, + formatRatioLocked(batteryUptime, elapsedRealtime), + batteryRealtime / 1000, + formatRatioLocked(batteryRealtime, elapsedRealtime), + uptime / 1000, + elapsedRealtime / 1000); SparseArray uidStats = getUidStats(); final int NU = uidStats.size(); @@ -515,11 +508,11 @@ public abstract class BatteryStats implements Parcelable { Uid.Wakelock wl = ent.getValue(); String linePrefix = ""; sb.setLength(0); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime, + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow, "full", which, linePrefix); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime, + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow, "partial", which, linePrefix); - linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime, + linePrefix = printWakeLockCheckin(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow, "window", which, linePrefix); // Only log if we had at lease one wakelock... @@ -538,7 +531,7 @@ public abstract class BatteryStats implements Parcelable { Timer timer = se.getSensorTime(); if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000; + long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000; int count = timer.getCount(which); if (totalTime != 0) { dumpLine(pw, uid, category, SENSOR_DATA, sensorNumber, totalTime, count); @@ -578,7 +571,7 @@ public abstract class BatteryStats implements Parcelable { for (Map.Entry sent : serviceStats.entrySet()) { BatteryStats.Uid.Pkg.Serv ss = sent.getValue(); - long startTime = ss.getStartTime(batteryUptime, which); + long startTime = ss.getStartTime(uSecNow, which); int starts = ss.getStarts(which); int launches = ss.getLaunches(which); if (startTime != 0 || starts != 0 || launches != 0) { @@ -598,40 +591,29 @@ public abstract class BatteryStats implements Parcelable { @SuppressWarnings("unused") private final void dumpLocked(Printer pw, String prefix, int which) { - final long rawUptime = SystemClock.uptimeMillis() * 1000; - final long rawRealtime = SystemClock.elapsedRealtime() * 1000; - final long batteryUptime = getBatteryUptime(rawUptime); - final long batteryRealtime = getBatteryUptime(rawRealtime); + long uSecTime = SystemClock.elapsedRealtime() * 1000; + final long uSecNow = getBatteryUptime(uSecTime); - final long whichBatteryUptime = computeBatteryUptime(rawUptime, which); - final long whichBatteryRealtime = computeBatteryRealtime(rawRealtime, which); - final long totalRealtime = computeRealtime(rawRealtime, which); - final long totalUptime = computeUptime(rawUptime, which); - StringBuilder sb = new StringBuilder(128); + long batteryUptime = computeBatteryUptime(uSecNow, which); + long batteryRealtime = computeBatteryRealtime(getBatteryRealtime(uSecTime), which); + long elapsedRealtime = computeRealtime(uSecTime, which); + long uptime = computeUptime(SystemClock.uptimeMillis() * 1000, which); pw.println(prefix - + " Time on battery: " + formatTimeMs(whichBatteryUptime / 1000) - + "(" + formatRatioLocked(whichBatteryUptime, totalRealtime) + + " Time on battery: " + formatTimeMs(batteryUptime / 1000) + "(" + + formatRatioLocked(batteryUptime, elapsedRealtime) + ") uptime, " - + formatTimeMs(whichBatteryRealtime / 1000) + "(" - + formatRatioLocked(whichBatteryRealtime, totalRealtime) + + formatTimeMs(batteryRealtime / 1000) + "(" + + formatRatioLocked(batteryRealtime, elapsedRealtime) + ") realtime"); pw.println(prefix + " Total: " - + formatTimeMs(totalUptime / 1000) + + formatTimeMs(uptime / 1000) + "uptime, " - + formatTimeMs(totalRealtime / 1000) + + formatTimeMs(elapsedRealtime / 1000) + "realtime"); - long screenOnTime = getScreenOnTime(batteryRealtime, which); - long phoneOnTime = getPhoneOnTime(batteryRealtime, which); - pw.println(prefix - + " Time with screen on: " + formatTimeMs(screenOnTime / 1000) - + "(" + formatRatioLocked(screenOnTime, whichBatteryRealtime) - + "), time with phone on: " + formatTimeMs(phoneOnTime / 1000) - + "(" + formatRatioLocked(phoneOnTime, whichBatteryRealtime) + ")"); - pw.println(" "); SparseArray uidStats = getUidStats(); @@ -659,11 +641,11 @@ public abstract class BatteryStats implements Parcelable { sb.append(prefix); sb.append(" Wake lock "); sb.append(ent.getKey()); - linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), batteryRealtime, + linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_FULL), uSecNow, "full", which, linePrefix); - linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), batteryRealtime, + linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_PARTIAL), uSecNow, "partial", which, linePrefix); - linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), batteryRealtime, + linePrefix = printWakeLock(sb, wl.getWakeTime(WAKE_TYPE_WINDOW), uSecNow, "window", which, linePrefix); if (!linePrefix.equals(": ")) { sb.append(" realtime"); @@ -695,7 +677,7 @@ public abstract class BatteryStats implements Parcelable { Timer timer = se.getSensorTime(); if (timer != null) { // Convert from microseconds to milliseconds with rounding - long totalTime = (timer.getTotalTime(batteryRealtime, which) + 500) / 1000; + long totalTime = (timer.getTotalTime(uSecNow, which) + 500) / 1000; int count = timer.getCount(which); //timer.logState(); if (totalTime != 0) { @@ -755,7 +737,7 @@ public abstract class BatteryStats implements Parcelable { for (Map.Entry sent : serviceStats.entrySet()) { BatteryStats.Uid.Pkg.Serv ss = sent.getValue(); - long startTime = ss.getStartTime(batteryUptime, which); + long startTime = ss.getStartTime(uSecNow, which); int starts = ss.getStarts(which); int launches = ss.getLaunches(which); if (startTime != 0 || starts != 0 || launches != 0) { @@ -805,24 +787,9 @@ public abstract class BatteryStats implements Parcelable { @SuppressWarnings("unused") public void dumpCheckinLocked(PrintWriter pw, String[] args) { - boolean isUnpluggedOnly = false; - - for (String arg : args) { - if ("-u".equals(arg)) { - if (LOCAL_LOGV) Log.v("BatteryStats", "Dumping unplugged data"); - isUnpluggedOnly = true; - } - } - - if (isUnpluggedOnly) { - dumpCheckinLocked(pw, STATS_UNPLUGGED); - } - else { - dumpCheckinLocked(pw, STATS_TOTAL); - dumpCheckinLocked(pw, STATS_LAST); - dumpCheckinLocked(pw, STATS_UNPLUGGED); - dumpCheckinLocked(pw, STATS_CURRENT); - } + dumpCheckinLocked(pw, STATS_TOTAL); + dumpCheckinLocked(pw, STATS_LAST); + dumpCheckinLocked(pw, STATS_UNPLUGGED); + dumpCheckinLocked(pw, STATS_CURRENT); } - } diff --git a/core/java/android/os/ParcelFileDescriptor.java b/core/java/android/os/ParcelFileDescriptor.java index 3fcb18e4a5330..ed138cb6788f6 100644 --- a/core/java/android/os/ParcelFileDescriptor.java +++ b/core/java/android/os/ParcelFileDescriptor.java @@ -75,11 +75,6 @@ public class ParcelFileDescriptor implements Parcelable { */ public static final int MODE_TRUNCATE = 0x04000000; - /** - * For use with {@link #open}: append to end of file while writing. - */ - public static final int MODE_APPEND = 0x02000000; - /** * Create a new ParcelFileDescriptor accessing a given file. * @@ -142,19 +137,6 @@ public class ParcelFileDescriptor implements Parcelable { return mFileDescriptor; } - /** - * Return the total size of the file representing this fd, as determined - * by stat(). Returns -1 if the fd is not a file. - */ - public native long getStatSize(); - - /** - * This is needed for implementing AssetFileDescriptor.AutoCloseOutputStream, - * and I really don't think we want it to be public. - * @hide - */ - public native long seekTo(long pos); - /** * Close the ParcelFileDescriptor. This implementation closes the underlying * OS resources allocated to represent this stream. diff --git a/core/java/android/pim/ICalendar.java b/core/java/android/pim/ICalendar.java index cc0f45ee24021..4a5d7e487f58d 100644 --- a/core/java/android/pim/ICalendar.java +++ b/core/java/android/pim/ICalendar.java @@ -405,15 +405,13 @@ public class ICalendar { // TODO: get rid of this -- handle all of the parsing in one pass through // the text. private static String normalizeText(String text) { + // first we deal with line folding, by replacing all "\r\n " strings + // with nothing + text = text.replaceAll("\r\n ", ""); + // it's supposed to be \r\n, but not everyone does that text = text.replaceAll("\r\n", "\n"); text = text.replaceAll("\r", "\n"); - - // we deal with line folding, by replacing all "\n " strings - // with nothing. The RFC specifies "\r\n " to be folded, but - // we handle "\n " and "\r " too because we can get those. - text = text.replaceAll("\n ", ""); - return text; } @@ -442,7 +440,7 @@ public class ICalendar { current = parseLine(line, state, current); // if the provided component was null, we will return the root // NOTE: in this case, if the first line is not a BEGIN, a - // FormatException will get thrown. + // FormatException will get thrown. if (component == null) { component = current; } @@ -526,7 +524,8 @@ public class ICalendar { private static String extractValue(ParserState state) throws FormatException { String line = state.line; - if (state.index >= line.length() || line.charAt(state.index) != ':') { + char c = line.charAt(state.index); + if (c != ':') { throw new FormatException("Expected ':' before end of line in " + line); } diff --git a/core/java/android/provider/Checkin.java b/core/java/android/provider/Checkin.java index 1454089e70baa..0cdac53525bd8 100644 --- a/core/java/android/provider/Checkin.java +++ b/core/java/android/provider/Checkin.java @@ -62,9 +62,6 @@ public final class Checkin { AUTOTEST_FAILURE, AUTOTEST_SEQUENCE_BEGIN, AUTOTEST_SUITE_BEGIN, - AUTOTEST_TCPDUMP_BEGIN, - AUTOTEST_TCPDUMP_DATA, - AUTOTEST_TCPDUMP_END, AUTOTEST_TEST_BEGIN, AUTOTEST_TEST_FAILURE, AUTOTEST_TEST_SUCCESS, @@ -101,14 +98,14 @@ public final class Checkin { SETUP_SERVER_ERROR, SETUP_SERVER_TIMEOUT, SETUP_NO_DATA_NETWORK, + SYSTEM_APP_NOT_RESPONDING, SYSTEM_BOOT, SYSTEM_LAST_KMSG, SYSTEM_RECOVERY_LOG, SYSTEM_RESTART, SYSTEM_SERVICE_LOOPING, SYSTEM_TOMBSTONE, - TEST, - BATTERY_DISCHARGE_INFO, + TEST, } } @@ -193,9 +190,6 @@ public final class Checkin { // The category is used for GTalk service messages public static final String CATEGORY = "android.server.checkin.CHECKIN"; - - // If true indicates that the checkin should only transfer market related data - public static final String EXTRA_MARKET_ONLY = "market_only"; } private static final String TAG = "Checkin"; diff --git a/core/java/android/provider/Im.java b/core/java/android/provider/Im.java index 19ad15874dcff..bea857feeaf86 100644 --- a/core/java/android/provider/Im.java +++ b/core/java/android/provider/Im.java @@ -2044,37 +2044,4 @@ public class Im { */ public static final Uri CONTENT_URI = Uri.parse("content://im/lastRmqId"); } - - /** - * Columns for IM branding resource map cache table. This table caches the result of - * loading the branding resources to speed up IM landing page start. - */ - public interface BrandingResourceMapCacheColumns { - /** - * The provider ID - *

    Type: INTEGER

    - */ - String PROVIDER_ID = "provider_id"; - /** - * The application resource ID - *

    Type: INTEGER

    - */ - String APP_RES_ID = "app_res_id"; - /** - * The plugin resource ID - *

    Type: INTEGER

    - */ - String PLUGIN_RES_ID = "plugin_res_id"; - } - - /** - * The table for caching the result of loading IM branding resources. - */ - public static final class BrandingResourceMapCache - implements BaseColumns, BrandingResourceMapCacheColumns { - /** - * The content:// style URL for this table. - */ - public static final Uri CONTENT_URI = Uri.parse("content://im/brandingResMapCache"); - } } diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 10ca5d547b2a4..4a784c8bd210d 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -2182,12 +2182,6 @@ public final class Settings { */ public static final String CHECKIN_INTERVAL = "checkin_interval"; - /** - * Boolean indicating if the market app should force market only checkins on - * install/uninstall. Any non-0 value is considered true. - */ - public static final String MARKET_FORCE_CHECKIN = "market_force_checkin"; - /** * How frequently (in seconds) to check the memory status of the * device. @@ -2460,14 +2454,6 @@ public final class Settings { public static final String GTALK_SSL_HANDSHAKE_TIMEOUT_MS = "gtalk_ssl_handshake_timeout_ms"; - /** - * Enable use of ssl session caching. - * 'db' - save each session in a per-process database - * not set or any other value - normal java in-memory caching. - * Other cache types may be added. - */ - public static final String SSL_SESSION_CACHE = "ssl_session_cache"; - /** * How many bytes long a message has to be, in order to be gzipped. */ @@ -2780,29 +2766,11 @@ public final class Settings { public static final String VOICE_SEARCH_ENCODING_WIFI = "voice_search_encoding_wifi"; /** - * Whether to use automatic gain control in voice search (0 = disable, 1 = enable). - * To be factored out of this class. + * Prefix for rules that launch automatic instrumentation test cycles. + * The format is the InstrumentationTestRunner (or compatible) package and class, + * followed optionally by space-separated key value pairs to pass to it. */ - public static final String VOICE_SEARCH_ENABLE_AGC = "voice_search_enable_agc"; - - /** - * Whether to use noise suppression in voice search (0 = disable, 1 = enable). - * To be factored out of this class. - */ - public static final String VOICE_SEARCH_ENABLE_NS = "voice_search_enable_ns"; - - /** - * Whether to use the IIR filter in voice search (0 = disable, 1 = enable). - * To be factored out of this class. - */ - public static final String VOICE_SEARCH_ENABLE_IIR = "voice_search_enable_iir"; - - /** - * List of test suites (local disk filename) for the automatic instrumentation test runner. - * The file format is similar to automated_suites.xml, see AutoTesterService. - * If this setting is missing or empty, the automatic test runner will not start. - */ - public static final String AUTOTEST_SUITES_FILE = "autotest_suites_file"; + public static final String AUTOTEST_PREFIX = "autotest:"; /** * Interval between synchronous checkins forced by the automatic test runner. @@ -2817,15 +2785,6 @@ public final class Settings { */ public static final String AUTOTEST_REBOOT_SECONDS = "autotest_reboot_seconds"; - - /** - * Threshold values for the duration and level of a discharge cycle, under - * which we log discharge cycle info. - */ - public static final String BATTERY_DISCHARGE_DURATION_THRESHOLD = - "battery_discharge_duration_threshold"; - public static final String BATTERY_DISCHARGE_THRESHOLD = "battery_discharge_threshold"; - /** * @deprecated * @hide diff --git a/core/java/android/server/BluetoothA2dpService.java b/core/java/android/server/BluetoothA2dpService.java index f8bc765e0a047..58f9491b98ff8 100644 --- a/core/java/android/server/BluetoothA2dpService.java +++ b/core/java/android/server/BluetoothA2dpService.java @@ -15,7 +15,8 @@ */ /** - * TODO: Move this to services.jar + * TODO: Move this to + * java/services/com/android/server/BluetoothA2dpService.java * and make the contructor package private again. * @hide */ @@ -34,16 +35,15 @@ import android.content.IntentFilter; import android.content.pm.PackageManager; import android.media.AudioManager; import android.os.Binder; -import android.os.Handler; -import android.os.Message; import android.provider.Settings; import android.util.Log; import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; +import java.util.HashMap; +import java.util.Iterator; public class BluetoothA2dpService extends IBluetoothA2dp.Stub { private static final String TAG = "BluetoothA2dpService"; @@ -57,8 +57,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { private static final String A2DP_SINK_ADDRESS = "a2dp_sink_address"; private static final String BLUETOOTH_ENABLED = "bluetooth_enabled"; - private static final int MESSAGE_CONNECT_TO = 1; - private final Context mContext; private final IntentFilter mIntentFilter; private HashMap mAudioDevices; @@ -88,7 +86,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { mIntentFilter = new IntentFilter(BluetoothIntent.ENABLED_ACTION); mIntentFilter.addAction(BluetoothIntent.DISABLED_ACTION); mIntentFilter.addAction(BluetoothIntent.BOND_STATE_CHANGED_ACTION); - mIntentFilter.addAction(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION); mContext.registerReceiver(mReceiver, mIntentFilter); if (device.isEnabled()) { @@ -126,37 +123,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { setSinkPriority(address, BluetoothA2dp.PRIORITY_OFF); break; } - } else if (action.equals(BluetoothIntent.REMOTE_DEVICE_CONNECTED_ACTION)) { - if (getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF) { - // This device is a preferred sink. Make an A2DP connection - // after a delay. We delay to avoid connection collisions, - // and to give other profiles such as HFP a chance to - // connect first. - Message msg = Message.obtain(mHandler, MESSAGE_CONNECT_TO, address); - mHandler.sendMessageDelayed(msg, 6000); - } - } - } - }; - - private final Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MESSAGE_CONNECT_TO: - String address = (String)msg.obj; - // check device is still preferred, and nothing is currently - // connected - if (getSinkPriority(address) > BluetoothA2dp.PRIORITY_OFF && - lookupSinksMatchingStates(new int[] { - BluetoothA2dp.STATE_CONNECTING, - BluetoothA2dp.STATE_CONNECTED, - BluetoothA2dp.STATE_PLAYING, - BluetoothA2dp.STATE_DISCONNECTING}).size() == 0) { - log("Auto-connecting A2DP to sink " + address); - connectSink(address); - } - break; } } }; @@ -176,10 +142,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { private synchronized void onBluetoothDisable() { if (mAudioDevices != null) { - // copy to allow modification during iteration - String[] paths = new String[mAudioDevices.size()]; - paths = mAudioDevices.keySet().toArray(paths); - for (String path : paths) { + for (String path : mAudioDevices.keySet()) { switch (mAudioDevices.get(path).state) { case BluetoothA2dp.STATE_CONNECTING: case BluetoothA2dp.STATE_CONNECTED: @@ -271,8 +234,17 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { public synchronized List listConnectedSinks() { mContext.enforceCallingOrSelfPermission(BLUETOOTH_PERM, "Need BLUETOOTH permission"); - return lookupSinksMatchingStates(new int[] {BluetoothA2dp.STATE_CONNECTED, - BluetoothA2dp.STATE_PLAYING}); + List connectedSinks = new ArrayList(); + if (mAudioDevices == null) { + return connectedSinks; + } + for (SinkState sink : mAudioDevices.values()) { + if (sink.state == BluetoothA2dp.STATE_CONNECTED || + sink.state == BluetoothA2dp.STATE_PLAYING) { + connectedSinks.add(sink.address); + } + } + return connectedSinks; } public synchronized int getSinkState(String address) { @@ -326,11 +298,7 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { // bluez 3.36 quietly disconnects the previous sink when a new sink // is connected, so we need to mark all previously connected sinks as // disconnected - - // copy to allow modification during iteration - String[] paths = new String[mAudioDevices.size()]; - paths = mAudioDevices.keySet().toArray(paths); - for (String oldPath : paths) { + for (String oldPath : mAudioDevices.keySet()) { if (path.equals(oldPath)) { continue; } @@ -382,22 +350,6 @@ public class BluetoothA2dpService extends IBluetoothA2dp.Stub { return null; } - private synchronized List lookupSinksMatchingStates(int[] states) { - List sinks = new ArrayList(); - if (mAudioDevices == null) { - return sinks; - } - for (SinkState sink : mAudioDevices.values()) { - for (int state : states) { - if (sink.state == state) { - sinks.add(sink.address); - break; - } - } - } - return sinks; - } - private synchronized void updateState(String path, int state) { if (mAudioDevices == null) return; diff --git a/core/java/android/server/BluetoothDeviceService.java b/core/java/android/server/BluetoothDeviceService.java index 950ff3a9adfbb..fa53a601077e2 100644 --- a/core/java/android/server/BluetoothDeviceService.java +++ b/core/java/android/server/BluetoothDeviceService.java @@ -141,20 +141,6 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { mBondState.setBondState(address, BluetoothDevice.BOND_NOT_BONDED, BluetoothDevice.UNBOND_REASON_AUTH_CANCELED); } - - // Remove remoteServiceChannelCallbacks - HashMap callbacksMap = - mEventLoop.getRemoteServiceChannelCallbacks(); - IBluetoothDeviceCallback callback; - - for (String address : callbacksMap.keySet()) { - callback = callbacksMap.get(address); - try { - callback.onGetRemoteServiceChannelResult(address, BluetoothError.ERROR_DISABLED); - } catch (RemoteException e) {} - callbacksMap.remove(address); - } - // update mode Intent intent = new Intent(BluetoothIntent.SCAN_MODE_CHANGED_ACTION); intent.putExtra(BluetoothIntent.SCAN_MODE, BluetoothDevice.SCAN_MODE_NONE); @@ -583,18 +569,10 @@ public class BluetoothDeviceService extends IBluetoothDevice.Stub { } address = address.toUpperCase(); - String[] bonding = mBondState.listInState(BluetoothDevice.BOND_BONDING); - if (bonding.length > 0 && !bonding[0].equals(address)) { - log("Ignoring createBond(): another device is bonding"); - // a different device is currently bonding, fail - return false; - } - // Check for bond state only if we are not performing auto // pairing exponential back-off attempts. if (!mBondState.isAutoPairingAttemptsInProgress(address) && - mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) { - log("Ignoring createBond(): this device is already bonding or bonded"); + mBondState.getBondState(address) != BluetoothDevice.BOND_NOT_BONDED) { return false; } diff --git a/core/java/android/server/search/SearchableInfo.java b/core/java/android/server/search/SearchableInfo.java index 0c04839a4472b..c18675ef13e9f 100644 --- a/core/java/android/server/search/SearchableInfo.java +++ b/core/java/android/server/search/SearchableInfo.java @@ -35,7 +35,6 @@ import android.text.InputType; import android.util.AttributeSet; import android.util.Log; import android.util.Xml; -import android.view.inputmethod.EditorInfo; import java.io.IOException; import java.util.ArrayList; @@ -78,7 +77,6 @@ public final class SearchableInfo implements Parcelable { private int mIconId = 0; private int mSearchButtonText = 0; private int mSearchInputType = 0; - private int mSearchImeOptions = 0; private String mSuggestAuthority = null; private String mSuggestPath = null; private String mSuggestSelection = null; @@ -431,9 +429,8 @@ public final class SearchableInfo implements Parcelable { com.android.internal.R.styleable.Searchable_searchButtonText, 0); mSearchInputType = a.getInt(com.android.internal.R.styleable.Searchable_inputType, InputType.TYPE_CLASS_TEXT | + InputType.TYPE_TEXT_FLAG_SEARCH | InputType.TYPE_TEXT_VARIATION_NORMAL); - mSearchImeOptions = a.getInt(com.android.internal.R.styleable.Searchable_imeOptions, - EditorInfo.IME_ACTION_SEARCH); setSearchModeFlags(); if (DBG_INHIBIT_SUGGESTIONS == 0) { @@ -745,17 +742,6 @@ public final class SearchableInfo implements Parcelable { return mSearchInputType; } - /** - * Return the input method options specified in the searchable attributes. - * This will default to EditorInfo.ACTION_SEARCH if not specified (which is - * appropriate for a search box). - * - * @return the input type - */ - public int getImeOptions() { - return mSearchImeOptions; - } - /** * Return the list of searchable activities, for use in the drop-down. */ @@ -796,7 +782,6 @@ public final class SearchableInfo implements Parcelable { mIconId = in.readInt(); mSearchButtonText = in.readInt(); mSearchInputType = in.readInt(); - mSearchImeOptions = in.readInt(); setSearchModeFlags(); mSuggestAuthority = in.readString(); @@ -833,7 +818,6 @@ public final class SearchableInfo implements Parcelable { dest.writeInt(mIconId); dest.writeInt(mSearchButtonText); dest.writeInt(mSearchInputType); - dest.writeInt(mSearchImeOptions); dest.writeString(mSuggestAuthority); dest.writeString(mSuggestPath); diff --git a/core/java/android/speech/srec/package.html b/core/java/android/speech/srec/package.html index 9a99df85a9064..723b30bb6e9e6 100644 --- a/core/java/android/speech/srec/package.html +++ b/core/java/android/speech/srec/package.html @@ -1,6 +1,5 @@ Simple, synchronous SREC speech recognition API. -@hide diff --git a/core/java/android/text/InputType.java b/core/java/android/text/InputType.java index f643f9256c989..a073cf49081c9 100644 --- a/core/java/android/text/InputType.java +++ b/core/java/android/text/InputType.java @@ -128,6 +128,11 @@ public interface InputType { */ public static final int TYPE_TEXT_FLAG_IME_MULTI_LINE = 0x00040000; + /** + * Flag for {@link #TYPE_CLASS_TEXT}: flags any text being used as a search string + */ + public static final int TYPE_TEXT_FLAG_SEARCH = 0x00080000; + // ---------------------------------------------------------------------- /** diff --git a/core/java/android/text/Styled.java b/core/java/android/text/Styled.java index 0aa2004fa2584..05c27ea90c5ec 100644 --- a/core/java/android/text/Styled.java +++ b/core/java/android/text/Styled.java @@ -16,26 +16,25 @@ package android.text; -import android.graphics.Canvas; import android.graphics.Paint; -import android.text.style.CharacterStyle; -import android.text.style.MetricAffectingSpan; -import android.text.style.ReplacementSpan; +import android.graphics.Canvas; +import android.graphics.Path; +import android.graphics.RectF; +import android.graphics.Typeface; +import android.graphics.MaskFilter; +import android.graphics.Rasterizer; +import android.graphics.LayerRasterizer; +import android.text.style.*; -/** - * This class provides static methods for drawing and measuring styled texts, like - * {@link android.text.Spanned} object with {@link android.text.style.ReplacementSpan}. - * @hide - */ -public class Styled +/* package */ class Styled { private static float each(Canvas canvas, Spanned text, int start, int end, int dir, boolean reverse, float x, int top, int y, int bottom, - Paint.FontMetricsInt fmi, + Paint.FontMetricsInt fm, + TextPaint realPaint, TextPaint paint, - TextPaint workPaint, boolean needwid) { boolean havewid = false; @@ -44,9 +43,9 @@ public class Styled ReplacementSpan replacement = null; - paint.bgColor = 0; - paint.baselineShift = 0; - workPaint.set(paint); + realPaint.bgColor = 0; + realPaint.baselineShift = 0; + paint.set(realPaint); if (spans.length > 0) { for (int i = 0; i < spans.length; i++) { @@ -56,7 +55,7 @@ public class Styled replacement = (ReplacementSpan)span; } else { - span.updateDrawState(workPaint); + span.updateDrawState(paint); } } } @@ -75,66 +74,66 @@ public class Styled tmpend = end; } - if (fmi != null) { - workPaint.getFontMetricsInt(fmi); + if (fm != null) { + paint.getFontMetricsInt(fm); } if (canvas != null) { - if (workPaint.bgColor != 0) { - int c = workPaint.getColor(); - Paint.Style s = workPaint.getStyle(); - workPaint.setColor(workPaint.bgColor); - workPaint.setStyle(Paint.Style.FILL); + if (paint.bgColor != 0) { + int c = paint.getColor(); + Paint.Style s = paint.getStyle(); + paint.setColor(paint.bgColor); + paint.setStyle(Paint.Style.FILL); if (!havewid) { - ret = workPaint.measureText(tmp, tmpstart, tmpend); + ret = paint.measureText(tmp, tmpstart, tmpend); havewid = true; } if (dir == Layout.DIR_RIGHT_TO_LEFT) - canvas.drawRect(x - ret, top, x, bottom, workPaint); + canvas.drawRect(x - ret, top, x, bottom, paint); else - canvas.drawRect(x, top, x + ret, bottom, workPaint); + canvas.drawRect(x, top, x + ret, bottom, paint); - workPaint.setStyle(s); - workPaint.setColor(c); + paint.setStyle(s); + paint.setColor(c); } if (dir == Layout.DIR_RIGHT_TO_LEFT) { if (!havewid) { - ret = workPaint.measureText(tmp, tmpstart, tmpend); + ret = paint.measureText(tmp, tmpstart, tmpend); havewid = true; } canvas.drawText(tmp, tmpstart, tmpend, - x - ret, y + workPaint.baselineShift, workPaint); + x - ret, y + paint.baselineShift, paint); } else { if (needwid) { if (!havewid) { - ret = workPaint.measureText(tmp, tmpstart, tmpend); + ret = paint.measureText(tmp, tmpstart, tmpend); havewid = true; } } canvas.drawText(tmp, tmpstart, tmpend, - x, y + workPaint.baselineShift, workPaint); + x, y + paint.baselineShift, paint); } } else { if (needwid && !havewid) { - ret = workPaint.measureText(tmp, tmpstart, tmpend); + ret = paint.measureText(tmp, tmpstart, tmpend); havewid = true; } } } else { - ret = replacement.getSize(workPaint, text, start, end, fmi); + ret = replacement.getSize(paint, text, start, end, fm); if (canvas != null) { if (dir == Layout.DIR_RIGHT_TO_LEFT) replacement.draw(canvas, text, start, end, - x - ret, top, y, bottom, workPaint); + x - ret, top, y, bottom, paint); else replacement.draw(canvas, text, start, end, - x, top, y, bottom, workPaint); + x, top, y, bottom, paint); } } @@ -144,29 +143,15 @@ public class Styled return ret; } - /** - * Return the advance widths for the characters in the string. - * See also {@link android.graphics.Paint#getTextWidths(CharSequence, int, int, float[])}. - * - * @param paint The main {@link TextPaint} object. - * @param workPaint The {@link TextPaint} object used for temporal workspace. - * @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 (end - start). - * @param fmi FontMetrics information. Can be null. - * @return The actual number of widths returned. - */ - public static int getTextWidths(TextPaint paint, - TextPaint workPaint, - Spanned text, int start, int end, - float[] widths, Paint.FontMetricsInt fmi) { - // Keep workPaint as is so that developers reuse the workspace. + public static int getTextWidths(TextPaint realPaint, + TextPaint paint, + Spanned text, int start, int end, + float[] widths, Paint.FontMetricsInt fm) { + MetricAffectingSpan[] spans = text.getSpans(start, end, MetricAffectingSpan.class); ReplacementSpan replacement = null; - workPaint.set(paint); + paint.set(realPaint); for (int i = 0; i < spans.length; i++) { MetricAffectingSpan span = spans[i]; @@ -174,15 +159,15 @@ public class Styled replacement = (ReplacementSpan)span; } else { - span.updateMeasureState(workPaint); + span.updateMeasureState(paint); } } if (replacement == null) { - workPaint.getFontMetricsInt(fmi); - workPaint.getTextWidths(text, start, end, widths); + paint.getFontMetricsInt(fm); + paint.getTextWidths(text, start, end, widths); } else { - int wid = replacement.getSize(workPaint, text, start, end, fmi); + int wid = replacement.getSize(paint, text, start, end, fm); if (end > start) { widths[0] = wid; @@ -198,10 +183,10 @@ public class Styled CharSequence text, int start, int end, int dir, boolean reverse, float x, int top, int y, int bottom, - Paint.FontMetricsInt fmi, + Paint.FontMetricsInt fm, TextPaint paint, TextPaint workPaint, - boolean needWidth) { + boolean needwid) { if (! (text instanceof Spanned)) { float ret = 0; @@ -209,22 +194,22 @@ public class Styled CharSequence tmp = TextUtils.getReverse(text, start, end); int tmpend = end - start; - if (canvas != null || needWidth) + if (canvas != null || needwid) ret = paint.measureText(tmp, 0, tmpend); if (canvas != null) canvas.drawText(tmp, 0, tmpend, x - ret, y, paint); } else { - if (needWidth) + if (needwid) ret = paint.measureText(text, start, end); if (canvas != null) canvas.drawText(text, start, end, x, y, paint); } - if (fmi != null) { - paint.getFontMetricsInt(fmi); + if (fm != null) { + paint.getFontMetricsInt(fm); } return ret * dir; //Layout.DIR_RIGHT_TO_LEFT == -1 @@ -247,129 +232,67 @@ public class Styled next = sp.nextSpanTransition(i, end, division); x += each(canvas, sp, i, next, dir, reverse, - x, top, y, bottom, fmi, paint, workPaint, - needWidth || next != end); + x, top, y, bottom, fm, paint, workPaint, + needwid || next != end); - if (fmi != null) { - if (fmi.ascent < asc) - asc = fmi.ascent; - if (fmi.descent > desc) - desc = fmi.descent; + if (fm != null) { + if (fm.ascent < asc) + asc = fm.ascent; + if (fm.descent > desc) + desc = fm.descent; - if (fmi.top < ftop) - ftop = fmi.top; - if (fmi.bottom > fbot) - fbot = fmi.bottom; + if (fm.top < ftop) + ftop = fm.top; + if (fm.bottom > fbot) + fbot = fm.bottom; } } - if (fmi != null) { + if (fm != null) { if (start == end) { - paint.getFontMetricsInt(fmi); + paint.getFontMetricsInt(fm); } else { - fmi.ascent = asc; - fmi.descent = desc; - fmi.top = ftop; - fmi.bottom = fbot; + fm.ascent = asc; + fm.descent = desc; + fm.top = ftop; + fm.bottom = fbot; } } return x - ox; } - - /* package */ static float drawText(Canvas canvas, - CharSequence text, int start, int end, - int direction, boolean reverse, - float x, int top, int y, int bottom, - TextPaint paint, - TextPaint workPaint, - boolean needWidth) { - if ((direction == Layout.DIR_RIGHT_TO_LEFT && !reverse) || - (reverse && direction == Layout.DIR_LEFT_TO_RIGHT)) { + public static float drawText(Canvas canvas, + CharSequence text, int start, int end, + int dir, boolean reverse, + float x, int top, int y, int bottom, + TextPaint paint, + TextPaint workPaint, + boolean needwid) { + if ((dir == Layout.DIR_RIGHT_TO_LEFT && !reverse)||(reverse && dir == Layout.DIR_LEFT_TO_RIGHT)) { float ch = foreach(null, text, start, end, Layout.DIR_LEFT_TO_RIGHT, false, 0, 0, 0, 0, null, paint, workPaint, true); - ch *= direction; // DIR_RIGHT_TO_LEFT == -1 - foreach(canvas, text, start, end, -direction, + ch *= dir; // DIR_RIGHT_TO_LEFT == -1 + foreach(canvas, text, start, end, -dir, reverse, x + ch, top, y, bottom, null, paint, workPaint, true); return ch; } - return foreach(canvas, text, start, end, direction, reverse, + return foreach(canvas, text, start, end, dir, reverse, x, top, y, bottom, null, paint, workPaint, - needWidth); + needwid); } - - /** - * Draw the specified range of text, specified by start/end, with its origin at (x,y), - * in the specified Paint. The origin is interpreted based on the Align setting in the - * Paint. - * - * This method considers style information in the text - * (e.g. Even when text is an instance of {@link android.text.Spanned}, this method - * correctly draws the text). - * See also - * {@link android.graphics.Canvas#drawText(CharSequence, int, int, float, float, Paint)} - * and - * {@link android.graphics.Canvas#drawRect(float, float, float, float, Paint)}. - * - * @param canvas The target canvas. - * @param text The text to be drawn - * @param start The index of the first character in text to draw - * @param end (end - 1) is the index of the last character in text to draw - * @param direction The direction of the text. This must be - * {@link android.text.Layout#DIR_LEFT_TO_RIGHT} or - * {@link android.text.Layout#DIR_RIGHT_TO_LEFT}. - * @param x The x-coordinate of origin for where to draw the text - * @param top The top side of the rectangle to be drawn - * @param y The y-coordinate of origin for where to draw the text - * @param bottom The bottom side of the rectangle to be drawn - * @param paint The main {@link TextPaint} object. - * @param workPaint The {@link TextPaint} object used for temporal workspace. - * @param needWidth If true, this method returns the width of drawn text. - * @return Width of the drawn text if needWidth is true. - */ - public static float drawText(Canvas canvas, - CharSequence text, int start, int end, - int direction, - float x, int top, int y, int bottom, - TextPaint paint, - TextPaint workPaint, - boolean needWidth) { - // For safety. - direction = direction >= 0 ? Layout.DIR_LEFT_TO_RIGHT : Layout.DIR_RIGHT_TO_LEFT; - /* - * Hided "reverse" parameter since it is meaningless for external developers. - * Kept workPaint as is so that developers reuse the workspace. - */ - return drawText(canvas, text, start, end, direction, false, - x, top, y, bottom, paint, workPaint, needWidth); - } - - /** - * Return the width of the text, considering style information in the text - * (e.g. Even when text is an instance of {@link android.text.Spanned}, this method - * correctly mesures the width of the text). - * - * @param paint The main {@link TextPaint} object. - * @param workPaint The {@link TextPaint} object used for temporal workspace. - * @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 - * @param fmi FontMetrics information. Can be null - * @return The width of the text - */ + public static float measureText(TextPaint paint, TextPaint workPaint, CharSequence text, int start, int end, - Paint.FontMetricsInt fmi) { - // Keep workPaint as is so that developers reuse the workspace. + Paint.FontMetricsInt fm) { return foreach(null, text, start, end, Layout.DIR_LEFT_TO_RIGHT, false, - 0, 0, 0, 0, fmi, paint, workPaint, true); + 0, 0, 0, 0, fm, paint, workPaint, true); } } diff --git a/core/java/android/text/format/DateUtils.java b/core/java/android/text/format/DateUtils.java index 8a7cdd92950f1..feae6cf52a6f5 100644 --- a/core/java/android/text/format/DateUtils.java +++ b/core/java/android/text/format/DateUtils.java @@ -595,17 +595,6 @@ public class DateUtils * @param elapsedSeconds the elapsed time in seconds. */ public static String formatElapsedTime(long elapsedSeconds) { - return formatElapsedTime(null, elapsedSeconds); - } - - /** - * Formats an elapsed time in the form "MM:SS" or "H:MM:SS" - * for display on the call-in-progress screen. - * - * @param recycle {@link StringBuilder} to recycle, if possible - * @param elapsedSeconds the elapsed time in seconds. - */ - public static String formatElapsedTime(StringBuilder recycle, long elapsedSeconds) { initFormatStrings(); long hours = 0; @@ -624,24 +613,18 @@ public class DateUtils String result; if (hours > 0) { - return formatElapsedTime(recycle, sElapsedFormatHMMSS, hours, minutes, seconds); + return formatElapsedTime(sElapsedFormatHMMSS, hours, minutes, seconds); } else { - return formatElapsedTime(recycle, sElapsedFormatMMSS, minutes, seconds); + return formatElapsedTime(sElapsedFormatMMSS, minutes, seconds); } } /** * Fast formatting of h:mm:ss */ - private static String formatElapsedTime(StringBuilder recycle, String format, long hours, - long minutes, long seconds) { + private static String formatElapsedTime(String format, long hours, long minutes, long seconds) { if (FAST_FORMAT_HMMSS.equals(format)) { - StringBuilder sb = recycle; - if (sb == null) { - sb = new StringBuilder(8); - } else { - sb.setLength(0); - } + StringBuffer sb = new StringBuffer(16); sb.append(hours); sb.append(TIME_SEPARATOR); if (minutes < 10) { @@ -666,15 +649,9 @@ public class DateUtils /** * Fast formatting of m:ss */ - private static String formatElapsedTime(StringBuilder recycle, String format, long minutes, - long seconds) { + private static String formatElapsedTime(String format, long minutes, long seconds) { if (FAST_FORMAT_MMSS.equals(format)) { - StringBuilder sb = recycle; - if (sb == null) { - sb = new StringBuilder(8); - } else { - sb.setLength(0); - } + StringBuffer sb = new StringBuffer(16); if (minutes < 10) { sb.append(TIME_PADDING); } else { @@ -1051,9 +1028,8 @@ public class DateUtils * If FORMAT_NO_YEAR is set, then the year is not shown. * If neither FORMAT_SHOW_YEAR nor FORMAT_NO_YEAR are set, then the year * is shown only if it is different from the current year, or if the start - * and end dates fall on different years. If both are set, - * FORMAT_SHOW_YEAR takes precedence. - * + * and end dates fall on different years. + * *

    * Normally the date is shown unless the start and end day are the same. * If FORMAT_SHOW_DATE is set, then the date is always shown, even for @@ -1144,28 +1120,24 @@ public class DateUtils boolean abbrevMonth = (flags & (FORMAT_ABBREV_MONTH | FORMAT_ABBREV_ALL)) != 0; boolean noMonthDay = (flags & FORMAT_NO_MONTH_DAY) != 0; boolean numericDate = (flags & FORMAT_NUMERIC_DATE) != 0; - - // If we're getting called with a single instant in time (from - // e.g. formatDateTime(), below), then we can skip a lot of - // computation below that'd otherwise be thrown out. - boolean isInstant = (startMillis == endMillis); - - Time startDate = useUTC ? new Time(Time.TIMEZONE_UTC) : new Time(); - startDate.set(startMillis); - + + Time startDate; Time endDate; - int dayDistance; - if (isInstant) { - endDate = startDate; - dayDistance = 0; + + if (useUTC) { + startDate = new Time(Time.TIMEZONE_UTC); + endDate = new Time(Time.TIMEZONE_UTC); } else { - endDate = useUTC ? new Time(Time.TIMEZONE_UTC) : new Time(); - endDate.set(endMillis); - int startJulianDay = Time.getJulianDay(startMillis, startDate.gmtoff); - int endJulianDay = Time.getJulianDay(endMillis, endDate.gmtoff); - dayDistance = endJulianDay - startJulianDay; + startDate = new Time(); + endDate = new Time(); } - + + startDate.set(startMillis); + endDate.set(endMillis); + int startJulianDay = Time.getJulianDay(startMillis, startDate.gmtoff); + int endJulianDay = Time.getJulianDay(endMillis, endDate.gmtoff); + int dayDistance = endJulianDay - startJulianDay; + // If the end date ends at 12am at the beginning of a day, // then modify it to make it look like it ends at midnight on // the previous day. This will allow us to display "8pm - midnight", @@ -1180,21 +1152,20 @@ public class DateUtils // and an end date of Nov 12 at 00:00. // If the start and end time are the same, then skip this and don't // adjust the date. - if (!isInstant - && (endDate.hour | endDate.minute | endDate.second) == 0 - && (!showTime || dayDistance <= 1)) { + if ((endDate.hour | endDate.minute | endDate.second) == 0 + && (!showTime || dayDistance <= 1) && (startMillis != endMillis)) { endDate.monthDay -= 1; endDate.normalize(true /* ignore isDst */); } - + int startDay = startDate.monthDay; int startMonthNum = startDate.month; int startYear = startDate.year; - + int endDay = endDate.monthDay; int endMonthNum = endDate.month; int endYear = endDate.year; - + String startWeekDayString = ""; String endWeekDayString = ""; if (showWeekDay) { @@ -1205,9 +1176,9 @@ public class DateUtils weekDayFormat = WEEKDAY_FORMAT; } startWeekDayString = startDate.format(weekDayFormat); - endWeekDayString = isInstant ? startWeekDayString : endDate.format(weekDayFormat); + endWeekDayString = endDate.format(weekDayFormat); } - + String startTimeString = ""; String endTimeString = ""; if (showTime) { @@ -1233,7 +1204,7 @@ public class DateUtils boolean capNoon = (flags & FORMAT_CAP_NOON) != 0; boolean noMidnight = (flags & FORMAT_NO_MIDNIGHT) != 0; boolean capMidnight = (flags & FORMAT_CAP_MIDNIGHT) != 0; - + boolean startOnTheHour = startDate.minute == 0 && startDate.second == 0; boolean endOnTheHour = endDate.minute == 0 && endDate.second == 0; if (abbrevTime && startOnTheHour) { @@ -1249,41 +1220,20 @@ public class DateUtils startTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm); } } - - // Don't waste time on setting endTimeFormat when - // we're dealing with an instant, where we'll never - // need the end point. (It's the same as the start - // point) - if (!isInstant) { - if (abbrevTime && endOnTheHour) { - if (capAMPM) { - endTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.hour_ampm); - } + if (abbrevTime && endOnTheHour) { + if (capAMPM) { + endTimeFormat = res.getString(com.android.internal.R.string.hour_cap_ampm); } else { - if (capAMPM) { - endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm); - } + endTimeFormat = res.getString(com.android.internal.R.string.hour_ampm); } - - if (endDate.hour == 12 && endOnTheHour && !noNoon) { - if (capNoon) { - endTimeFormat = res.getString(com.android.internal.R.string.Noon); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.noon); - } - } else if (endDate.hour == 0 && endOnTheHour && !noMidnight) { - if (capMidnight) { - endTimeFormat = res.getString(com.android.internal.R.string.Midnight); - } else { - endTimeFormat = res.getString(com.android.internal.R.string.midnight); - } + } else { + if (capAMPM) { + endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_cap_ampm); + } else { + endTimeFormat = res.getString(com.android.internal.R.string.hour_minute_ampm); } } - + if (startDate.hour == 12 && startOnTheHour && !noNoon) { if (capNoon) { startTimeFormat = res.getString(com.android.internal.R.string.Noon); @@ -1293,32 +1243,37 @@ public class DateUtils // Don't show the start time starting at midnight. Show // 12am instead. } + + if (endDate.hour == 12 && endOnTheHour && !noNoon) { + if (capNoon) { + endTimeFormat = res.getString(com.android.internal.R.string.Noon); + } else { + endTimeFormat = res.getString(com.android.internal.R.string.noon); + } + } else if (endDate.hour == 0 && endOnTheHour && !noMidnight) { + if (capMidnight) { + endTimeFormat = res.getString(com.android.internal.R.string.Midnight); + } else { + endTimeFormat = res.getString(com.android.internal.R.string.midnight); + } + } } - startTimeString = startDate.format(startTimeFormat); - endTimeString = isInstant ? startTimeString : endDate.format(endTimeFormat); + endTimeString = endDate.format(endTimeFormat); } - + + // Get the current year + long millis = System.currentTimeMillis(); + Time time = new Time(); + time.set(millis); + int currentYear = time.year; + // Show the year if the user specified FORMAT_SHOW_YEAR or if // the starting and end years are different from each other // or from the current year. But don't show the year if the - // user specified FORMAT_NO_YEAR. - if (showYear) { - // No code... just a comment for clarity. Keep showYear - // on, as they enabled it with FORMAT_SHOW_YEAR. This - // takes precedence over them setting FORMAT_NO_YEAR. - } else if (noYear) { - // They explicitly didn't want a year. - showYear = false; - } else if (startYear != endYear) { - showYear = true; - } else { - // Show the year if it's not equal to the current year. - Time currentTime = new Time(); - currentTime.setToNow(); - showYear = startYear != currentTime.year; - } - + // user specified FORMAT_NO_YEAR; + showYear = showYear || (!noYear && (startYear != endYear || startYear != currentYear)); + String defaultDateFormat, fullFormat, dateRange; if (numericDate) { defaultDateFormat = res.getString(com.android.internal.R.string.numeric_date); @@ -1351,7 +1306,7 @@ public class DateUtils } } } - + if (showWeekDay) { if (showTime) { fullFormat = res.getString(com.android.internal.R.string.wday1_date1_time1_wday2_date2_time2); @@ -1365,20 +1320,20 @@ public class DateUtils fullFormat = res.getString(com.android.internal.R.string.date1_date2); } } - + if (noMonthDay && startMonthNum == endMonthNum) { // Example: "January, 2008" String startDateString = startDate.format(defaultDateFormat); return startDateString; } - + if (startYear != endYear || noMonthDay) { // Different year or we are not showing the month day number. // Example: "December 31, 2007 - January 1, 2008" // Or: "January - February, 2008" String startDateString = startDate.format(defaultDateFormat); String endDateString = endDate.format(defaultDateFormat); - + // The values that are used in a fullFormat string are specified // by position. dateRange = String.format(fullFormat, @@ -1386,7 +1341,7 @@ public class DateUtils endWeekDayString, endDateString, endTimeString); return dateRange; } - + // Get the month, day, and year strings for the start and end dates String monthFormat; if (numericDate) { @@ -1399,17 +1354,16 @@ public class DateUtils String startMonthString = startDate.format(monthFormat); String startMonthDayString = startDate.format(MONTH_DAY_FORMAT); String startYearString = startDate.format(YEAR_FORMAT); - - String endMonthString = isInstant ? null : endDate.format(monthFormat); - String endMonthDayString = isInstant ? null : endDate.format(MONTH_DAY_FORMAT); - String endYearString = isInstant ? null : endDate.format(YEAR_FORMAT); - + String endMonthString = endDate.format(monthFormat); + String endMonthDayString = endDate.format(MONTH_DAY_FORMAT); + String endYearString = endDate.format(YEAR_FORMAT); + if (startMonthNum != endMonthNum) { // Same year, different month. // Example: "October 28 - November 3" // or: "Wed, Oct 31 - Sat, Nov 3, 2007" // or: "Oct 31, 8am - Sat, Nov 3, 2007, 5pm" - + int index = 0; if (showWeekDay) index = 1; if (showYear) index += 2; @@ -1417,7 +1371,7 @@ public class DateUtils if (numericDate) index += 8; int resId = sameYearTable[index]; fullFormat = res.getString(resId); - + // The values that are used in a fullFormat string are specified // by position. dateRange = String.format(fullFormat, @@ -1427,7 +1381,7 @@ public class DateUtils endYearString, endTimeString); return dateRange; } - + if (startDay != endDay) { // Same month, different day. int index = 0; @@ -1437,7 +1391,7 @@ public class DateUtils if (numericDate) index += 8; int resId = sameMonthTable[index]; fullFormat = res.getString(resId); - + // The values that are used in a fullFormat string are specified // by position. dateRange = String.format(fullFormat, @@ -1447,19 +1401,19 @@ public class DateUtils endYearString, endTimeString); return dateRange; } - + // Same start and end day boolean showDate = (flags & FORMAT_SHOW_DATE) != 0; - + // If nothing was specified, then show the date. if (!showTime && !showDate && !showWeekDay) showDate = true; - + // Compute the time string (example: "10:00 - 11:00 am") String timeString = ""; if (showTime) { // If the start and end time are the same, then just show the // start time. - if (isInstant) { + if (startMillis == endMillis) { // Same start and end time. // Example: "10:15 AM" timeString = startTimeString; @@ -1469,7 +1423,7 @@ public class DateUtils timeString = String.format(timeFormat, startTimeString, endTimeString); } } - + // Figure out which full format to use. fullFormat = ""; String dateString = ""; @@ -1503,7 +1457,7 @@ public class DateUtils } else if (showTime) { return timeString; } - + // The values that are used in a fullFormat string are specified // by position. dateRange = String.format(fullFormat, timeString, startWeekDayString, dateString); diff --git a/core/java/android/text/method/NumberKeyListener.java b/core/java/android/text/method/NumberKeyListener.java index 9270ca58e4a6b..e500faec4439c 100644 --- a/core/java/android/text/method/NumberKeyListener.java +++ b/core/java/android/text/method/NumberKeyListener.java @@ -101,11 +101,6 @@ public abstract class NumberKeyListener extends BaseKeyListener selEnd = Math.max(a, b); } - if (selStart < 0 || selEnd < 0) { - selStart = selEnd = 0; - Selection.setSelection(content, 0); - } - int i = event != null ? lookup(event, content) : 0; int repeatCount = event != null ? event.getRepeatCount() : 0; if (repeatCount == 0) { diff --git a/core/java/android/view/GestureDetector.java b/core/java/android/view/GestureDetector.java index e0231a7b99f45..679c683cfeea2 100644 --- a/core/java/android/view/GestureDetector.java +++ b/core/java/android/view/GestureDetector.java @@ -113,48 +113,20 @@ public class GestureDetector { } /** - * The listener that is used to notify when a double-tap or a confirmed - * single-tap occur. + * @hide pending API council */ public interface OnDoubleTapListener { - /** - * Notified when a single-tap occurs. - *

    - * Unlike {@link OnGestureListener#onSingleTapUp(MotionEvent)}, this - * will only be called after the detector is confident that the user's - * first tap is not followed by a second tap leading to a double-tap - * gesture. - * - * @param e The down motion event of the single-tap. - * @return true if the event is consumed, else false - */ boolean onSingleTapConfirmed(MotionEvent e); - - /** - * Notified when a double-tap occurs. - * - * @param e The down motion event of the first tap of the double-tap. - * @return true if the event is consumed, else false - */ - boolean onDoubleTap(MotionEvent e); - - /** - * Notified when an event within a double-tap gesture occurs, including - * the down, move, and up events. - * - * @param e The motion event that occurred during the double-tap gesture. - * @return true if the event is consumed, else false - */ boolean onDoubleTapEvent(MotionEvent e); } - + /** - * A convenience class to extend when you only want to listen for a subset - * of all the gestures. This implements all methods in the - * {@link OnGestureListener} and {@link OnDoubleTapListener} but does - * nothing and return {@code false} for all applicable methods. + * A convenience class to extend when you only want to listen for a + * subset of all the gestures. This implements all methods in the + * {@link OnGestureListener} but does nothing and return {@code false} + * for all applicable methods. */ - public static class SimpleOnGestureListener implements OnGestureListener, OnDoubleTapListener { + public static class SimpleOnGestureListener implements OnGestureListener { public boolean onSingleTapUp(MotionEvent e) { return false; } @@ -178,25 +150,13 @@ public class GestureDetector { public boolean onDown(MotionEvent e) { return false; } - - public boolean onDoubleTap(MotionEvent e) { - return false; - } - - public boolean onDoubleTapEvent(MotionEvent e) { - return false; - } - - public boolean onSingleTapConfirmed(MotionEvent e) { - return false; - } } // TODO: ViewConfiguration private int mBiggerTouchSlopSquare = 20 * 20; - + private int mTouchSlopSquare; - private int mDoubleTapSlopSquare; + private int mDoubleTapSlopSquare; private int mMinimumFlingVelocity; private static final int LONGPRESS_TIMEOUT = ViewConfiguration.getLongPressTimeout(); @@ -204,7 +164,7 @@ public class GestureDetector { // TODO make new double-tap timeout, and define its events (i.e. either time // between down-down or time between up-down) private static final int DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout(); - + // constants for Message.what used by GestureHandler below private static final int SHOW_PRESS = 1; private static final int LONG_PRESS = 2; @@ -221,13 +181,13 @@ public class GestureDetector { private MotionEvent mCurrentDownEvent; private MotionEvent mPreviousUpEvent; - + /** * True when the user is still touching for the second tap (down, move, and * up events). Can only be true if there is a double tap listener attached. */ private boolean mIsDoubleTapping; - + private float mLastMotionY; private float mLastMotionX; @@ -266,7 +226,7 @@ public class GestureDetector { break; default: - throw new RuntimeException("Unknown message " + msg); //never + throw new RuntimeException("Unknown message " + msg); //never } } } @@ -343,9 +303,6 @@ public class GestureDetector { mHandler = new GestureHandler(); } mListener = listener; - if (listener instanceof OnDoubleTapListener) { - setOnDoubleTapListener((OnDoubleTapListener) listener); - } init(context); } @@ -374,11 +331,8 @@ public class GestureDetector { } /** - * Sets the listener which will be called for double-tap and related - * gestures. - * - * @param onDoubleTapListener the listener invoked for all the callbacks, or - * null to stop listening for double-tap gestures. + * @hide pending API council + * @param onDoubleTapListener */ public void setOnDoubleTapListener(OnDoubleTapListener onDoubleTapListener) { mDoubleTapListener = onDoubleTapListener; @@ -433,10 +387,7 @@ public class GestureDetector { isConsideredDoubleTap(mCurrentDownEvent, mPreviousUpEvent, ev)) { // This is a second tap mIsDoubleTapping = true; - // Give a callback with the first tap of the double-tap - handled |= mDoubleTapListener.onDoubleTap(mCurrentDownEvent); - // Give a callback with down event of the double-tap - handled |= mDoubleTapListener.onDoubleTapEvent(ev); + handled = mDoubleTapListener.onDoubleTapEvent(ev); } else { // This is a first tap mHandler.sendEmptyMessageDelayed(TAP, DOUBLE_TAP_TIMEOUT); @@ -467,8 +418,7 @@ public class GestureDetector { final float scrollX = mLastMotionX - x; final float scrollY = mLastMotionY - y; if (mIsDoubleTapping) { - // Give the move events of the double-tap - handled |= mDoubleTapListener.onDoubleTapEvent(ev); + handled = mDoubleTapListener.onDoubleTapEvent(ev); } else if (mAlwaysInTapRegion) { final int deltaX = (int) (x - mCurrentDownEvent.getX()); final int deltaY = (int) (y - mCurrentDownEvent.getY()); @@ -496,8 +446,7 @@ public class GestureDetector { mStillDown = false; MotionEvent currentUpEvent = MotionEvent.obtain(ev); if (mIsDoubleTapping) { - // Finally, give the up event of the double-tap - handled |= mDoubleTapListener.onDoubleTapEvent(ev); + handled = mDoubleTapListener.onDoubleTapEvent(ev); mIsDoubleTapping = false; break; } else if (mInLongPress) { @@ -546,7 +495,7 @@ public class GestureDetector { if (!mAlwaysInBiggerTapRegion) { return false; } - + if (secondDown.getEventTime() - firstUp.getEventTime() > DOUBLE_TAP_TIMEOUT) { return false; } @@ -555,7 +504,7 @@ public class GestureDetector { int deltaY = (int) firstDown.getY() - (int) secondDown.getY(); return (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare); } - + private void dispatchLongPress() { mHandler.removeMessages(TAP); mInLongPress = true; diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java index 430cc71de6108..d6ea91c4b5e37 100644 --- a/core/java/android/view/KeyEvent.java +++ b/core/java/android/view/KeyEvent.java @@ -228,12 +228,6 @@ public class KeyEvent implements Parcelable { */ public static final int FLAG_SOFT_KEYBOARD = 0x2; - /** - * This mask is set if we don't want the key event to cause us to leave - * touch mode. - */ - public static final int FLAG_KEEP_TOUCH_MODE = 0x4; - /** * Returns the maximum keycode. */ diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java index 406fad8e312da..5ed3a7ea6471f 100644 --- a/core/java/android/view/View.java +++ b/core/java/android/view/View.java @@ -57,7 +57,6 @@ import com.android.internal.view.menu.MenuBuilder; import java.util.ArrayList; import java.util.Arrays; -import java.lang.ref.SoftReference; /** *

    @@ -1564,7 +1563,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { private int[] mDrawableState = null; - private SoftReference mDrawingCache; + private Bitmap mDrawingCache; /** * When this view has focus and the next focus is {@link #FOCUS_LEFT}, @@ -3951,16 +3950,25 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } if ((changed & WILL_NOT_CACHE_DRAWING) != 0) { - destroyDrawingCache(); + if (mDrawingCache != null) { + mDrawingCache.recycle(); + } + mDrawingCache = null; } if ((changed & DRAWING_CACHE_ENABLED) != 0) { - destroyDrawingCache(); + if (mDrawingCache != null) { + mDrawingCache.recycle(); + } + mDrawingCache = null; mPrivateFlags &= ~DRAWING_CACHE_VALID; } if ((changed & DRAWING_CACHE_QUALITY_MASK) != 0) { - destroyDrawingCache(); + if (mDrawingCache != null) { + mDrawingCache.recycle(); + } + mDrawingCache = null; mPrivateFlags &= ~DRAWING_CACHE_VALID; } @@ -5407,10 +5415,11 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if ((mViewFlags & WILL_NOT_CACHE_DRAWING) == WILL_NOT_CACHE_DRAWING) { return null; } - if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED) { + if ((mViewFlags & DRAWING_CACHE_ENABLED) == DRAWING_CACHE_ENABLED && + ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDrawingCache == null)) { buildDrawingCache(); } - return mDrawingCache == null ? null : mDrawingCache.get(); + return mDrawingCache; } /** @@ -5425,8 +5434,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { */ public void destroyDrawingCache() { if (mDrawingCache != null) { - final Bitmap bitmap = mDrawingCache.get(); - if (bitmap != null) bitmap.recycle(); + mDrawingCache.recycle(); mDrawingCache = null; } } @@ -5466,9 +5474,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { * @see #destroyDrawingCache() */ public void buildDrawingCache() { - if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDrawingCache == null || - mDrawingCache.get() == null) { - + if ((mPrivateFlags & DRAWING_CACHE_VALID) == 0 || mDrawingCache == null) { if (ViewDebug.TRACE_HIERARCHY) { ViewDebug.trace(this, ViewDebug.HierarchyTraceType.BUILD_CACHE); } @@ -5486,12 +5492,15 @@ public class View implements Drawable.Callback, KeyEvent.Callback { if (width <= 0 || height <= 0 || (width * height * (opaque ? 2 : 4) >= // Projected bitmap size in bytes ViewConfiguration.get(mContext).getScaledMaximumDrawingCacheSize())) { - destroyDrawingCache(); + if (mDrawingCache != null) { + mDrawingCache.recycle(); + } + mDrawingCache = null; return; } boolean clear = true; - Bitmap bitmap = mDrawingCache == null ? null : mDrawingCache.get(); + Bitmap bitmap = mDrawingCache; if (bitmap == null || bitmap.getWidth() != width || bitmap.getHeight() != height) { @@ -5516,11 +5525,12 @@ public class View implements Drawable.Callback, KeyEvent.Callback { } // Try to cleanup memory - if (bitmap != null) bitmap.recycle(); + if (mDrawingCache != null) { + mDrawingCache.recycle(); + } try { - bitmap = Bitmap.createBitmap(width, height, quality); - mDrawingCache = new SoftReference(bitmap); + mDrawingCache = bitmap = Bitmap.createBitmap(width, height, quality); } catch (OutOfMemoryError e) { // If there is not enough memory to create the bitmap cache, just // ignore the issue as bitmap caches are not required to draw the @@ -8050,8 +8060,7 @@ public class View implements Drawable.Callback, KeyEvent.Callback { shader = new LinearGradient(0, 0, 0, 1, color, 0, Shader.TileMode.CLAMP); paint.setShader(shader); - // Restore the default transfer mode (src_over) - paint.setXfermode(null); + paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OVER)); } } } diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java index d3f48c6a9a56e..2f7b0d1a00688 100644 --- a/core/java/android/view/ViewConfiguration.java +++ b/core/java/android/view/ViewConfiguration.java @@ -56,7 +56,7 @@ public class ViewConfiguration { /** * Defines the duration in milliseconds we will wait to see if a touch event - * is a tap or a scroll. If the user does not move within this interval, it is + * is a top or a scroll. If the user does not move within this interval, it is * considered to be a tap. */ private static final int TAP_TIMEOUT = 100; @@ -213,7 +213,7 @@ public class ViewConfiguration { } /** - * @return the length of the fading edges in pixels + * @return Defines the length of the fading edges in pixels * * @deprecated Use {@link #getScaledFadingEdgeLength()} instead. */ @@ -223,14 +223,14 @@ public class ViewConfiguration { } /** - * @return the length of the fading edges in pixels + * @return Defines the length of the fading edges in pixels */ public int getScaledFadingEdgeLength() { return mFadingEdgeLength; } /** - * @return the duration in milliseconds of the pressed state in child + * @return Defines the duration in milliseconds of the pressed state in child * components. */ public static int getPressedStateDuration() { @@ -238,7 +238,7 @@ public class ViewConfiguration { } /** - * @return the duration in milliseconds before a press turns into + * @return Defines the duration in milliseconds before a press turns into * a long press */ public static int getLongPressTimeout() { @@ -246,8 +246,8 @@ public class ViewConfiguration { } /** - * @return the duration in milliseconds we will wait to see if a touch event - * is a tap or a scroll. If the user does not move within this interval, it is + * @return Defines the duration in milliseconds we will wait to see if a touch event + * is a top or a scroll. If the user does not move within this interval, it is * considered to be a tap. */ public static int getTapTimeout() { @@ -255,7 +255,7 @@ public class ViewConfiguration { } /** - * @return the duration in milliseconds we will wait to see if a touch event + * @return Defines the duration in milliseconds we will wait to see if a touch event * is a jump tap. If the user does not move within this interval, it is * considered to be a tap. */ @@ -264,7 +264,7 @@ public class ViewConfiguration { } /** - * @return the duration in milliseconds between the first tap's up event and + * @return Defines the duration in milliseconds between the first tap's up event and * the second tap's down event for an interaction to be considered a * double-tap. * @hide pending API council diff --git a/core/java/android/view/ViewRoot.java b/core/java/android/view/ViewRoot.java index de64d0e4ca009..3cfaf1b4c27cf 100644 --- a/core/java/android/view/ViewRoot.java +++ b/core/java/android/view/ViewRoot.java @@ -143,7 +143,6 @@ public final class ViewRoot extends Handler implements ViewParent, boolean mFullRedrawNeeded; boolean mNewSurfaceNeeded; boolean mHasHadWindowFocus; - boolean mLastWasImTarget; boolean mWindowAttributesChanged = false; @@ -999,21 +998,6 @@ public final class ViewRoot extends Handler implements ViewParent, mNewSurfaceNeeded = false; mViewVisibility = viewVisibility; - if (mAttachInfo.mHasWindowFocus) { - final boolean imTarget = WindowManager.LayoutParams - .mayUseInputMethod(mWindowAttributes.flags); - if (imTarget != mLastWasImTarget) { - mLastWasImTarget = imTarget; - InputMethodManager imm = InputMethodManager.peekInstance(); - if (imm != null && imTarget) { - imm.startGettingWindowFocus(mView); - imm.onWindowFocus(mView, mView.findFocus(), - mWindowAttributes.softInputMode, - !mHasHadWindowFocus, mWindowAttributes.flags); - } - } - } - boolean cancelDraw = attachInfo.mTreeObserver.dispatchOnPreDraw(); if (!cancelDraw && !newSurface) { @@ -1192,7 +1176,7 @@ public final class ViewRoot extends Handler implements ViewParent, // properly re-composite its drawing on a transparent // background. This automatically respects the clip/dirty region if (!canvas.isOpaque()) { - canvas.drawColor(0x00000000, PorterDuff.Mode.CLEAR); + canvas.drawColor(0xff0000ff, PorterDuff.Mode.CLEAR); } else if (yoff != 0) { // If we are applying an offset, we need to clear the area // where the offset doesn't appear to avoid having garbage @@ -1624,13 +1608,10 @@ public final class ViewRoot extends Handler implements ViewParent, } } - mLastWasImTarget = WindowManager.LayoutParams - .mayUseInputMethod(mWindowAttributes.flags); - InputMethodManager imm = InputMethodManager.peekInstance(); if (mView != null) { - if (hasWindowFocus && imm != null && mLastWasImTarget) { - imm.startGettingWindowFocus(mView); + if (hasWindowFocus && imm != null) { + imm.startGettingWindowFocus(); } mView.dispatchWindowFocusChanged(hasWindowFocus); } @@ -1638,7 +1619,7 @@ public final class ViewRoot extends Handler implements ViewParent, // Note: must be done after the focus change callbacks, // so all of the view state is set up correctly. if (hasWindowFocus) { - if (imm != null && mLastWasImTarget) { + if (imm != null) { imm.onWindowFocus(mView, mView.findFocus(), mWindowAttributes.softInputMode, !mHasHadWindowFocus, mWindowAttributes.flags); @@ -1995,9 +1976,6 @@ public final class ViewRoot extends Handler implements ViewParent, if (event.getAction() != KeyEvent.ACTION_DOWN) { return false; } - if ((event.getFlags()&KeyEvent.FLAG_KEEP_TOUCH_MODE) != 0) { - return false; - } // only relevant if we are in touch mode if (!mAttachInfo.mInTouchMode) { @@ -2117,7 +2095,8 @@ public final class ViewRoot extends Handler implements ViewParent, // If it is possible for this window to interact with the input // method window, then we want to first dispatch our key events // to the input method. - if (mLastWasImTarget) { + if (WindowManager.LayoutParams.mayUseInputMethod( + mWindowAttributes.flags)) { InputMethodManager imm = InputMethodManager.peekInstance(); if (imm != null && mView != null) { int seq = enqueuePendingEvent(event, sendDone); @@ -2147,10 +2126,6 @@ public final class ViewRoot extends Handler implements ViewParent, sWindowSession.finishKey(mWindow); } catch (RemoteException e) { } - } else { - Log.w("ViewRoot", "handleFinishedEvent(seq=" + seq - + " handled=" + handled + " ev=" + event - + ") neither delivering nor finishing key"); } } } @@ -2473,8 +2448,6 @@ public final class ViewRoot extends Handler implements ViewParent, final ViewRoot viewRoot = mViewRoot.get(); if (viewRoot != null) { viewRoot.dispatchKey(event); - } else { - Log.w("ViewRoot.W", "Key event " + event + " but no ViewRoot available!"); } } diff --git a/core/java/android/view/inputmethod/BaseInputConnection.java b/core/java/android/view/inputmethod/BaseInputConnection.java index 52b4107348082..6fbc174bab49d 100644 --- a/core/java/android/view/inputmethod/BaseInputConnection.java +++ b/core/java/android/view/inputmethod/BaseInputConnection.java @@ -338,13 +338,6 @@ public class BaseInputConnection implements InputConnection { return TextUtils.substring(content, b, b + length); } - /** - * The default implementation does nothing. - */ - public boolean performEditorAction(int actionCode) { - return false; - } - /** * The default implementation does nothing. */ diff --git a/core/java/android/view/inputmethod/EditorInfo.java b/core/java/android/view/inputmethod/EditorInfo.java index 0405371d6db7b..b2f26d7304dc1 100644 --- a/core/java/android/view/inputmethod/EditorInfo.java +++ b/core/java/android/view/inputmethod/EditorInfo.java @@ -25,100 +25,17 @@ public class EditorInfo implements InputType, Parcelable { public int inputType = TYPE_NULL; /** - * Set of bits in {@link #imeOptions} that provide alternative actions - * associated with the "enter" key. This both helps the IME provide - * better feedback about what the enter key will do, and also allows it - * to provide alternative mechanisms for providing that command. - */ - public static final int IME_MASK_ACTION = 0x000000ff; - - /** - * Bits of {@link #IME_MASK_ACTION}: there is no special action - * associated with this editor. - */ - public static final int IME_ACTION_NONE = 0x00000000; - - /** - * Bits of {@link #IME_MASK_ACTION}: the action key performs a "go" - * operation to take the user to the target of the text they typed. - * Typically used, for example, when entering a URL. - */ - public static final int IME_ACTION_GO = 0x00000001; - - /** - * Bits of {@link #IME_MASK_ACTION}: the action key performs a "search" - * operation, taking the user to the results of searching for the text - * the have typed (in whatever context is appropriate). - */ - public static final int IME_ACTION_SEARCH = 0x00000002; - - /** - * Bits of {@link #IME_MASK_ACTION}: the action key performs a "send" - * operation, delivering the text to its target. This is typically used - * when composing a message. - */ - public static final int IME_ACTION_SEND = 0x00000003; - - /** - * Bits of {@link #IME_MASK_ACTION}: the action key performs a "next" - * operation, taking the user to the next field that will accept text. - */ - public static final int IME_ACTION_NEXT = 0x00000004; - - /** - * Flag of {@link #imeOptions}: used in conjunction with - * {@link #IME_MASK_ACTION}, this indicates that the action should not - * be available in-line as the same as a "enter" key. Typically this is - * because the action has such a significant impact or is not recoverable - * enough that accidentally hitting it should be avoided, such as sending - * a message. - */ - public static final int IME_FLAG_NO_ENTER_ACTION = 0x40000000; - - /** - * Generic non-special type for {@link #imeOptions}. - */ - public static final int IME_NORMAL = 0x00000000; - - /** - * Special code for when the ime option has been undefined. This is not - * used with the EditorInfo structure, but can be used elsewhere. - */ - public static final int IME_UNDEFINED = 0x80000000; - - /** - * Extended type information for the editor, to help the IME better - * integrate with it. - */ - public int imeOptions = IME_NORMAL; - - /** - * A string supplying additional information options that are - * private to a particular IME implementation. The string must be + * A string supplying additional information about the content type that + * is private to a particular IME implementation. The string must be * scoped to a package owned by the implementation, to ensure there are * no conflicts between implementations, but other than that you can put * whatever you want in it to communicate with the IME. For example, * you could have a string that supplies an argument like * "com.example.myapp.SpecialMode=3". This field is can be - * filled in from the {@link android.R.attr#privateImeOptions} + * filled in from the {@link android.R.attr#editorPrivateContentType} * attribute of a TextView. */ - public String privateImeOptions = null; - - /** - * In some cases an IME may be able to display an arbitrary label for - * a command the user can perform, which you can specify here. You can - * not count on this being used. - */ - public CharSequence actionLabel = null; - - /** - * If {@link #actionLabel} has been given, this is the id for that command - * when the user presses its button that is delivered back with - * {@link InputConnection#performEditorAction(int) - * InputConnection.performEditorAction()}. - */ - public int actionId = 0; + public String privateContentType = null; /** * The text offset of the start of the selection at the time editing @@ -189,10 +106,7 @@ public class EditorInfo implements InputType, Parcelable { */ public void dump(Printer pw, String prefix) { pw.println(prefix + "inputType=0x" + Integer.toHexString(inputType) - + " imeOptions=0x" + Integer.toHexString(imeOptions) - + " privateImeOptions=" + privateImeOptions); - pw.println(prefix + "actionLabel=" + actionLabel - + " actionId=" + actionId); + + " privateContentType=" + privateContentType); pw.println(prefix + "initialSelStart=" + initialSelStart + " initialSelEnd=" + initialSelEnd + " initialCapsMode=0x" @@ -213,10 +127,7 @@ public class EditorInfo implements InputType, Parcelable { */ public void writeToParcel(Parcel dest, int flags) { dest.writeInt(inputType); - dest.writeInt(imeOptions); - dest.writeString(privateImeOptions); - TextUtils.writeToParcel(actionLabel, dest, flags); - dest.writeInt(actionId); + dest.writeString(privateContentType); dest.writeInt(initialSelStart); dest.writeInt(initialSelEnd); dest.writeInt(initialCapsMode); @@ -235,10 +146,7 @@ public class EditorInfo implements InputType, Parcelable { public EditorInfo createFromParcel(Parcel source) { EditorInfo res = new EditorInfo(); res.inputType = source.readInt(); - res.imeOptions = source.readInt(); - res.privateImeOptions = source.readString(); - res.actionLabel = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(source); - res.actionId = source.readInt(); + res.privateContentType = source.readString(); res.initialSelStart = source.readInt(); res.initialSelEnd = source.readInt(); res.initialCapsMode = source.readInt(); diff --git a/core/java/android/view/inputmethod/InputConnection.java b/core/java/android/view/inputmethod/InputConnection.java index 32cce35608d41..530127d1eceee 100644 --- a/core/java/android/view/inputmethod/InputConnection.java +++ b/core/java/android/view/inputmethod/InputConnection.java @@ -208,23 +208,9 @@ public interface InputConnection { /** * Set the selection of the text editor. To set the cursor position, * start and end should have the same value. - * @return Returns true on success, false if the input connection is no longer - * valid. */ public boolean setSelection(int start, int end); - /** - * Have the editor perform an action it has said it can do. - * - * @param editorAction This must be one of the action constants for - * {@link EditorInfo#imeOptions EditorInfo.editorType}, such as - * {@link EditorInfo#IME_ACTION_GO EditorInfo.EDITOR_ACTION_GO}. - * - * @return Returns true on success, false if the input connection is no longer - * valid. - */ - public boolean performEditorAction(int editorAction); - /** * Perform a context menu action on the field. The given id may be one of: * {@link android.R.id#selectAll}, diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index e9e470304228b..91fa2115d272a 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -221,11 +221,6 @@ public final class InputMethodManager { // ----------------------------------------------------------- - /** - * This is the root view of the overall window that currently has input - * method focus. - */ - View mCurRootView; /** * This is the view that should currently be served by an input method, * regardless of the state of setting that up. @@ -845,13 +840,6 @@ public final class InputMethodManager { void focusInLocked(View view) { if (DEBUG) Log.v(TAG, "focusIn: " + view); - - if (mCurRootView != view.getRootView()) { - // This is a request from a window that isn't in the window with - // IME focus, so ignore it. - return; - } - // Okay we have a new view that is being served. if (mServedView != view) { mCurrentTextBoxAttribute = null; @@ -925,7 +913,7 @@ public final class InputMethodManager { } /** - * Called by ViewRoot when its window gets input focus. + * Called by ViewRoot the first time it gets window focus. * @hide */ public void onWindowFocus(View rootView, View focusedView, int softInputMode, @@ -958,10 +946,9 @@ public final class InputMethodManager { } /** @hide */ - public void startGettingWindowFocus(View rootView) { + public void startGettingWindowFocus() { synchronized (mH) { mWindowFocusedView = null; - mCurRootView = rootView; } } @@ -1178,7 +1165,6 @@ public final class InputMethodManager { + " mBindSequence=" + mBindSequence + " mCurId=" + mCurId); p.println(" mCurMethod=" + mCurMethod); - p.println(" mCurRootView=" + mCurRootView); p.println(" mServedView=" + mServedView); p.println(" mLastServedView=" + mLastServedView); p.println(" mServedConnecting=" + mServedConnecting); diff --git a/core/java/android/webkit/CallbackProxy.java b/core/java/android/webkit/CallbackProxy.java index 84aeb832d1e72..4f8e5e4fbcbeb 100644 --- a/core/java/android/webkit/CallbackProxy.java +++ b/core/java/android/webkit/CallbackProxy.java @@ -907,12 +907,10 @@ class CallbackProxy extends Handler { } public void onReceivedIcon(Bitmap icon) { - // The current item might be null if the icon was already stored in the - // database and this is a new WebView. - WebHistoryItem i = mBackForwardList.getCurrentItem(); - if (i != null) { - i.setFavicon(icon); + if (Config.DEBUG && mBackForwardList.getCurrentItem() == null) { + throw new AssertionError(); } + mBackForwardList.getCurrentItem().setFavicon(icon); // Do an unsynchronized quick check to avoid posting if no callback has // been set. if (mWebChromeClient == null) { diff --git a/core/java/android/webkit/TextDialog.java b/core/java/android/webkit/TextDialog.java index 8a82411ec1936..c2620a512e4f2 100644 --- a/core/java/android/webkit/TextDialog.java +++ b/core/java/android/webkit/TextDialog.java @@ -25,6 +25,8 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.graphics.drawable.ShapeDrawable; import android.graphics.drawable.shapes.RectShape; +import android.os.Handler; +import android.os.Message; import android.text.Editable; import android.text.InputFilter; import android.text.Selection; @@ -41,6 +43,7 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; +import android.view.ViewConfiguration; import android.widget.AbsoluteLayout.LayoutParams; import android.widget.ArrayAdapter; import android.widget.AutoCompleteTextView; @@ -79,6 +82,22 @@ import java.util.ArrayList; // FIXME: This can be replaced with TextView.NO_FILTERS if that // is made public/protected. private static final InputFilter[] NO_FILTERS = new InputFilter[0]; + // The time of the last enter down, so we know whether to perform a long + // press. + private long mDownTime; + + private boolean mTrackballDown = false; + private static int LONGPRESS = 1; + private Handler mHandler = new Handler() { + public void handleMessage(Message msg) { + if (msg.what == LONGPRESS) { + if (mTrackballDown) { + performLongClick(); + mTrackballDown = false; + } + } + } + }; /** * Create a new TextDialog. @@ -115,13 +134,6 @@ import java.util.ArrayList; setTextColor(Color.BLACK); } - @Override - protected boolean shouldAdvanceFocusOnEnter() { - // In the browser, single line textfields use enter as a form submit, - // so we never want to advance the focus on enter. - return false; - } - @Override public boolean dispatchKeyEvent(KeyEvent event) { if (event.isSystem()) { @@ -140,33 +152,43 @@ import java.util.ArrayList; return true; } - if ((mSingle && KeyEvent.KEYCODE_ENTER == keyCode)) { + // For single-line textfields, return key should not be handled + // here. Instead, the WebView is passed the key up, so it may fire a + // submit/onClick. + // Center key should always be passed to a potential onClick + if ((mSingle && KeyEvent.KEYCODE_ENTER == keyCode) + || KeyEvent.KEYCODE_DPAD_CENTER == keyCode) { if (isPopupShowing()) { - return super.dispatchKeyEvent(event); + super.dispatchKeyEvent(event); + return true; } - if (!down) { - // Hide the keyboard, since the user has just submitted this - // form. The submission happens thanks to the two calls - // to sendDomEvent. + if (down) { + if (event.getRepeatCount() == 0) { + mGotEnterDown = true; + mDownTime = event.getEventTime(); + // Send the keydown when the up comes, so that we have + // a chance to handle a long press. + } else if (mGotEnterDown && event.getEventTime() - mDownTime > + ViewConfiguration.getLongPressTimeout()) { + performLongClick(); + mGotEnterDown = false; + } + } else if (mGotEnterDown) { + mGotEnterDown = false; + if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) { + mWebView.shortPressOnTextField(); + return true; + } + // If we reached here, then this is a single line textfield, and + // the user pressed ENTER. In this case, we want to hide the + // soft input method. InputMethodManager.getInstance(mContext) .hideSoftInputFromWindow(getWindowToken(), 0); sendDomEvent(new KeyEvent(KeyEvent.ACTION_DOWN, keyCode)); sendDomEvent(event); } - return super.dispatchKeyEvent(event); - } else if (KeyEvent.KEYCODE_DPAD_CENTER == keyCode) { - // Note that this handles center key and trackball. - if (isPopupShowing()) { - return super.dispatchKeyEvent(event); - } - // Center key should be passed to a potential onClick - if (!down) { - mWebView.shortPressOnTextField(); - } - // Pass to super to handle longpress. - return super.dispatchKeyEvent(event); + return true; } - // Ensure there is a layout so arrow keys are handled properly. if (getLayout() == null) { measure(mWidthSpec, mHeightSpec); @@ -203,8 +225,9 @@ import java.util.ArrayList; case KeyEvent.KEYCODE_DPAD_DOWN: isArrowKey = true; break; + case KeyEvent.KEYCODE_DPAD_CENTER: case KeyEvent.KEYCODE_ENTER: - // For multi-line text boxes, newlines will + // For multi-line text boxes, newlines and dpad center will // trigger onTextChanged for key down (which will send both // key up and key down) but not key up. mGotEnterDown = true; @@ -246,7 +269,7 @@ import java.util.ArrayList; // with WebCore's notion of the current selection, reset the selection // to what it was before the key event. Selection.setSelection(text, oldStart, oldEnd); - // Ignore the key up event for newlines. This prevents + // Ignore the key up event for newlines or dpad center. This prevents // multiple newlines in the native textarea. if (mGotEnterDown && !down) { return true; @@ -368,8 +391,27 @@ import java.util.ArrayList; if (isPopupShowing()) { return super.onTrackballEvent(event); } - if (event.getAction() != MotionEvent.ACTION_MOVE) { - return false; + int action = event.getAction(); + switch (action) { + case MotionEvent.ACTION_DOWN: + if (!mTrackballDown) { + mTrackballDown = true; + mHandler.sendEmptyMessageDelayed(LONGPRESS, + ViewConfiguration.getLongPressTimeout()); + } + return true; + case MotionEvent.ACTION_UP: + if (mTrackballDown) { + mWebView.shortPressOnTextField(); + mTrackballDown = false; + mHandler.removeMessages(LONGPRESS); + } + return true; + case MotionEvent.ACTION_CANCEL: + mTrackballDown = false; + return true; + case MotionEvent.ACTION_MOVE: + // fall through } Spannable text = (Spannable) getText(); MovementMethod move = getMovementMethod(); @@ -400,6 +442,7 @@ import java.util.ArrayList; // hide the soft keyboard when the edit text is out of focus InputMethodManager.getInstance(mContext).hideSoftInputFromWindow( getWindowToken(), 0); + mHandler.removeMessages(LONGPRESS); mWebView.removeView(this); mWebView.requestFocus(); mScrollToAccommodateCursor = false; diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java index 5126ef06fbd56..417b657c8b7df 100644 --- a/core/java/android/webkit/WebView.java +++ b/core/java/android/webkit/WebView.java @@ -71,7 +71,6 @@ import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Scroller; import android.widget.Toast; -import android.widget.ZoomButtonsController; import android.widget.ZoomControls; import android.widget.ZoomRingController; import android.widget.FrameLayout; @@ -285,10 +284,8 @@ public class WebView extends AbsoluteLayout /** * Customizable constant */ - // pre-computed square of ViewConfiguration.getScaledTouchSlop() + // pre-computed square of ViewConfiguration.getTouchSlop() private int mTouchSlopSquare; - // pre-computed square of ViewConfiguration.getScaledDoubleTapSlop() - private int mDoubleTapSlopSquare; // This should be ViewConfiguration.getTapTimeout() // But system time out is 100ms, which is too short for the browser. // In the browser, if it switches out of tap too soon, jump tap won't work. @@ -324,8 +321,6 @@ public class WebView extends AbsoluteLayout private int mContentHeight; // cache of value from WebViewCore static int MAX_FLOAT_CONTENT_WIDTH = 480; - // the calculated minimum content width for calculating the minimum scale. - // If it is 0, it means don't use it. private int mMinContentWidth; // Need to have the separate control for horizontal and vertical scrollbar @@ -558,9 +553,7 @@ public class WebView extends AbsoluteLayout return mExtra; } } - - private ZoomButtonsController mZoomButtonsController; - + private ZoomRingController mZoomRingController; private ImageView mZoomRingOverview; private Animation mZoomRingOverviewExitAnimation; @@ -624,9 +617,6 @@ public class WebView extends AbsoluteLayout / ZOOM_RING_STEPS; } mZoomRingController.setThumbAngle(angle * MAX_ZOOM_RING_ANGLE); - - // Don't show a thumb if the user cannot zoom - mZoomRingController.setThumbVisible(mMinZoomScale != mMaxZoomScale); // Show the zoom overview tab on the ring setZoomOverviewVisible(true); @@ -743,26 +733,6 @@ public class WebView extends AbsoluteLayout mZoomRingController.setPannerAcceleration(160); mZoomRingController.setPannerStartAcceleratingDuration(700); createZoomRingOverviewTab(); - mZoomButtonsController = new ZoomButtonsController(context, this); - mZoomButtonsController.setOverviewVisible(true); - mZoomButtonsController.setCallback(new ZoomButtonsController.OnZoomListener() { - public void onCenter(int x, int y) { - mZoomListener.onCenter(x, y); - } - - public void onOverview() { - mZoomButtonsController.setVisible(false); - zoomScrollOut(); - } - - public void onVisibilityChanged(boolean visible) { - mZoomListener.onVisibilityChanged(visible); - } - - public void onZoom(boolean zoomIn) { - mZoomListener.onSimpleZoom(zoomIn); - } - }); } private void init() { @@ -775,9 +745,6 @@ public class WebView extends AbsoluteLayout final int slop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); mTouchSlopSquare = slop * slop; mMinLockSnapReverseDistance = slop; - final int doubleTapslop = ViewConfiguration.get(getContext()) - .getScaledDoubleTapSlop(); - mDoubleTapSlopSquare = doubleTapslop * doubleTapslop; } private void createZoomRingOverviewTab() { @@ -796,7 +763,7 @@ public class WebView extends AbsoluteLayout FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER); // TODO: magic constant that's based on the zoom ring radius + some offset - lp.topMargin = 200; + lp.topMargin = 208; mZoomRingOverview.setLayoutParams(lp); mZoomRingOverview.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { @@ -2338,19 +2305,8 @@ public class WebView extends AbsoluteLayout /** * Use this function to bind an object to Javascript so that the * methods can be accessed from Javascript. - *

    IMPORTANT: - *

      - *
    • Using addJavascriptInterface() allows JavaScript to control your - * application. This can be a very useful feature or a dangerous security - * issue. When the HTML in the WebView is untrustworthy (for example, part - * or all of the HTML is provided by some person or process), then an - * attacker could inject HTML that will execute your code and possibly any - * code of the attacker's choosing.
      - * Do not use addJavascriptInterface() unless all of the HTML in this - * WebView was written by you.
    • - *
    • The Java object that is bound runs in another thread and not in - * the thread that it was constructed in.
    • - *

    + * IMPORTANT, the object that is bound runs in another thread and + * not in the thread that it was constructed in. * @param obj The class instance to bind to Javascript * @param interfaceName The name to used to expose the class in Javascript */ @@ -3013,8 +2969,8 @@ public class WebView extends AbsoluteLayout if (lp != null) { // Take the last touch and adjust for the location of the // TextDialog. - float x = mLastTouchX + (float) (mScrollX - lp.x); - float y = mLastTouchY + (float) (mScrollY - lp.y); + float x = mLastTouchX - lp.x; + float y = mLastTouchY - lp.y; mTextEntry.fakeTouchEvent(x, y); } } @@ -3208,9 +3164,6 @@ public class WebView extends AbsoluteLayout mSelectX = mScrollX + (int) mLastTouchX; mSelectY = mScrollY + (int) mLastTouchY; } - int contentX = viewToContent((int) mLastTouchX + mScrollX); - int contentY = viewToContent((int) mLastTouchY + mScrollY); - nativeClearFocus(contentX, contentY); } if (keyCode >= KeyEvent.KEYCODE_DPAD_UP @@ -3402,9 +3355,6 @@ public class WebView extends AbsoluteLayout public void emulateShiftHeld() { mExtendSelection = false; mShiftIsPressed = true; - int contentX = viewToContent((int) mLastTouchX + mScrollX); - int contentY = viewToContent((int) mLastTouchY + mScrollY); - nativeClearFocus(contentX, contentY); } private boolean commitCopy() { @@ -3451,7 +3401,6 @@ public class WebView extends AbsoluteLayout // Clean up the zoom ring mZoomRingController.setVisible(false); - mZoomButtonsController.setVisible(false); } // Implementation for OnHierarchyChangeListener @@ -3500,17 +3449,8 @@ public class WebView extends AbsoluteLayout // false for the first parameter } } else { - if (!mZoomButtonsController.isVisible()) { - /* - * The zoom controls come in their own window, so our window - * loses focus. Our policy is to not draw the focus ring if - * our window is not focused, but this is an exception since - * the user can still navigate the web page with the zoom - * controls showing. - */ - // If our window has lost focus, stop drawing the focus ring - mDrawFocusRing = false; - } + // If our window has lost focus, stop drawing the focus ring + mDrawFocusRing = false; mGotKeyDown = false; mShiftIsPressed = false; if (mNativeClass != 0) { @@ -3652,8 +3592,7 @@ public class WebView extends AbsoluteLayout + mTouchMode); } - if ((mZoomRingController.isVisible() || mZoomButtonsController.isVisible()) - && mInZoomTapDragMode) { + if (mZoomRingController.isVisible() && mInZoomTapDragMode) { if (ev.getAction() == MotionEvent.ACTION_UP) { // Just released the second tap, no longer in tap-drag mode mInZoomTapDragMode = false; @@ -3691,9 +3630,6 @@ public class WebView extends AbsoluteLayout mLastSentTouchTime = eventTime; } - int deltaX = (int) (mLastTouchX - x); - int deltaY = (int) (mLastTouchY - y); - switch (action) { case MotionEvent.ACTION_DOWN: { if (mTouchMode == SCROLL_ZOOM_ANIMATION_IN @@ -3719,23 +3655,16 @@ public class WebView extends AbsoluteLayout , viewToContent(mSelectY), false); mTouchSelection = mExtendSelection = true; } else if (!ZoomRingController.useOldZoom(mContext) && - mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP) && - (deltaX * deltaX + deltaY * deltaY < mDoubleTapSlopSquare)) { + mPrivateHandler.hasMessages(RELEASE_SINGLE_TAP)) { // Found doubletap, invoke the zoom controller mPrivateHandler.removeMessages(RELEASE_SINGLE_TAP); - int contentX = viewToContent((int) mLastTouchX + mScrollX); - int contentY = viewToContent((int) mLastTouchY + mScrollY); - if (inEditingMode()) { - mTextEntry.updateCachedTextfield(); - } - nativeClearFocus(contentX, contentY); + mZoomRingController.setVisible(true); mInZoomTapDragMode = true; if (mLogEvent) { EventLog.writeEvent(EVENT_LOG_DOUBLE_TAP_DURATION, (eventTime - mLastTouchUpTime), eventTime); } - return mZoomRingController.handleDoubleTapEvent(ev) || - mZoomButtonsController.handleDoubleTapEvent(ev); + return mZoomRingController.handleDoubleTapEvent(ev); } else { mTouchMode = TOUCH_INIT_MODE; mPreventDrag = mForwardTouchEvents; @@ -3772,6 +3701,9 @@ public class WebView extends AbsoluteLayout } mVelocityTracker.addMovement(ev); + int deltaX = (int) (mLastTouchX - x); + int deltaY = (int) (mLastTouchY - y); + if (mTouchMode != TOUCH_DRAG_MODE) { if (mTouchMode == TOUCH_SELECT_MODE) { mSelectX = mScrollX + (int) x; diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java index 6ab088d7a306a..a7261c5ca844d 100644 --- a/core/java/android/webkit/WebViewCore.java +++ b/core/java/android/webkit/WebViewCore.java @@ -1294,9 +1294,7 @@ final class WebViewCore { draw.mViewPoint = new Point(mCurrentViewWidth, mCurrentViewHeight); if (LOGV_ENABLED) Log.v(LOGTAG, "webkitDraw NEW_PICTURE_MSG_ID"); Message.obtain(mWebView.mPrivateHandler, - WebView.NEW_PICTURE_MSG_ID, - mViewportMinimumScale == 0 ? nativeGetContentMinPrefWidth() - : 0, + WebView.NEW_PICTURE_MSG_ID, nativeGetContentMinPrefWidth(), 0, draw).sendToTarget(); nativeCheckNavCache(); if (mWebkitScrollX != 0 || mWebkitScrollY != 0) { diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java index 9da78d0d41990..f362e2202c5e5 100644 --- a/core/java/android/widget/AbsListView.java +++ b/core/java/android/widget/AbsListView.java @@ -17,6 +17,7 @@ package android.widget; import android.content.Context; +import android.content.res.Configuration; import android.content.res.TypedArray; import android.graphics.Canvas; import android.graphics.Rect; @@ -27,7 +28,6 @@ import android.os.Handler; import android.os.Parcel; import android.os.Parcelable; import android.text.Editable; -import android.text.TextUtils; import android.text.TextWatcher; import android.util.AttributeSet; import android.view.Gravity; @@ -893,16 +893,25 @@ public abstract class AbsListView extends AdapterView implements Te mSyncMode = SYNC_FIRST_POSITION; } - setFilterText(ss.filter); + // Don't restore the type filter window when there is no keyboard + if (acceptFilter()) { + String filterText = ss.filter; + setFilterText(filterText); + } requestLayout(); } private boolean acceptFilter() { final Context context = mContext; + final Configuration configuration = context.getResources().getConfiguration(); + final boolean keyboardShowing = configuration.keyboardHidden != + Configuration.KEYBOARDHIDDEN_YES; + final boolean hasKeyboard = configuration.keyboard != Configuration.KEYBOARD_NOKEYS; final InputMethodManager inputManager = (InputMethodManager) context.getSystemService(Context.INPUT_METHOD_SERVICE); - return !inputManager.isFullscreenMode(); + return (hasKeyboard && keyboardShowing) || + (!hasKeyboard && !inputManager.isFullscreenMode()); } /** @@ -913,7 +922,7 @@ public abstract class AbsListView extends AdapterView implements Te */ public void setFilterText(String filterText) { // TODO: Should we check for acceptFilter()? - if (mTextFilterEnabled && !TextUtils.isEmpty(filterText)) { + if (mTextFilterEnabled && filterText != null && filterText.length() > 0) { createTextFilter(false); // This is going to call our listener onTextChanged, but we might not // be ready to bring up a window yet @@ -933,18 +942,6 @@ public abstract class AbsListView extends AdapterView implements Te } } - /** - * Returns the list's text filter, if available. - * @return the list's text filter or null if filtering isn't enabled - * @hide pending API Council approval - */ - public CharSequence getTextFilter() { - if (mTextFilterEnabled && mTextFilter != null) { - return mTextFilter.getText(); - } - return null; - } - @Override protected void onFocusChanged(boolean gainFocus, int direction, Rect previouslyFocusedRect) { super.onFocusChanged(gainFocus, direction, previouslyFocusedRect); diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java index 1d553f1d2b297..b046a6b17ecf1 100644 --- a/core/java/android/widget/AbsSeekBar.java +++ b/core/java/android/widget/AbsSeekBar.java @@ -40,15 +40,9 @@ public abstract class AbsSeekBar extends ProgressBar { * Whether this is user seekable. */ boolean mIsUserSeekable = true; - - /** - * On key presses (right or left), the amount to increment/decrement the - * progress. - */ - private int mKeyProgressIncrement = 1; private static final int NO_ALPHA = 0xFF; - private float mDisabledAlpha; + float mDisabledAlpha; public AbsSeekBar(Context context) { super(context); @@ -107,39 +101,6 @@ public abstract class AbsSeekBar extends ProgressBar { invalidate(); } - /** - * Sets the amount of progress changed via the arrow keys. - * - * @param increment The amount to increment or decrement when the user - * presses the arrow keys. - */ - public void setKeyProgressIncrement(int increment) { - mKeyProgressIncrement = increment < 0 ? -increment : increment; - } - - /** - * Returns the amount of progress changed via the arrow keys. - *

    - * By default, this will be a value that is derived from the max progress. - * - * @return The amount to increment or decrement when the user presses the - * arrow keys. This will be positive. - */ - public int getKeyProgressIncrement() { - return mKeyProgressIncrement; - } - - @Override - public synchronized void setMax(int max) { - super.setMax(max); - - if ((mKeyProgressIncrement == 0) || (getMax() / mKeyProgressIncrement > 20)) { - // It will take the user too long to change this via keys, change it - // to something more reasonable - setKeyProgressIncrement(Math.max(1, Math.round((float) getMax() / 20))); - } - } - @Override protected boolean verifyDrawable(Drawable who) { return who == mThumb || super.verifyDrawable(who); @@ -360,12 +321,12 @@ public abstract class AbsSeekBar extends ProgressBar { switch (keyCode) { case KeyEvent.KEYCODE_DPAD_LEFT: if (progress <= 0) break; - setProgress(progress - mKeyProgressIncrement, true); + setProgress(progress - 1, true); return true; case KeyEvent.KEYCODE_DPAD_RIGHT: if (progress >= getMax()) break; - setProgress(progress + mKeyProgressIncrement, true); + setProgress(progress + 1, true); return true; } diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java index f847bc399b5a9..cf9c588a21440 100644 --- a/core/java/android/widget/AnalogClock.java +++ b/core/java/android/widget/AnalogClock.java @@ -48,6 +48,7 @@ public class AnalogClock extends View { private int mDialHeight; private boolean mAttached; + private long mLastTime; private final Handler mHandler = new Handler(); private float mMinutes; @@ -95,6 +96,7 @@ public class AnalogClock extends View { protected void onAttachedToWindow() { super.onAttachedToWindow(); + onTimeChanged(); if (!mAttached) { mAttached = true; IntentFilter filter = new IntentFilter(); @@ -105,15 +107,6 @@ public class AnalogClock extends View { getContext().registerReceiver(mIntentReceiver, filter, null, mHandler); } - - // NOTE: It's safe to do these after registering the receiver since the receiver always runs - // in the main thread, therefore the receiver can't run before this method returns. - - // The time zone may have changed while the receiver wasn't registered, so update the Time - mCalendar = new Time(); - - // Make sure we update to the current time - onTimeChanged(); } @Override @@ -219,7 +212,9 @@ public class AnalogClock extends View { } private void onTimeChanged() { - mCalendar.setToNow(); + long time = System.currentTimeMillis(); + mCalendar.set(time); + mLastTime = time; int hour = mCalendar.hour; int minute = mCalendar.minute; @@ -236,6 +231,8 @@ public class AnalogClock extends View { if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) { String tz = intent.getStringExtra("time-zone"); mCalendar = new Time(TimeZone.getTimeZone(tz).getID()); + } else { + mCalendar = new Time(); } onTimeChanged(); diff --git a/core/java/android/widget/AutoCompleteTextView.java b/core/java/android/widget/AutoCompleteTextView.java index 0c1c72ab170c7..7a51676bf7681 100644 --- a/core/java/android/widget/AutoCompleteTextView.java +++ b/core/java/android/widget/AutoCompleteTextView.java @@ -78,8 +78,6 @@ import com.android.internal.R; * @attr ref android.R.styleable#AutoCompleteTextView_completionThreshold * @attr ref android.R.styleable#AutoCompleteTextView_completionHintView * @attr ref android.R.styleable#AutoCompleteTextView_dropDownSelector - * @attr ref android.R.styleable#AutoCompleteTextView_dropDownAnchor - * @attr ref android.R.styleable#AutoCompleteTextView_dropDownWidth */ public class AutoCompleteTextView extends EditText implements Filter.FilterListener { static final boolean DEBUG = false; @@ -98,9 +96,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe private DropDownListView mDropDownList; private int mDropDownVerticalOffset; private int mDropDownHorizontalOffset; - private int mDropDownAnchorId; - private View mDropDownAnchorView; // view is retrieved lazily from id once needed - private int mDropDownWidth; private Drawable mDropDownListHighlight; @@ -152,18 +147,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe a.getDimension(R.styleable.AutoCompleteTextView_dropDownVerticalOffset, 0.0f); mDropDownHorizontalOffset = (int) a.getDimension(R.styleable.AutoCompleteTextView_dropDownHorizontalOffset, 0.0f); - - // Get the anchor's id now, but the view won't be ready, so wait to actually get the - // view and store it in mDropDownAnchorView lazily in getDropDownAnchorView later. - // Defaults to NO_ID, in which case the getDropDownAnchorView method will simply return - // this TextView, as a default anchoring point. - mDropDownAnchorId = a.getResourceId(R.styleable.AutoCompleteTextView_dropDownAnchor, - View.NO_ID); - - // For dropdown width, the developer can specify a specific width, or FILL_PARENT - // (for full screen width) or WRAP_CONTENT (to match the width of the anchored view). - mDropDownWidth = a.getLayoutDimension(R.styleable.AutoCompleteTextView_dropDownWidth, - ViewGroup.LayoutParams.WRAP_CONTENT); mHintResource = a.getResourceId(R.styleable.AutoCompleteTextView_completionHintView, R.layout.simple_dropdown_hint); @@ -204,49 +187,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe public void setCompletionHint(CharSequence hint) { mHintText = hint; } - - /** - *

    Returns the current width for the auto-complete drop down list. This can - * be a fixed width, or {@link ViewGroup.LayoutParams#FILL_PARENT} to fill the screen, or - * {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the width of its anchor view.

    - * - * @return the width for the drop down list - */ - public int getDropDownWidth() { - return mDropDownWidth; - } - - /** - *

    Sets the current width for the auto-complete drop down list. This can - * be a fixed width, or {@link ViewGroup.LayoutParams#FILL_PARENT} to fill the screen, or - * {@link ViewGroup.LayoutParams#WRAP_CONTENT} to fit the width of its anchor view.

    - * - * @param width the width to use - */ - public void setDropDownWidth(int width) { - mDropDownWidth = width; - } - - /** - *

    Returns the id for the view that the auto-complete drop down list is anchored to.

    - * - * @return the view's id, or {@link View#NO_ID} if none specified - */ - public int getDropDownAnchor() { - return mDropDownAnchorId; - } - - /** - *

    Sets the view to which the auto-complete drop down list should anchor. The view - * corresponding to this id will not be loaded until the next time it is needed to avoid - * loading a view which is not yet instantiated.

    - * - * @param id the id to anchor the drop down list view to - */ - public void setDropDownAnchor(int id) { - mDropDownAnchorId = id; - mDropDownAnchorView = null; - } /** *

    Returns the number of characters the user must type before the drop @@ -801,18 +741,6 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe return result; } - - /** - *

    Used for lazy instantiation of the anchor view from the id we have. If the value of - * the id is NO_ID or we can't find a view for the given id, we return this TextView as - * the default anchoring point.

    - */ - private View getDropDownAnchorView() { - if (mDropDownAnchorView == null && mDropDownAnchorId != View.NO_ID) { - mDropDownAnchorView = getRootView().findViewById(mDropDownAnchorId); - } - return mDropDownAnchorView == null ? this : mDropDownAnchorView; - } /** *

    Displays the drop down on screen.

    @@ -820,37 +748,16 @@ public class AutoCompleteTextView extends EditText implements Filter.FilterListe public void showDropDown() { int height = buildDropDown(); if (mPopup.isShowing()) { - int widthSpec; - if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) { - // The call to PopupWindow's update method below can accept -1 for any - // value you do not want to update. - widthSpec = -1; - } else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) { - widthSpec = getDropDownAnchorView().getWidth(); - } else { - widthSpec = mDropDownWidth; - } - mPopup.update(getDropDownAnchorView(), mDropDownHorizontalOffset, - mDropDownVerticalOffset, widthSpec, height); + mPopup.update(this, mDropDownHorizontalOffset, mDropDownVerticalOffset, + getWidth(), height); } else { - int widthSpec; - if (mDropDownWidth == ViewGroup.LayoutParams.FILL_PARENT) { - mPopup.setWindowLayoutMode(ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT); - } else { - mPopup.setWindowLayoutMode(0, ViewGroup.LayoutParams.WRAP_CONTENT); - if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) { - mPopup.setWidth(getDropDownAnchorView().getWidth()); - } else { - mPopup.setWidth(mDropDownWidth); - } - } + mPopup.setWindowLayoutMode(0, ViewGroup.LayoutParams.WRAP_CONTENT); + mPopup.setWidth(getWidth()); mPopup.setHeight(height); mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED); mPopup.setOutsideTouchable(true); mPopup.setTouchInterceptor(new PopupTouchIntercepter()); - mPopup.showAsDropDown(getDropDownAnchorView(), - mDropDownHorizontalOffset, mDropDownVerticalOffset); + mPopup.showAsDropDown(this, mDropDownHorizontalOffset, mDropDownVerticalOffset); mDropDownList.setSelection(ListView.INVALID_POSITION); mDropDownList.hideSelector(); mDropDownList.requestFocus(); diff --git a/core/java/android/widget/BaseAdapter.java b/core/java/android/widget/BaseAdapter.java index 532fd766ec66a..1921d734fa8a4 100644 --- a/core/java/android/widget/BaseAdapter.java +++ b/core/java/android/widget/BaseAdapter.java @@ -42,10 +42,6 @@ public abstract class BaseAdapter implements ListAdapter, SpinnerAdapter { mDataSetObservable.unregisterObserver(observer); } - /** - * Notifies the attached View that the underlying data has been changed - * and it should refresh itself. - */ public void notifyDataSetChanged() { mDataSetObservable.notifyChanged(); } diff --git a/core/java/android/widget/Chronometer.java b/core/java/android/widget/Chronometer.java index 91add585fb5a8..369221e8789ac 100644 --- a/core/java/android/widget/Chronometer.java +++ b/core/java/android/widget/Chronometer.java @@ -69,10 +69,7 @@ public class Chronometer extends TextView { private Object[] mFormatterArgs = new Object[1]; private StringBuilder mFormatBuilder; private OnChronometerTickListener mOnChronometerTickListener; - private StringBuilder mRecycle = new StringBuilder(8); - - private static final int TICK_WHAT = 2; - + /** * Initialize this Chronometer object. * Sets the base to the current time. @@ -118,7 +115,6 @@ public class Chronometer extends TextView { @android.view.RemotableViewMethod public void setBase(long base) { mBase = base; - dispatchChronometerTick(); updateText(SystemClock.elapsedRealtime()); } @@ -220,10 +216,10 @@ public class Chronometer extends TextView { updateRunning(); } - private synchronized void updateText(long now) { + private void updateText(long now) { long seconds = now - mBase; seconds /= 1000; - String text = DateUtils.formatElapsedTime(mRecycle, seconds); + String text = DateUtils.formatElapsedTime(seconds); if (mFormat != null) { Locale loc = Locale.getDefault(); @@ -251,10 +247,7 @@ public class Chronometer extends TextView { if (running != mRunning) { if (running) { updateText(SystemClock.elapsedRealtime()); - dispatchChronometerTick(); - mHandler.sendMessageDelayed(Message.obtain(mHandler, TICK_WHAT), 1000); - } else { - mHandler.removeMessages(TICK_WHAT); + mHandler.sendMessageDelayed(Message.obtain(), 1000); } mRunning = running; } @@ -262,10 +255,10 @@ public class Chronometer extends TextView { private Handler mHandler = new Handler() { public void handleMessage(Message m) { - if (mRunning) { + if (mStarted) { updateText(SystemClock.elapsedRealtime()); dispatchChronometerTick(); - sendMessageDelayed(Message.obtain(this, TICK_WHAT), 1000); + sendMessageDelayed(Message.obtain(), 1000); } } }; diff --git a/core/java/android/widget/CursorAdapter.java b/core/java/android/widget/CursorAdapter.java index 898e501a183f2..3d758e757feb6 100644 --- a/core/java/android/widget/CursorAdapter.java +++ b/core/java/android/widget/CursorAdapter.java @@ -348,21 +348,6 @@ public abstract class CursorAdapter extends BaseAdapter implements Filterable, mFilterQueryProvider = filterQueryProvider; } - /** - * Called when the {@link ContentObserver} on the cursor receives a change notification. - * The default implementation provides the auto-requery logic, but may be overridden by - * sub classes. - * - * @see ContentObserver#onChange(boolean) - * @hide pending API Council approval - */ - protected void onContentChanged() { - if (mAutoRequery && mCursor != null && !mCursor.isClosed()) { - if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor + " due to update"); - mDataValid = mCursor.requery(); - } - } - private class ChangeObserver extends ContentObserver { public ChangeObserver() { super(new Handler()); @@ -375,7 +360,10 @@ public abstract class CursorAdapter extends BaseAdapter implements Filterable, @Override public void onChange(boolean selfChange) { - onContentChanged(); + if (mAutoRequery && mCursor != null && !mCursor.isClosed()) { + if (Config.LOGV) Log.v("Cursor", "Auto requerying " + mCursor + " due to update"); + mDataValid = mCursor.requery(); + } } } diff --git a/core/java/android/widget/Filter.java b/core/java/android/widget/Filter.java index 1d0fd5ead8c90..a2316cf6c7bf7 100644 --- a/core/java/android/widget/Filter.java +++ b/core/java/android/widget/Filter.java @@ -45,6 +45,8 @@ public abstract class Filter { private Handler mThreadHandler; private Handler mResultHandler; + private String mConstraint; + private boolean mConstraintIsValid = false; /** *

    Creates a new asynchronous filter.

    @@ -82,6 +84,13 @@ public abstract class Filter { */ public final void filter(CharSequence constraint, FilterListener listener) { synchronized (this) { + String constraintAsString = constraint != null ? constraint.toString() : null; + if (mConstraintIsValid && ( + (constraintAsString == null && mConstraint == null) || + (constraintAsString != null && constraintAsString.equals(mConstraint)))) { + // nothing to do + return; + } if (mThreadHandler == null) { HandlerThread thread = new HandlerThread(THREAD_NAME); @@ -94,13 +103,16 @@ public abstract class Filter { RequestArguments args = new RequestArguments(); // make sure we use an immutable copy of the constraint, so that // it doesn't change while the filter operation is in progress - args.constraint = constraint != null ? constraint.toString() : null; + args.constraint = constraintAsString; args.listener = listener; message.obj = args; mThreadHandler.removeMessages(FILTER_TOKEN); mThreadHandler.removeMessages(FINISH_TOKEN); mThreadHandler.sendMessage(message); + + mConstraint = constraintAsString; + mConstraintIsValid = true; } } diff --git a/core/java/android/widget/GridView.java b/core/java/android/widget/GridView.java index 6bbf062c3afec..38bfc7c17b44b 100644 --- a/core/java/android/widget/GridView.java +++ b/core/java/android/widget/GridView.java @@ -924,23 +924,32 @@ public class GridView extends AbsListView { final int count = mItemCount; if (count > 0) { final View child = obtainView(0); + final int childViewType = mAdapter.getItemViewType(0); - AbsListView.LayoutParams p = (AbsListView.LayoutParams)child.getLayoutParams(); - if (p == null) { - p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, + AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams(); + if (lp == null) { + lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0); + child.setLayoutParams(lp); + } + lp.viewType = childViewType; + + final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec, + mListPadding.left + mListPadding.right, lp.width); + + int lpHeight = lp.height; + + int childHeightSpec; + if (lpHeight > 0) { + childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); + } else { + childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); } - p.viewType = mAdapter.getItemViewType(0); - int childHeightSpec = getChildMeasureSpec( - MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED), 0, p.height); - int childWidthSpec = getChildMeasureSpec( - MeasureSpec.makeMeasureSpec(mColumnWidth, MeasureSpec.EXACTLY), 0, p.width); child.measure(childWidthSpec, childHeightSpec); - childHeight = child.getMeasuredHeight(); - if (mRecycler.shouldRecycleViewType(p.viewType)) { + if (mRecycler.shouldRecycleViewType(childViewType)) { mRecycler.addScrapView(child); } } diff --git a/core/java/android/widget/HorizontalScrollView.java b/core/java/android/widget/HorizontalScrollView.java index 652e30c72133f..96fe595c29d68 100644 --- a/core/java/android/widget/HorizontalScrollView.java +++ b/core/java/android/widget/HorizontalScrollView.java @@ -875,7 +875,7 @@ public class HorizontalScrollView extends FrameLayout { int parentHeightMeasureSpec, int heightUsed) { final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); - final int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, + final int childHeightMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin + heightUsed, lp.height); final int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec( diff --git a/core/java/android/widget/ImageView.java b/core/java/android/widget/ImageView.java index a4523b92e1d92..94d1bd175c7ae 100644 --- a/core/java/android/widget/ImageView.java +++ b/core/java/android/widget/ImageView.java @@ -840,7 +840,7 @@ public class ImageView extends View { @Override public int getBaseline() { - return mBaselineAligned ? getMeasuredHeight() : -1; + return mBaselineAligned ? getHeight() : -1; } /** diff --git a/core/java/android/widget/ListView.java b/core/java/android/widget/ListView.java index 6df72d42d5b41..4e5989cb69b22 100644 --- a/core/java/android/widget/ListView.java +++ b/core/java/android/widget/ListView.java @@ -1011,13 +1011,34 @@ public class ListView extends AbsListView { if (mItemCount > 0 && (widthMode == MeasureSpec.UNSPECIFIED || heightMode == MeasureSpec.UNSPECIFIED)) { final View child = obtainView(0); + final int childViewType = mAdapter.getItemViewType(0); - measureScrapChild(child, 0, widthMeasureSpec); + AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams(); + if (lp == null) { + lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT, 0); + child.setLayoutParams(lp); + } + lp.viewType = childViewType; + + final int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec, + mListPadding.left + mListPadding.right, lp.width); + + int lpHeight = lp.height; + + int childHeightSpec; + if (lpHeight > 0) { + childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); + } else { + childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); + } + + child.measure(childWidthSpec, childHeightSpec); childWidth = child.getMeasuredWidth(); childHeight = child.getMeasuredHeight(); - if (recycleOnMeasure()) { + if (mRecycler.shouldRecycleViewType(childViewType)) { mRecycler.addScrapView(child); } } @@ -1034,40 +1055,13 @@ public class ListView extends AbsListView { if (heightMode == MeasureSpec.AT_MOST) { // TODO: after first layout we should maybe start at the first visible position, not 0 - heightSize = measureHeightOfChildren(widthMeasureSpec, 0, NO_POSITION, heightSize, -1); + heightSize = measureHeightOfChildren( + MeasureSpec.makeMeasureSpec(widthSize, MeasureSpec.EXACTLY), + 0, NO_POSITION, heightSize, -1); } setMeasuredDimension(widthSize, heightSize); - mWidthMeasureSpec = widthMeasureSpec; - } - - private void measureScrapChild(View child, int position, int widthMeasureSpec) { - LayoutParams p = (LayoutParams) child.getLayoutParams(); - if (p == null) { - p = new LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, - ViewGroup.LayoutParams.WRAP_CONTENT, 0); - } - p.viewType = mAdapter.getItemViewType(position); - - int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec, - mListPadding.left + mListPadding.right, p.width); - int lpHeight = p.height; - int childHeightSpec; - if (lpHeight > 0) { - childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY); - } else { - childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED); - } - child.measure(childWidthSpec, childHeightSpec); - } - - /** - * @return True to recycle the views used to measure this ListView in - * UNSPECIFIED/AT_MOST modes, false otherwise. - * @hide - */ - protected boolean recycleOnMeasure() { - return true; + mWidthMeasureSpec = widthMeasureSpec; } /** @@ -1096,8 +1090,8 @@ public class ListView extends AbsListView { * startPosition is 0). * @return The height of this ListView with the given children. */ - final int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition, - final int maxHeight, int disallowPartialChildPosition) { + final int measureHeightOfChildren(final int widthMeasureSpec, final int startPosition, + int endPosition, final int maxHeight, int disallowPartialChildPosition) { final ListAdapter adapter = mAdapter; if (adapter == null) { @@ -1116,20 +1110,29 @@ public class ListView extends AbsListView { // mItemCount - 1 since endPosition parameter is inclusive endPosition = (endPosition == NO_POSITION) ? adapter.getCount() - 1 : endPosition; final AbsListView.RecycleBin recycleBin = mRecycler; - final boolean recyle = recycleOnMeasure(); - for (i = startPosition; i <= endPosition; ++i) { child = obtainView(i); + final int childViewType = adapter.getItemViewType(i); - measureScrapChild(child, i, widthMeasureSpec); + AbsListView.LayoutParams lp = (AbsListView.LayoutParams) child.getLayoutParams(); + if (lp == null) { + lp = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.WRAP_CONTENT, 0); + child.setLayoutParams(lp); + } + lp.viewType = childViewType; if (i > 0) { // Count the divider for all but one child returnedHeight += dividerHeight; } + child.measure(widthMeasureSpec, lp.height >= 0 + ? MeasureSpec.makeMeasureSpec(lp.height, MeasureSpec.EXACTLY) + : MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)); + // Recycle the view before we possibly return from the method - if (recyle) { + if (recycleBin.shouldRecycleViewType(childViewType)) { recycleBin.addScrapView(child); } @@ -1653,7 +1656,7 @@ public class ListView extends AbsListView { // Respect layout params that are already in the view. Otherwise make some up... // noinspection unchecked - AbsListView.LayoutParams p = (AbsListView.LayoutParams) child.getLayoutParams(); + AbsListView.LayoutParams p = (AbsListView.LayoutParams)child.getLayoutParams(); if (p == null) { p = new AbsListView.LayoutParams(ViewGroup.LayoutParams.FILL_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT, 0); @@ -1672,7 +1675,7 @@ public class ListView extends AbsListView { if (mChoiceMode != CHOICE_MODE_NONE && mCheckStates != null) { if (child instanceof Checkable) { - ((Checkable) child).setChecked(mCheckStates.get(position)); + ((Checkable)child).setChecked(mCheckStates.get(position)); } } diff --git a/core/java/android/widget/MultiAutoCompleteTextView.java b/core/java/android/widget/MultiAutoCompleteTextView.java index 05abc2661eb2b..59a931011ad7b 100644 --- a/core/java/android/widget/MultiAutoCompleteTextView.java +++ b/core/java/android/widget/MultiAutoCompleteTextView.java @@ -126,7 +126,7 @@ public class MultiAutoCompleteTextView extends AutoCompleteTextView { Editable text = getText(); int end = getSelectionEnd(); - if (end < 0 || mTokenizer == null) { + if (end < 0) { return false; } @@ -147,7 +147,7 @@ public class MultiAutoCompleteTextView extends AutoCompleteTextView { public void performValidation() { Validator v = getValidator(); - if (v == null || mTokenizer == null) { + if (v == null) { return; } diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java index 53db77e2dfa3d..4a5cea1cb0286 100644 --- a/core/java/android/widget/PopupWindow.java +++ b/core/java/android/widget/PopupWindow.java @@ -30,7 +30,6 @@ import android.view.View.OnTouchListener; import android.graphics.PixelFormat; import android.graphics.Rect; import android.graphics.drawable.Drawable; -import android.graphics.drawable.StateListDrawable; import android.os.IBinder; import android.content.Context; import android.content.res.TypedArray; @@ -103,8 +102,6 @@ public class PopupWindow { private Rect mTempRect = new Rect(); private Drawable mBackground; - private Drawable mAboveAnchorBackgroundDrawable; - private Drawable mBelowAnchorBackgroundDrawable; private boolean mAboveAnchor; @@ -167,43 +164,6 @@ public class PopupWindow { mBackground = a.getDrawable(R.styleable.PopupWindow_popupBackground); - // If this is a StateListDrawable, try to find and store the drawable to be - // used when the drop-down is placed above its anchor view, and the one to be - // used when the drop-down is placed below its anchor view. We extract - // the drawables ourselves to work around a problem with using refreshDrawableState - // that it will take into account the padding of all drawables specified in a - // StateListDrawable, thus adding superfluous padding to drop-down views. - // - // We assume a StateListDrawable will have a drawable for ABOVE_ANCHOR_STATE_SET and - // at least one other drawable, intended for the 'below-anchor state'. - if (mBackground instanceof StateListDrawable) { - StateListDrawable background = (StateListDrawable) mBackground; - - // Find the above-anchor view - this one's easy, it should be labeled as such. - int aboveAnchorStateIndex = background.getStateDrawableIndex(ABOVE_ANCHOR_STATE_SET); - - // Now, for the below-anchor view, look for any other drawable specified in the - // StateListDrawable which is not for the above-anchor state and use that. - int count = background.getStateCount(); - int belowAnchorStateIndex = -1; - for (int i = 0; i < count; i++) { - if (i != aboveAnchorStateIndex) { - belowAnchorStateIndex = i; - break; - } - } - - // Store the drawables we found, if we found them. Otherwise, set them both - // to null so that we'll just use refreshDrawableState. - if (aboveAnchorStateIndex != -1 && belowAnchorStateIndex != -1) { - mAboveAnchorBackgroundDrawable = background.getStateDrawable(aboveAnchorStateIndex); - mBelowAnchorBackgroundDrawable = background.getStateDrawable(belowAnchorStateIndex); - } else { - mBelowAnchorBackgroundDrawable = null; - mAboveAnchorBackgroundDrawable = null; - } - } - a.recycle(); } @@ -701,18 +661,7 @@ public class PopupWindow { mAboveAnchor = findDropDownPosition(anchor, p, xoff, yoff); if (mBackground != null) { - // If the background drawable provided was a StateListDrawable with above-anchor - // and below-anchor states, use those. Otherwise rely on refreshDrawableState to - // do the job. - if (mAboveAnchorBackgroundDrawable != null) { - if (mAboveAnchor) { - mPopupView.setBackgroundDrawable(mAboveAnchorBackgroundDrawable); - } else { - mPopupView.setBackgroundDrawable(mBelowAnchorBackgroundDrawable); - } - } else { - mPopupView.refreshDrawableState(); - } + mPopupView.refreshDrawableState(); } if (mHeightMode < 0) p.height = mLastHeight = mHeightMode; @@ -748,18 +697,12 @@ public class PopupWindow { */ private void preparePopup(WindowManager.LayoutParams p) { if (mBackground != null) { - final ViewGroup.LayoutParams layoutParams = mContentView.getLayoutParams(); - int height = ViewGroup.LayoutParams.FILL_PARENT; - if (layoutParams != null && - layoutParams.height == ViewGroup.LayoutParams.WRAP_CONTENT) { - height = ViewGroup.LayoutParams.WRAP_CONTENT; - } - // when a background is available, we embed the content view // within another view that owns the background drawable PopupViewContainer popupViewContainer = new PopupViewContainer(mContext); PopupViewContainer.LayoutParams listParams = new PopupViewContainer.LayoutParams( - ViewGroup.LayoutParams.FILL_PARENT, height + ViewGroup.LayoutParams.FILL_PARENT, + ViewGroup.LayoutParams.FILL_PARENT ); popupViewContainer.setBackgroundDrawable(mBackground); popupViewContainer.addView(mContentView, listParams); diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java index f646ab5b55b47..dd2570afec7b8 100644 --- a/core/java/android/widget/ProgressBar.java +++ b/core/java/android/widget/ProgressBar.java @@ -526,7 +526,6 @@ public class ProgressBar extends View { * @see #getProgress() * @see #incrementProgressBy(int) */ - @android.view.RemotableViewMethod public synchronized void setProgress(int progress) { setProgress(progress, false); } diff --git a/core/java/android/widget/ResourceCursorAdapter.java b/core/java/android/widget/ResourceCursorAdapter.java index a5dbd9883469c..9052ae3b44968 100644 --- a/core/java/android/widget/ResourceCursorAdapter.java +++ b/core/java/android/widget/ResourceCursorAdapter.java @@ -46,29 +46,9 @@ public abstract class ResourceCursorAdapter extends CursorAdapter { public ResourceCursorAdapter(Context context, int layout, Cursor c) { super(context, c); mLayout = mDropDownLayout = layout; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); + mInflater = (LayoutInflater)context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); } - /** - * Constructor. - * - * @param context The context where the ListView associated with this - * SimpleListItemFactory is running - * @param layout resource identifier of a layout file that defines the views - * for this list item. Unless you override them later, this will - * define both the item views and the drop down views. - * @param c The cursor from which to get the data. - * @param autoRequery If true the adapter will call requery() on the - * cursor whenever it changes so the most recent - * data is always displayed. - * @hide Pending API Council approval - */ - public ResourceCursorAdapter(Context context, int layout, Cursor c, boolean autoRequery) { - super(context, c, autoRequery); - mLayout = mDropDownLayout = layout; - mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - } - /** * Inflates view(s) from the specified XML file. * diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java index 88b2a018a3eba..c852be5fd3631 100644 --- a/core/java/android/widget/TextView.java +++ b/core/java/android/widget/TextView.java @@ -84,7 +84,6 @@ import android.view.MenuItem; import android.view.MotionEvent; import android.view.View; import android.view.ViewDebug; -import android.view.ViewRoot; import android.view.ViewTreeObserver; import android.view.ViewGroup.LayoutParams; import android.view.animation.AnimationUtils; @@ -216,7 +215,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int mDrawableSizeTop, mDrawableSizeBottom, mDrawableSizeLeft, mDrawableSizeRight; int mDrawableWidthTop, mDrawableWidthBottom, mDrawableHeightLeft, mDrawableHeightRight; int mDrawablePadding; - } + }; private Drawables mDrawables; private CharSequence mError; @@ -240,13 +239,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener private int mMarqueeRepeatLimit = 3; class InputContentType { - int imeOptions = EditorInfo.IME_UNDEFINED; - String privateImeOptions; - CharSequence imeActionLabel; - int imeActionId; + String privateContentType; Bundle extras; - OnEditorActionListener onEditorActionListener; - boolean enterDown; } InputContentType mInputContentType; @@ -274,26 +268,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener p.measureText("H"); } - /** - * Interface definition for a callback to be invoked when an action is - * performed on the editor. - */ - public interface OnEditorActionListener { - /** - * Called when an action is being performed. - * - * @param v The view that was clicked. - * @param actionId Identifier of the action. This will be either the - * identifier you supplied, or {@link EditorInfo#IME_UNDEFINED - * EditorInfo.IME_UNDEFINED} if being called due to the enter key - * being pressed. - * @param event If triggered by an enter key, this is the event; - * otherwise, this is null. - * @return Return true if you have consumed the action, else false. - */ - boolean onEditorAction(TextView v, int actionId, KeyEvent event); - } - public TextView(Context context) { this(context, null); } @@ -402,7 +376,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener int shadowcolor = 0; float dx = 0, dy = 0, r = 0; boolean password = false; - int inputType = EditorInfo.TYPE_NULL; + int contentType = EditorInfo.TYPE_NULL; int n = a.getIndexCount(); for (int i = 0; i < n; i++) { @@ -636,34 +610,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener break; case com.android.internal.R.styleable.TextView_inputType: - inputType = a.getInt(attr, mInputType); + contentType = a.getInt(attr, mInputType); break; - case com.android.internal.R.styleable.TextView_imeOptions: - if (mInputContentType == null) { - mInputContentType = new InputContentType(); - } - mInputContentType.imeOptions = a.getInt(attr, - mInputContentType.imeOptions); - break; - - case com.android.internal.R.styleable.TextView_imeActionLabel: - if (mInputContentType == null) { - mInputContentType = new InputContentType(); - } - mInputContentType.imeActionLabel = a.getText(attr); - break; - - case com.android.internal.R.styleable.TextView_imeActionId: - if (mInputContentType == null) { - mInputContentType = new InputContentType(); - } - mInputContentType.imeActionId = a.getInt(attr, - mInputContentType.imeActionId); - break; - - case com.android.internal.R.styleable.TextView_privateImeOptions: - setPrivateImeOptions(a.getString(attr)); + case com.android.internal.R.styleable.TextView_editorPrivateContentType: + setPrivateContentType(a.getString(attr)); break; case com.android.internal.R.styleable.TextView_editorExtras: @@ -681,7 +632,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener BufferType bufferType = BufferType.EDITABLE; - if ((inputType&(EditorInfo.TYPE_MASK_CLASS + if ((contentType&(EditorInfo.TYPE_MASK_CLASS |EditorInfo.TYPE_MASK_VARIATION)) == (EditorInfo.TYPE_CLASS_TEXT |EditorInfo.TYPE_TEXT_VARIATION_PASSWORD)) { @@ -705,57 +656,57 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener throw new RuntimeException(ex); } try { - mInputType = inputType != EditorInfo.TYPE_NULL - ? inputType + mInputType = contentType != EditorInfo.TYPE_NULL + ? contentType : mInput.getInputType(); } catch (IncompatibleClassChangeError e) { mInputType = EditorInfo.TYPE_CLASS_TEXT; } } else if (digits != null) { mInput = DigitsKeyListener.getInstance(digits.toString()); - mInputType = inputType; - } else if (inputType != EditorInfo.TYPE_NULL) { - setInputType(inputType, true); - singleLine = (inputType&(EditorInfo.TYPE_MASK_CLASS + mInputType = contentType; + } else if (contentType != EditorInfo.TYPE_NULL) { + setInputType(contentType, true); + singleLine = (contentType&(EditorInfo.TYPE_MASK_CLASS | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE)) != (EditorInfo.TYPE_CLASS_TEXT | EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE); } else if (phone) { mInput = DialerKeyListener.getInstance(); - inputType = EditorInfo.TYPE_CLASS_PHONE; + contentType = EditorInfo.TYPE_CLASS_PHONE; } else if (numeric != 0) { mInput = DigitsKeyListener.getInstance((numeric & SIGNED) != 0, (numeric & DECIMAL) != 0); - inputType = EditorInfo.TYPE_CLASS_NUMBER; + contentType = EditorInfo.TYPE_CLASS_NUMBER; if ((numeric & SIGNED) != 0) { - inputType |= EditorInfo.TYPE_NUMBER_FLAG_SIGNED; + contentType |= EditorInfo.TYPE_NUMBER_FLAG_SIGNED; } if ((numeric & DECIMAL) != 0) { - inputType |= EditorInfo.TYPE_NUMBER_FLAG_DECIMAL; + contentType |= EditorInfo.TYPE_NUMBER_FLAG_DECIMAL; } - mInputType = inputType; + mInputType = contentType; } else if (autotext || autocap != -1) { TextKeyListener.Capitalize cap; - inputType = EditorInfo.TYPE_CLASS_TEXT; + contentType = EditorInfo.TYPE_CLASS_TEXT; if (!singleLine) { - inputType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; + contentType |= EditorInfo.TYPE_TEXT_FLAG_MULTI_LINE; } switch (autocap) { case 1: cap = TextKeyListener.Capitalize.SENTENCES; - inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES; + contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_SENTENCES; break; case 2: cap = TextKeyListener.Capitalize.WORDS; - inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS; + contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_WORDS; break; case 3: cap = TextKeyListener.Capitalize.CHARACTERS; - inputType |= EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS; + contentType |= EditorInfo.TYPE_TEXT_FLAG_CAP_CHARACTERS; break; default: @@ -764,7 +715,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } mInput = TextKeyListener.getInstance(autotext, cap); - mInputType = inputType; + mInputType = contentType; } else if (editable) { mInput = TextKeyListener.getInstance(); mInputType = EditorInfo.TYPE_CLASS_TEXT; @@ -1124,11 +1075,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * @attr ref android.R.styleable#TextView_singleLine */ public final void setTransformationMethod(TransformationMethod method) { - if (method == mTransformation) { - // Avoid the setText() below if the transformation is - // the same. - return; - } if (mTransformation != null) { if (mText instanceof Spannable) { ((Spannable) mText).removeSpan(mTransformation); @@ -2832,7 +2778,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener /** * Directly change the content type integer of the text view, without * modifying any other state. - * @see #setInputType(int) + * @see #setContentType * @see android.text.InputType * @attr ref android.R.styleable#TextView_inputType */ @@ -2895,160 +2841,29 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return mInputType; } - /** - * Change the editor type integer associated with the text view, which - * will be reported to an IME with {@link EditorInfo#imeOptions} when it - * has focus. - * @see #getImeOptions - * @see android.view.inputmethod.EditorInfo - * @attr ref android.R.styleable#TextView_imeOptions - */ - public void setImeOptions(int imeOptions) { - if (mInputContentType == null) { - mInputContentType = new InputContentType(); - } - mInputContentType.imeOptions = imeOptions; - } - - /** - * Get the type of the IME editor. - * - * @see #setImeOptions(int) - * @see android.view.inputmethod.EditorInfo - */ - public int getImeOptions() { - return mInputContentType != null - ? mInputContentType.imeOptions : EditorInfo.IME_UNDEFINED; - } - - /** - * Change the custom IME action associated with the text view, which - * will be reported to an IME with {@link EditorInfo#actionLabel} - * and {@link EditorInfo#actionId} when it has focus. - * @see #getImeActionLabel - * @see #getImeActionId - * @see android.view.inputmethod.EditorInfo - * @attr ref android.R.styleable#TextView_imeActionLabel - * @attr ref android.R.styleable#TextView_imeActionId - */ - public void setImeActionLabel(CharSequence label, int actionId) { - if (mInputContentType == null) { - mInputContentType = new InputContentType(); - } - mInputContentType.imeActionLabel = label; - mInputContentType.imeActionId = actionId; - } - - /** - * Get the IME action label previous set with {@link #setImeActionLabel}. - * - * @see #setImeActionLabel - * @see android.view.inputmethod.EditorInfo - */ - public CharSequence getImeActionLabel() { - return mInputContentType != null - ? mInputContentType.imeActionLabel : null; - } - - /** - * Get the IME action ID previous set with {@link #setImeActionLabel}. - * - * @see #setImeActionLabel - * @see android.view.inputmethod.EditorInfo - */ - public int getImeActionId() { - return mInputContentType != null - ? mInputContentType.imeActionId : 0; - } - - /** - * Set a special OnClickListener to be called when an action is performed - * on the text view. This will be called when the enter key is pressed, - * or when an action supplied to the IME is selected by the user. - */ - public void setOnEditorActionListener(OnEditorActionListener l) { - if (mInputContentType == null) { - mInputContentType = new InputContentType(); - } - mInputContentType.onEditorActionListener = l; - } - - /** - * Called when an attached input method calls - * {@link InputConnection#performEditorAction(int) - * InputConnection.performEditorAction()} - * for this text view. The default implementation will call your click - * listener supplied to {@link #setOnEditorActionListener}, - * or generate an enter key down/up pair to invoke the action if not. - * - * @param actionCode The code of the action being performed. - * - * @see #setOnEditorActionListener - */ - public void onEditorAction(int actionCode) { - final InputContentType ict = mInputContentType; - if (ict != null) { - if (ict.onEditorActionListener != null) { - if (ict.onEditorActionListener.onEditorAction(this, - actionCode, null)) { - return; - } - } - } - - if (actionCode == EditorInfo.IME_ACTION_NEXT && - (ict != null || !shouldAdvanceFocusOnEnter())) { - // This is the default handling for the NEXT action, to advance - // focus. Note that for backwards compatibility we don't do this - // default handling if explicit ime options have not been given, - // and we do not advance by default on an enter key -- in that - // case, we want to turn this into the normal enter key codes that - // an app may be expecting. - View v = focusSearch(FOCUS_DOWN); - if (v != null) { - if (!v.requestFocus(FOCUS_DOWN)) { - throw new IllegalStateException("focus search returned a view " + - "that wasn't able to take focus!"); - } - } - return; - } - - Handler h = getHandler(); - long eventTime = SystemClock.uptimeMillis(); - h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, - new KeyEvent(eventTime, eventTime, - KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0, - KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); - h.sendMessage(h.obtainMessage(ViewRoot.DISPATCH_KEY_FROM_IME, - new KeyEvent(SystemClock.uptimeMillis(), eventTime, - KeyEvent.ACTION_UP, KeyEvent.KEYCODE_ENTER, 0, 0, 0, 0, - KeyEvent.FLAG_SOFT_KEYBOARD|KeyEvent.FLAG_KEEP_TOUCH_MODE))); - } - /** * Set the private content type of the text, which is the - * {@link EditorInfo#privateImeOptions EditorInfo.privateImeOptions} + * {@link EditorInfo#privateContentType TextBoxAttribute.privateContentType} * field that will be filled in when creating an input connection. * - * @see #getPrivateImeOptions() - * @see EditorInfo#privateImeOptions - * @attr ref android.R.styleable#TextView_privateImeOptions + * @see #getPrivateContentType() + * @see EditorInfo#privateContentType + * @attr ref android.R.styleable#TextView_editorPrivateContentType */ - public void setPrivateImeOptions(String type) { + public void setPrivateContentType(String type) { if (mInputContentType == null) mInputContentType = new InputContentType(); - mInputContentType.privateImeOptions = type; + mInputContentType.privateContentType = type; } /** * Get the private type of the content. * - * @see #setPrivateImeOptions(String) - * @see EditorInfo#privateImeOptions + * @see #setPrivateContentType(String) + * @see EditorInfo#privateContentType */ - public String getPrivateImeOptions() { + public String getPrivateContentType() { return mInputContentType != null - ? mInputContentType.privateImeOptions : null; + ? mInputContentType.privateContentType : null; } /** @@ -3992,7 +3807,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener * but also in mail addresses and subjects which will display on multiple * lines but where it doesn't make sense to insert newlines. */ - protected boolean shouldAdvanceFocusOnEnter() { + private boolean advanceFocusOnEnter() { if (mInput == null) { return false; } @@ -4013,37 +3828,15 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return false; } - private boolean isInterestingEnter(KeyEvent event) { - if ((event.getFlags() & KeyEvent.FLAG_SOFT_KEYBOARD) != 0 && - mInputContentType != null && - (mInputContentType.imeOptions & - EditorInfo.IME_FLAG_NO_ENTER_ACTION) != 0) { - // If this enter key came from a soft keyboard, and the - // text editor has been configured to not do a default - // action for software enter keys, then we aren't interested. - return false; - } - return true; - } - private int doKeyDown(int keyCode, KeyEvent event, KeyEvent otherEvent) { if (!isEnabled()) { return 0; } switch (keyCode) { - case KeyEvent.KEYCODE_ENTER: - if (!isInterestingEnter(event)) { - // Ignore enter key we aren't interested in. - return -1; - } - if (mInputContentType != null - && mInputContentType.onEditorActionListener != null) { - mInputContentType.enterDown = true; - } - // fall through... case KeyEvent.KEYCODE_DPAD_CENTER: - if (shouldAdvanceFocusOnEnter()) { + case KeyEvent.KEYCODE_ENTER: + if (advanceFocusOnEnter()) { return 0; } } @@ -4146,17 +3939,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener return super.onKeyUp(keyCode, event); case KeyEvent.KEYCODE_ENTER: - if (mInputContentType != null - && mInputContentType.onEditorActionListener != null - && mInputContentType.enterDown) { - mInputContentType.enterDown = false; - if (mInputContentType.onEditorActionListener.onEditorAction( - this, EditorInfo.IME_UNDEFINED, event)) { - return true; - } - } - - if (shouldAdvanceFocusOnEnter()) { + if (advanceFocusOnEnter()) { /* * If there is a click listener, just call through to * super, which will invoke it. @@ -4211,26 +3994,11 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mInputMethodState = new InputMethodState(); } outAttrs.inputType = mInputType; - if (mInputContentType != null) { - outAttrs.imeOptions = mInputContentType.imeOptions; - outAttrs.privateImeOptions = mInputContentType.privateImeOptions; - outAttrs.actionLabel = mInputContentType.imeActionLabel; - outAttrs.actionId = mInputContentType.imeActionId; - outAttrs.extras = mInputContentType.extras; - } else { - outAttrs.imeOptions = EditorInfo.IME_UNDEFINED; - } - if (outAttrs.imeOptions == EditorInfo.IME_UNDEFINED) { - if (focusSearch(FOCUS_DOWN) != null) { - // An action has not been set, but the enter key will move to - // the next focus, so set the action to that. - outAttrs.imeOptions = EditorInfo.IME_ACTION_NEXT; - if (!shouldAdvanceFocusOnEnter()) { - outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_ENTER_ACTION; - } - } - } outAttrs.hintText = mHint; + if (mInputContentType != null) { + outAttrs.privateContentType = mInputContentType.privateContentType; + outAttrs.extras = mInputContentType.extras; + } if (mText instanceof Editable) { InputConnection ic = new EditableInputConnection(this); outAttrs.initialSelStart = Selection.getSelectionStart(mText); @@ -6019,9 +5787,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } // Don't leave us in the middle of a batch edit. onEndBatchEdit(); - if (mInputContentType != null) { - mInputContentType.enterDown = false; - } } startStopMarquee(hasWindowFocus); @@ -6115,7 +5880,8 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener mScroller = s; } - private static class Blink extends Handler implements Runnable { + private static class Blink extends Handler + implements Runnable { private WeakReference mView; private boolean mCancelled; @@ -6373,44 +6139,23 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener } int start = end; + char c; int len = mText.length(); - for (; start > 0; start--) { - char c = mTransformed.charAt(start - 1); - int type = Character.getType(c); - - if (c != '\'' && - type != Character.UPPERCASE_LETTER && - type != Character.LOWERCASE_LETTER && - type != Character.TITLECASE_LETTER && - type != Character.MODIFIER_LETTER && - type != Character.DECIMAL_DIGIT_NUMBER) { - break; - } + while (start > 0 && (((c = mTransformed.charAt(start - 1)) == '\'') || + (Character.isLetterOrDigit(c)))) { + start--; } - for (; end < len; end++) { - char c = mTransformed.charAt(end); - int type = Character.getType(c); - - if (c != '\'' && - type != Character.UPPERCASE_LETTER && - type != Character.LOWERCASE_LETTER && - type != Character.TITLECASE_LETTER && - type != Character.MODIFIER_LETTER && - type != Character.DECIMAL_DIGIT_NUMBER) { - break; - } + while (end < len && (((c = mTransformed.charAt(end)) == '\'') || + (Character.isLetterOrDigit(c)))) { + end++; } if (start == end) { return null; } - if (end - start > 48) { - return null; - } - return TextUtils.substring(mTransformed, start, end); } diff --git a/core/java/android/widget/ZoomButtonsController.java b/core/java/android/widget/ZoomButtonsController.java deleted file mode 100644 index ec45e23a76208..0000000000000 --- a/core/java/android/widget/ZoomButtonsController.java +++ /dev/null @@ -1,478 +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.widget; - -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.graphics.PixelFormat; -import android.graphics.Rect; -import android.os.Handler; -import android.os.Message; -import android.provider.Settings; -import android.view.Gravity; -import android.view.KeyEvent; -import android.view.LayoutInflater; -import android.view.MotionEvent; -import android.view.View; -import android.view.ViewConfiguration; -import android.view.WindowManager; -import android.view.View.OnClickListener; -import android.view.WindowManager.LayoutParams; - -// TODO: make sure no px values exist, only dip (scale if necessary from Viewconfiguration) - -/** - * TODO: Docs - * - * If you are using this with a custom View, please call - * {@link #setVisible(boolean) setVisible(false)} from the - * {@link View#onDetachedFromWindow}. - * - * @hide - */ -public class ZoomButtonsController implements View.OnTouchListener { - - private static final String TAG = "ZoomButtonsController"; - - private static final int ZOOM_CONTROLS_TIMEOUT = - (int) ViewConfiguration.getZoomControlsTimeout(); - - // TODO: scaled to density - private static final int ZOOM_CONTROLS_TOUCH_PADDING = 20; - - private Context mContext; - private WindowManager mWindowManager; - - /** - * The view that is being zoomed by this zoom ring. - */ - private View mOwnerView; - - /** - * The bounds of the owner view in global coordinates. This is recalculated - * each time the zoom ring is shown. - */ - private Rect mOwnerViewBounds = new Rect(); - - /** - * The container that is added as a window. - */ - private FrameLayout mContainer; - private LayoutParams mContainerLayoutParams; - private int[] mContainerLocation = new int[2]; - - private ZoomControls mControls; - - /** - * The view (or null) that should receive touch events. This will get set if - * the touch down hits the container. It will be reset on the touch up. - */ - private View mTouchTargetView; - /** - * The {@link #mTouchTargetView}'s location in window, set on touch down. - */ - private int[] mTouchTargetLocationInWindow = new int[2]; - /** - * If the zoom ring is dismissed but the user is still in a touch - * interaction, we set this to true. This will ignore all touch events until - * up/cancel, and then set the owner's touch listener to null. - */ - private boolean mReleaseTouchListenerOnUp; - - private boolean mIsVisible; - - private Rect mTempRect = new Rect(); - - private OnZoomListener mCallback; - - /** - * When showing the zoom, we add the view as a new window. However, there is - * logic that needs to know the size of the zoom which is determined after - * it's laid out. Therefore, we must post this logic onto the UI thread so - * it will be exceuted AFTER the layout. This is the logic. - */ - private Runnable mPostedVisibleInitializer; - - private IntentFilter mConfigurationChangedFilter = - new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED); - - private BroadcastReceiver mConfigurationChangedReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (!mIsVisible) return; - - mHandler.removeMessages(MSG_POST_CONFIGURATION_CHANGED); - mHandler.sendEmptyMessage(MSG_POST_CONFIGURATION_CHANGED); - } - }; - - /** When configuration changes, this is called after the UI thread is idle. */ - private static final int MSG_POST_CONFIGURATION_CHANGED = 2; - /** Used to delay the zoom ring dismissal. */ - private static final int MSG_DISMISS_ZOOM_RING = 3; - /** - * If setVisible(true) is called and the owner view's window token is null, - * we delay the setVisible(true) call until it is not null. - */ - private static final int MSG_POST_SET_VISIBLE = 4; - - private Handler mHandler = new Handler() { - @Override - public void handleMessage(Message msg) { - switch (msg.what) { - case MSG_POST_CONFIGURATION_CHANGED: - onPostConfigurationChanged(); - break; - - case MSG_DISMISS_ZOOM_RING: - setVisible(false); - break; - - case MSG_POST_SET_VISIBLE: - if (mOwnerView.getWindowToken() == null) { - // Doh, it is still null, throw an exception - throw new IllegalArgumentException( - "Cannot make the zoom ring visible if the owner view is " + - "not attached to a window."); - } - setVisible(true); - break; - } - - } - }; - - public ZoomButtonsController(Context context, View ownerView) { - mContext = context; - mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); - mOwnerView = ownerView; - - mContainer = createContainer(); - } - - private FrameLayout createContainer() { - LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); - lp.gravity = Gravity.BOTTOM | Gravity.CENTER; - lp.flags = LayoutParams.FLAG_NOT_TOUCHABLE | - LayoutParams.FLAG_LAYOUT_NO_LIMITS; - lp.height = LayoutParams.WRAP_CONTENT; - lp.width = LayoutParams.FILL_PARENT; - lp.type = LayoutParams.TYPE_APPLICATION_PANEL; - lp.format = PixelFormat.TRANSPARENT; - // TODO: make a new animation for this - lp.windowAnimations = com.android.internal.R.style.Animation_InputMethodFancy; - mContainerLayoutParams = lp; - - FrameLayout container = new FrameLayout(mContext); - container.setLayoutParams(lp); - container.setMeasureAllChildren(true); - - LayoutInflater inflater = (LayoutInflater) mContext - .getSystemService(Context.LAYOUT_INFLATER_SERVICE); - inflater.inflate(com.android.internal.R.layout.zoom_magnify, container); - - mControls = (ZoomControls) container.findViewById(com.android.internal.R.id.zoomControls); - mControls.setOnZoomInClickListener(new OnClickListener() { - public void onClick(View v) { - dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT); - if (mCallback != null) mCallback.onZoom(true); - } - }); - mControls.setOnZoomOutClickListener(new OnClickListener() { - public void onClick(View v) { - dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT); - if (mCallback != null) mCallback.onZoom(false); - } - }); - - View overview = container.findViewById(com.android.internal.R.id.zoomMagnify); - overview.setVisibility(View.GONE); - overview.setOnClickListener(new OnClickListener() { - public void onClick(View v) { - dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT); - if (mCallback != null) mCallback.onOverview(); - } - }); - - return container; - } - - public void setCallback(OnZoomListener callback) { - mCallback = callback; - } - - public void setFocusable(boolean focusable) { - if (focusable) { - mContainerLayoutParams.flags &= ~LayoutParams.FLAG_NOT_FOCUSABLE; - } else { - mContainerLayoutParams.flags |= LayoutParams.FLAG_NOT_FOCUSABLE; - } - - if (mIsVisible) { - mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams); - } - } - - public void setOverviewVisible(boolean visible) { - mContainer.findViewById(com.android.internal.R.id.zoomMagnify) - .setVisibility(visible ? View.VISIBLE : View.GONE); - } - - public boolean isVisible() { - return mIsVisible; - } - - public void setVisible(boolean visible) { - - if (!useThisZoom(mContext)) return; - - if (visible) { - if (mOwnerView.getWindowToken() == null) { - /* - * We need a window token to show ourselves, maybe the owner's - * window hasn't been created yet but it will have been by the - * time the looper is idle, so post the setVisible(true) call. - */ - if (!mHandler.hasMessages(MSG_POST_SET_VISIBLE)) { - mHandler.sendEmptyMessage(MSG_POST_SET_VISIBLE); - } - return; - } - - dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT); - } - - if (mIsVisible == visible) { - return; - } - mIsVisible = visible; - - if (visible) { - if (mContainerLayoutParams.token == null) { - mContainerLayoutParams.token = mOwnerView.getWindowToken(); - } - - mWindowManager.addView(mContainer, mContainerLayoutParams); - - if (mPostedVisibleInitializer == null) { - mPostedVisibleInitializer = new Runnable() { - public void run() { - refreshPositioningVariables(); - - if (mCallback != null) { - mCallback.onVisibilityChanged(true); - } - } - }; - } - - mHandler.post(mPostedVisibleInitializer); - - // Handle configuration changes when visible - mContext.registerReceiver(mConfigurationChangedReceiver, mConfigurationChangedFilter); - - // Steal touches events from the owner - mOwnerView.setOnTouchListener(this); - mReleaseTouchListenerOnUp = false; - - } else { - // Don't want to steal any more touches - if (mTouchTargetView != null) { - // We are still stealing the touch events for this touch - // sequence, so release the touch listener later - mReleaseTouchListenerOnUp = true; - } else { - mOwnerView.setOnTouchListener(null); - } - - // No longer care about configuration changes - mContext.unregisterReceiver(mConfigurationChangedReceiver); - - mWindowManager.removeView(mContainer); - mHandler.removeCallbacks(mPostedVisibleInitializer); - - if (mCallback != null) { - mCallback.onVisibilityChanged(false); - } - } - - } - - /** - * TODO: docs - * - * Notes: - * - Please ensure you set your View to INVISIBLE not GONE when hiding it. - * - * @return TODO - */ - public FrameLayout getContainer() { - return mContainer; - } - - public int getZoomRingId() { - return mControls.getId(); - } - - private void dismissControlsDelayed(int delay) { - mHandler.removeMessages(MSG_DISMISS_ZOOM_RING); - mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_RING, delay); - } - - /** - * Should be called by the client for each event belonging to the second tap - * (the down, move, up, and cancel events). - * - * @param event The event belonging to the second tap. - * @return Whether the event was consumed. - */ - public boolean handleDoubleTapEvent(MotionEvent event) { - if (!useThisZoom(mContext)) return false; - - int action = event.getAction(); - - if (action == MotionEvent.ACTION_DOWN) { - int x = (int) event.getX(); - int y = (int) event.getY(); - - setVisible(true); - centerPoint(x, y); - } - - return true; - } - - private void refreshPositioningVariables() { - // Calculate the owner view's bounds - mOwnerView.getGlobalVisibleRect(mOwnerViewBounds); - mContainer.getLocationOnScreen(mContainerLocation); - } - - /** - * Centers the point (in owner view's coordinates). - */ - private void centerPoint(int x, int y) { - if (mCallback != null) { - mCallback.onCenter(x, y); - } - } - - public boolean onTouch(View v, MotionEvent event) { - int action = event.getAction(); - - if (mReleaseTouchListenerOnUp) { - // The ring was dismissed but we need to throw away all events until the up - if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { - mOwnerView.setOnTouchListener(null); - setTouchTargetView(null); - mReleaseTouchListenerOnUp = false; - } - - // Eat this event - return true; - } - - // TODO: optimize this (it ends up removing message and queuing another) - dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT); - - View targetView = mTouchTargetView; - - switch (action) { - case MotionEvent.ACTION_DOWN: - targetView = getViewForTouch((int) event.getRawX(), (int) event.getRawY()); - setTouchTargetView(targetView); - break; - - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - setTouchTargetView(null); - break; - } - - if (targetView != null) { - // The upperleft corner of the target view in raw coordinates - int targetViewRawX = mContainerLocation[0] + mTouchTargetLocationInWindow[0]; - int targetViewRawY = mContainerLocation[1] + mTouchTargetLocationInWindow[1]; - - MotionEvent containerEvent = MotionEvent.obtain(event); - // Convert the motion event into the target view's coordinates (from - // owner view's coordinates) - containerEvent.offsetLocation(mOwnerViewBounds.left - targetViewRawX, - mOwnerViewBounds.top - targetViewRawY); - boolean retValue = targetView.dispatchTouchEvent(containerEvent); - containerEvent.recycle(); - return retValue; - - } else { - return false; - } - } - - private void setTouchTargetView(View view) { - mTouchTargetView = view; - if (view != null) { - view.getLocationInWindow(mTouchTargetLocationInWindow); - } - } - - /** - * Returns the View that should receive a touch at the given coordinates. - * - * @param rawX The raw X. - * @param rawY The raw Y. - * @return The view that should receive the touches, or null if there is not one. - */ - private View getViewForTouch(int rawX, int rawY) { - // Reverse order so the child drawn on top gets first dibs. - int containerCoordsX = rawX - mContainerLocation[0]; - int containerCoordsY = rawY - mContainerLocation[1]; - Rect frame = mTempRect; - for (int i = mContainer.getChildCount() - 1; i >= 0; i--) { - View child = mContainer.getChildAt(i); - if (child.getVisibility() != View.VISIBLE) { - continue; - } - - child.getHitRect(frame); - // Expand the touch region - frame.top -= ZOOM_CONTROLS_TOUCH_PADDING; - if (frame.contains(containerCoordsX, containerCoordsY)) { - return child; - } - } - - return null; - } - - private void onPostConfigurationChanged() { - dismissControlsDelayed(ZOOM_CONTROLS_TIMEOUT); - refreshPositioningVariables(); - } - - public static boolean useThisZoom(Context context) { - return ZoomRingController.getZoomType(context) == 2; - } - - public interface OnZoomListener { - void onCenter(int x, int y); - void onVisibilityChanged(boolean visible); - void onZoom(boolean zoomIn); - void onOverview(); - } -} diff --git a/core/java/android/widget/ZoomRing.java b/core/java/android/widget/ZoomRing.java index a5a867b4e91bf..a29e1a0ec3834 100644 --- a/core/java/android/widget/ZoomRing.java +++ b/core/java/android/widget/ZoomRing.java @@ -77,7 +77,7 @@ public class ZoomRing extends View { private int mPreviousWidgetDragX; private int mPreviousWidgetDragY; - private boolean mThumbVisible = true; + private boolean mDrawThumb = true; private Drawable mThumbDrawable; /** Shown beneath the thumb if we can still zoom in. */ @@ -91,13 +91,6 @@ public class ZoomRing extends View { private static final int THUMB_ARROWS_FADE_DURATION = 300; private long mThumbArrowsFadeStartTime; private int mThumbArrowsAlpha = 255; - - private static final int THUMB_PLUS_MINUS_DISTANCE = 69; - private static final int THUMB_PLUS_MINUS_OFFSET_ANGLE = TWO_PI_INT_MULTIPLIED / 11; - /** Drawn (without rotation) on top of the arrow. */ - private Drawable mThumbPlusDrawable; - /** Drawn (without rotation) on top of the arrow. */ - private Drawable mThumbMinusDrawable; private static final int MODE_IDLE = 0; @@ -106,7 +99,7 @@ public class ZoomRing extends View { * are waiting for him to move the slop amount before considering him in the * drag thumb state. */ - private static final int MODE_WAITING_FOR_DRAG_THUMB_AFTER_JUMP = 5; + private static final int MODE_WAITING_FOR_DRAG_THUMB = 5; private static final int MODE_DRAG_THUMB = 1; /** * User has his finger down, but we are waiting for him to pass the touch @@ -116,14 +109,11 @@ public class ZoomRing extends View { private static final int MODE_WAITING_FOR_MOVE_ZOOM_RING = 4; private static final int MODE_MOVE_ZOOM_RING = 2; private static final int MODE_TAP_DRAG = 3; - /** Ignore the touch interaction until the user touches the thumb again. */ - private static final int MODE_IGNORE_UNTIL_TOUCHES_THUMB = 6; + /** Ignore the touch interaction. Reset to MODE_IDLE after up/cancel. */ + private static final int MODE_IGNORE_UNTIL_UP = 6; private int mMode; - - /** Records the last mode the user was in. */ - private int mPreviousMode; - - private long mPreviousCenterUpTime; + + private long mPreviousUpTime; private int mPreviousDownX; private int mPreviousDownY; @@ -132,9 +122,7 @@ public class ZoomRing extends View { private OnZoomRingCallback mCallback; private int mPreviousCallbackAngle; private int mCallbackThreshold = Integer.MAX_VALUE; - /** If the user drags to within __% of a tick, snap to that tick. */ - private int mFuzzyCallbackThreshold = Integer.MAX_VALUE; - + private boolean mResetThumbAutomatically = true; private int mThumbDragStartAngle; @@ -145,8 +133,6 @@ public class ZoomRing extends View { private Scroller mThumbScroller; - private boolean mVibration = true; - private static final int MSG_THUMB_SCROLLER_TICK = 1; private static final int MSG_THUMB_ARROWS_FADE_TICK = 2; private Handler mHandler = new Handler() { @@ -177,8 +163,6 @@ public class ZoomRing extends View { mutate(); mThumbMinusArrowDrawable = res.getDrawable(R.drawable.zoom_ring_thumb_minus_arrow_rotatable). mutate(); - mThumbPlusDrawable = res.getDrawable(R.drawable.zoom_ring_thumb_plus); - mThumbMinusDrawable = res.getDrawable(R.drawable.zoom_ring_thumb_minus); if (DRAW_TRAIL) { mTrail = res.getDrawable(R.drawable.zoom_ring_trail).mutate(); } @@ -191,7 +175,7 @@ public class ZoomRing extends View { mThumbHalfHeight = mThumbDrawable.getIntrinsicHeight() / 2; mThumbHalfWidth = mThumbDrawable.getIntrinsicWidth() / 2; - setCallbackThreshold(PI_INT_MULTIPLIED / 6); + mCallbackThreshold = PI_INT_MULTIPLIED / 6; } public ZoomRing(Context context, AttributeSet attrs) { @@ -209,20 +193,8 @@ public class ZoomRing extends View { // TODO: rename public void setCallbackThreshold(int callbackThreshold) { mCallbackThreshold = callbackThreshold; - mFuzzyCallbackThreshold = (int) (callbackThreshold * 0.65f); } - public void setVibration(boolean vibrate) { - mVibration = vibrate; - } - - public void setThumbVisible(boolean thumbVisible) { - if (mThumbVisible != thumbVisible) { - mThumbVisible = thumbVisible; - invalidate(); - } - } - // TODO: from XML too public void setRingBounds(int innerRadius, int outerRadius) { mBoundInnerRadiusSquared = innerRadius * innerRadius; @@ -334,7 +306,15 @@ public class ZoomRing extends View { public void setThumbAngleAnimated(int angle, int duration) { // The angle when going from the current angle to the new angle int deltaAngle = getDelta(mThumbAngle, angle); - setThumbAngleAnimated(angle, duration, deltaAngle > 0); + // Counter clockwise if the new angle is more the current angle + boolean counterClockwise = deltaAngle > 0; + + if (deltaAngle > PI_INT_MULTIPLIED || deltaAngle < -PI_INT_MULTIPLIED) { + // It's quicker to go the other direction + counterClockwise = !counterClockwise; + } + + setThumbAngleAnimated(angle, duration, counterClockwise); } public void setThumbAngleAnimated(int angle, int duration, boolean counterClockwise) { @@ -374,10 +354,14 @@ public class ZoomRing extends View { return mThumbScroller.getCurrX() % TWO_PI_INT_MULTIPLIED; } + public void resetThumbAngle(int angle) { + mPreviousCallbackAngle = angle; + setThumbAngleInt(angle); + } + public void resetThumbAngle() { if (mResetThumbAutomatically) { - mPreviousCallbackAngle = 0; - setThumbAngleInt(0); + resetThumbAngle(0); } } @@ -410,119 +394,101 @@ public class ZoomRing extends View { mTrail.setBounds(0, 0, right - left, bottom - top); } - // These drawables are the same size as the track mThumbPlusArrowDrawable.setBounds(0, 0, right - left, bottom - top); mThumbMinusArrowDrawable.setBounds(0, 0, right - left, bottom - top); } @Override public boolean onTouchEvent(MotionEvent event) { -// Log.d(TAG, "History size: " + event.getHistorySize()); - return handleTouch(event.getAction(), event.getEventTime(), (int) event.getX(), (int) event.getY(), (int) event.getRawX(), (int) event.getRawY()); } - private void resetToIdle() { - setMode(MODE_IDLE); + private void resetState() { + mMode = MODE_IDLE; mPreviousWidgetDragX = mPreviousWidgetDragY = Integer.MIN_VALUE; mAcculumalatedTrailAngle = 0.0; } public void setTapDragMode(boolean tapDragMode, int x, int y) { - resetToIdle(); + resetState(); + mMode = tapDragMode ? MODE_TAP_DRAG : MODE_IDLE; + if (tapDragMode) { - setMode(MODE_TAP_DRAG); - mCallback.onUserInteractionStarted(); onThumbDragStarted(getAngle(x - mCenterX, y - mCenterY)); - } else { - onTouchUp(SystemClock.elapsedRealtime(), true); } } public boolean handleTouch(int action, long time, int x, int y, int rawX, int rawY) { - // local{X,Y} will be where the center of the widget is (0,0) - int localX = x - mCenterX; - int localY = y - mCenterY; - - /* - * If we are not drawing the thumb, there is no way for the user to be - * touching the thumb. Also, if this is the case, assume they are not - * touching the ring (so the user cannot absolute set the thumb, and - * there will be a larger touch region for going into the move-ring - * mode). - */ - boolean isTouchingThumb = mThumbVisible; - boolean isTouchingRing = mThumbVisible; - - int touchAngle = getAngle(localX, localY); -// printAngle("touchAngle", touchAngle); -// printAngle("mThumbAngle", mThumbAngle); -// printAngle("mPreviousCallbackAngle", mPreviousCallbackAngle); -// Log.d(TAG, ""); - - - int radiusSquared = localX * localX + localY * localY; - if (radiusSquared < mBoundInnerRadiusSquared || - radiusSquared > mBoundOuterRadiusSquared) { - // Out-of-bounds - isTouchingThumb = false; - isTouchingRing = false; - } - - if (isTouchingThumb) { - int deltaThumbAndTouch = getDelta(mThumbAngle, touchAngle); - int absoluteDeltaThumbAndTouch = deltaThumbAndTouch >= 0 ? - deltaThumbAndTouch : -deltaThumbAndTouch; - if (absoluteDeltaThumbAndTouch > THUMB_GRAB_SLOP) { - // Didn't grab close enough to the thumb - isTouchingThumb = false; - } - } - switch (action) { + case MotionEvent.ACTION_DOWN: - if (!isTouchingRing && - (time - mPreviousCenterUpTime <= DOUBLE_TAP_DISMISS_TIMEOUT)) { - // Make sure the double-tap is in the center of the widget (and not on the ring) + if (time - mPreviousUpTime <= DOUBLE_TAP_DISMISS_TIMEOUT) { mCallback.onZoomRingDismissed(true); - onTouchUp(time, isTouchingRing); + onTouchUp(time); // Dismissing, so halt here return true; } - resetToIdle(); mCallback.onUserInteractionStarted(); mPreviousDownX = x; mPreviousDownY = y; + resetState(); // Fall through to code below switch (since the down is used for // jumping to the touched tick) break; case MotionEvent.ACTION_MOVE: + if (mMode == MODE_IGNORE_UNTIL_UP) return true; + // Fall through to code below switch break; case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: - onTouchUp(time, isTouchingRing); + onTouchUp(time); return true; default: return false; } + // local{X,Y} will be where the center of the widget is (0,0) + int localX = x - mCenterX; + int localY = y - mCenterY; + boolean isTouchingThumb = true; + boolean isInRingBounds = true; + + int touchAngle = getAngle(localX, localY); + int radiusSquared = localX * localX + localY * localY; + if (radiusSquared < mBoundInnerRadiusSquared || + radiusSquared > mBoundOuterRadiusSquared) { + // Out-of-bounds + isTouchingThumb = false; + isInRingBounds = false; + } + + int deltaThumbAndTouch = getDelta(mThumbAngle, touchAngle); + int absoluteDeltaThumbAndTouch = deltaThumbAndTouch >= 0 ? + deltaThumbAndTouch : -deltaThumbAndTouch; + if (isTouchingThumb && + absoluteDeltaThumbAndTouch > THUMB_GRAB_SLOP) { + // Didn't grab close enough to the thumb + isTouchingThumb = false; + } + if (mMode == MODE_IDLE) { if (isTouchingThumb) { // They grabbed the thumb - setMode(MODE_DRAG_THUMB); + mMode = MODE_DRAG_THUMB; onThumbDragStarted(touchAngle); - } else if (isTouchingRing) { + } else if (isInRingBounds) { // They tapped somewhere else on the ring int tickAngle = getClosestTickAngle(touchAngle); + int deltaThumbAndTick = getDelta(mThumbAngle, tickAngle); int boundAngle = getBoundIfExceeds(mThumbAngle, deltaThumbAndTick); @@ -531,12 +497,12 @@ public class ZoomRing extends View { if (deltaThumbAndTick > MAX_ABS_JUMP_DELTA_ANGLE || deltaThumbAndTick < -MAX_ABS_JUMP_DELTA_ANGLE) { // Trying to jump too far, ignore this touch interaction - setMode(MODE_IGNORE_UNTIL_TOUCHES_THUMB); + mMode = MODE_IGNORE_UNTIL_UP; return true; } + // Make sure we only let them jump within bounds if (boundAngle != Integer.MIN_VALUE) { - // Cap the user's jump to the bound tickAngle = boundAngle; } } else { @@ -549,59 +515,47 @@ public class ZoomRing extends View { deltaThumbAndTick = getDelta(mThumbAngle, tickAngle, !oldDirectionIsCcw); boundAngle = getBoundIfExceeds(mThumbAngle, deltaThumbAndTick); if (boundAngle != Integer.MIN_VALUE) { - // Cannot get to the tapped location because it is out-of-bounds - setMode(MODE_IGNORE_UNTIL_TOUCHES_THUMB); + // Not allowed to be here, it is between two bounds + mMode = MODE_IGNORE_UNTIL_UP; return true; } } } - setMode(MODE_WAITING_FOR_DRAG_THUMB_AFTER_JUMP); + mMode = MODE_WAITING_FOR_DRAG_THUMB; mWaitingForDragThumbDownAngle = touchAngle; boolean ccw = deltaThumbAndTick > 0; setThumbAngleAnimated(tickAngle, 0, ccw); - /* - * Our thumb scrolling animation takes us from mThumbAngle to - * tickAngle, so manifest that as the user dragging the thumb - * there. - */ + // Our thumb scrolling animation takes us from mThumbAngle to tickAngle onThumbDragStarted(mThumbAngle); - // We know which direction we want to go onThumbDragged(tickAngle, true, ccw); } else { - // They tapped somewhere else on the widget - setMode(MODE_WAITING_FOR_MOVE_ZOOM_RING); + // They tapped somewhere else + mMode = MODE_WAITING_FOR_MOVE_ZOOM_RING; mCallback.onZoomRingSetMovableHintVisible(true); } - } else if (mMode == MODE_WAITING_FOR_DRAG_THUMB_AFTER_JUMP) { + } else if (mMode == MODE_WAITING_FOR_DRAG_THUMB) { int deltaDownAngle = getDelta(mWaitingForDragThumbDownAngle, touchAngle); if ((deltaDownAngle < -THUMB_DRAG_SLOP || deltaDownAngle > THUMB_DRAG_SLOP) && isDeltaInBounds(mWaitingForDragThumbDownAngle, deltaDownAngle)) { - setMode(MODE_DRAG_THUMB); - - // No need to call onThumbDragStarted, since that was done when they tapped-to-jump + mMode = MODE_DRAG_THUMB; } } else if (mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) { if (Math.abs(x - mPreviousDownX) > mTouchSlop || Math.abs(y - mPreviousDownY) > mTouchSlop) { /* Make sure the user has moved the slop amount before going into that mode. */ - setMode(MODE_MOVE_ZOOM_RING); + mMode = MODE_MOVE_ZOOM_RING; mCallback.onZoomRingMovingStarted(); } - } else if (mMode == MODE_IGNORE_UNTIL_TOUCHES_THUMB) { - if (isTouchingThumb) { - // The user is back on the thumb, let's go back to the previous mode - setMode(mPreviousMode); - } } // Purposefully not an "else if" if (mMode == MODE_DRAG_THUMB || mMode == MODE_TAP_DRAG) { - if (isTouchingRing) { + if (isInRingBounds) { onThumbDragged(touchAngle, false, false); } } else if (mMode == MODE_MOVE_ZOOM_RING) { @@ -611,39 +565,24 @@ public class ZoomRing extends View { return true; } - private void onTouchUp(long time, boolean isTouchingRing) { - int mode = mMode; - if (mode == MODE_IGNORE_UNTIL_TOUCHES_THUMB) { - // For cleaning up, pretend like the user was still in the previous mode - mode = mPreviousMode; - } - - if (mode == MODE_MOVE_ZOOM_RING || mode == MODE_WAITING_FOR_MOVE_ZOOM_RING) { + private void onTouchUp(long time) { + if (mMode == MODE_MOVE_ZOOM_RING || mMode == MODE_WAITING_FOR_MOVE_ZOOM_RING) { mCallback.onZoomRingSetMovableHintVisible(false); - if (mode == MODE_MOVE_ZOOM_RING) { + if (mMode == MODE_MOVE_ZOOM_RING) { mCallback.onZoomRingMovingStopped(); } - } else if (mode == MODE_DRAG_THUMB || mode == MODE_TAP_DRAG || - mode == MODE_WAITING_FOR_DRAG_THUMB_AFTER_JUMP) { + } else if (mMode == MODE_DRAG_THUMB || mMode == MODE_TAP_DRAG || + mMode == MODE_WAITING_FOR_DRAG_THUMB) { onThumbDragStopped(); - if (mode == MODE_DRAG_THUMB || mode == MODE_TAP_DRAG) { + if (mMode == MODE_DRAG_THUMB) { // Animate back to a tick setThumbAngleAnimated(mPreviousCallbackAngle, 0); } } + + mPreviousUpTime = time; mCallback.onUserInteractionStopped(); - - if (!isTouchingRing) { - mPreviousCenterUpTime = time; - } - } - - private void setMode(int mode) { - if (mode != mMode) { - mPreviousMode = mMode; - mMode = mode; - } } private boolean isDeltaInBounds(int startAngle, int deltaAngle) { @@ -742,8 +681,9 @@ public class ZoomRing extends View { int totalDeltaAngle; totalDeltaAngle = getDelta(mPreviousCallbackAngle, touchAngle, useDirection, ccw); - if (totalDeltaAngle >= mFuzzyCallbackThreshold - || totalDeltaAngle <= -mFuzzyCallbackThreshold) { + int fuzzyCallbackThreshold = (int) (mCallbackThreshold * 0.65f); + if (totalDeltaAngle >= fuzzyCallbackThreshold + || totalDeltaAngle <= -fuzzyCallbackThreshold) { if (!useDirection) { // Set ccw to match the direction found by getDelta @@ -797,7 +737,7 @@ public class ZoomRing extends View { // We bounded the touch angle totalDeltaAngle = getDelta(mPreviousCallbackAngle, touchAngle, useDirection, ccw); animateThumbToNewAngle = true; - setMode(MODE_IGNORE_UNTIL_TOUCHES_THUMB); + mMode = MODE_IGNORE_UNTIL_UP; } @@ -824,13 +764,11 @@ public class ZoomRing extends View { boolean canStillZoom = mCallback.onZoomRingThumbDragged( deltaLevels, mThumbDragStartAngle, touchAngle); - if (mVibration) { - // TODO: we're trying the haptics to see how it goes with - // users, so we're ignoring the settings (for now) - performHapticFeedback(HapticFeedbackConstants.ZOOM_RING_TICK, - HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING | - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - } + // TODO: we're trying the haptics to see how it goes with + // users, so we're ignoring the settings (for now) + performHapticFeedback(HapticFeedbackConstants.ZOOM_RING_TICK, + HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING | + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); // Set the callback angle to the actual angle based on how many delta levels we gave mPreviousCallbackAngle = getValidAngle( @@ -853,134 +791,6 @@ public class ZoomRing extends View { setThumbAngleAuto(touchAngle, useDirection, ccw); } } -// private void onThumbDragged(int touchAngle, boolean useDirection, boolean ccw) { -// int deltaPrevCbAndTouch = getDelta(mPreviousCallbackAngle, touchAngle, useDirection, ccw); -// -// if (!useDirection) { -// // Set ccw to match the direction found by getDelta -// ccw = deltaPrevCbAndTouch > 0; -// useDirection = true; -// } -// -// boolean animateThumbToNewAngle = false; -// boolean animationCcw = ccw; -// -// if (deltaPrevCbAndTouch >= mFuzzyCallbackThreshold -// || deltaPrevCbAndTouch <= -mFuzzyCallbackThreshold) { -// -// /* -// * When the user slides the thumb through the tick that corresponds -// * to a zoom bound, we don't want to abruptly stop there. Instead, -// * let the user slide it to the next tick, and then animate it back -// * to the original zoom bound tick. Because of this, we make sure -// * the delta from the bound is more than halfway to the next tick. -// * We make sure the bound is between the touch and the previous -// * callback to ensure we JUST passed the bound. -// */ -// int oldTouchAngle = touchAngle; -// if (ccw && mThumbCcwBound != Integer.MIN_VALUE) { -// int deltaCcwBoundAndTouch = -// getDelta(mThumbCcwBound, touchAngle, true, ccw); -// if (deltaCcwBoundAndTouch >= mCallbackThreshold / 2) { -// // The touch has past far enough from the bound -// int deltaPreviousCbAndTouch = getDelta(mPreviousCallbackAngle, -// touchAngle, true, ccw); -// if (deltaPreviousCbAndTouch >= deltaCcwBoundAndTouch) { -// // The bound is between the previous callback angle and the touch -// // Cap to the bound -// touchAngle = mThumbCcwBound; -// /* -// * We're moving the touch BACK to the bound, so animate -// * back in the opposite direction that passed the bound. -// */ -// animationCcw = false; -// } -// } -// } else if (!ccw && mThumbCwBound != Integer.MIN_VALUE) { -// // See block above for general comments -// int deltaCwBoundAndTouch = -// getDelta(mThumbCwBound, touchAngle, true, ccw); -// if (deltaCwBoundAndTouch <= -mCallbackThreshold / 2) { -// int deltaPreviousCbAndTouch = getDelta(mPreviousCallbackAngle, -// touchAngle, true, ccw); -// /* -// * Both of these will be negative since we got delta in -// * clockwise direction, and we want the magnitude of -// * deltaPreviousCbAndTouch to be greater than the magnitude -// * of deltaCwBoundAndTouch -// */ -// if (deltaPreviousCbAndTouch <= deltaCwBoundAndTouch) { -// touchAngle = mThumbCwBound; -// animationCcw = true; -// } -// } -// } -// if (touchAngle != oldTouchAngle) { -// // We bounded the touch angle -// deltaPrevCbAndTouch = getDelta(mPreviousCallbackAngle, touchAngle, true, ccw); -// // Animate back to the bound -// animateThumbToNewAngle = true; -// // Disallow movement now -// setMode(MODE_IGNORE_UNTIL_UP); -// } -// -// -// /* -// * Prevent it from jumping too far (this could happen if the user -// * goes through the center) -// */ -// -// if (mEnforceMaxAbsJump) { -// if (deltaPrevCbAndTouch <= -MAX_ABS_JUMP_DELTA_ANGLE) { -// deltaPrevCbAndTouch = -MAX_ABS_JUMP_DELTA_ANGLE; -// animateThumbToNewAngle = true; -// } else if (deltaPrevCbAndTouch >= MAX_ABS_JUMP_DELTA_ANGLE) { -// deltaPrevCbAndTouch = MAX_ABS_JUMP_DELTA_ANGLE; -// animateThumbToNewAngle = true; -// } -// } -// -// /* -// * We need to cover the edge case of a user grabbing the thumb, -// * going into the center of the widget, and then coming out from the -// * center to an angle that's slightly below the angle he's trying to -// * hit. If we do int division, we'll end up with one level lower -// * than the one he was going for. -// */ -// int deltaLevels = Math.round((float) deltaPrevCbAndTouch / mCallbackThreshold); -// if (deltaLevels != 0) { -// boolean canStillZoom = mCallback.onZoomRingThumbDragged( -// deltaLevels, mThumbDragStartAngle, touchAngle); -// -// if (mVibration) { -// // TODO: we're trying the haptics to see how it goes with -// // users, so we're ignoring the settings (for now) -// performHapticFeedback(HapticFeedbackConstants.ZOOM_RING_TICK, -// HapticFeedbackConstants.FLAG_IGNORE_GLOBAL_SETTING | -// HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); -// -// } -// // Set the callback angle to the actual angle based on how many delta levels we gave -// mPreviousCallbackAngle = getValidAngle( -// mPreviousCallbackAngle + (deltaLevels * mCallbackThreshold)); -// } -// } -// -// if (DRAW_TRAIL) { -// int deltaAngle = getDelta(mThumbAngle, touchAngle, true, ccw); -// mAcculumalatedTrailAngle += Math.toDegrees(deltaAngle / (double) RADIAN_INT_MULTIPLIER); -// } -// -// if (animateThumbToNewAngle) { -// setThumbAngleAnimated(touchAngle, 0, animationCcw); -// } else { -// /* -// * Use regular ccw here because animationCcw will never have been -// * changed if animateThumbToNewAngle is false -// */ -// setThumbAngleAuto(touchAngle, true, ccw); -// } -// } private int getValidAngle(int invalidAngle) { if (invalidAngle < 0) { @@ -1008,16 +818,16 @@ public class ZoomRing extends View { mCallback.onZoomRingThumbDraggingStopped(); } - private void onZoomRingMoved(int rawX, int rawY) { + private void onZoomRingMoved(int x, int y) { if (mPreviousWidgetDragX != Integer.MIN_VALUE) { - int deltaX = rawX - mPreviousWidgetDragX; - int deltaY = rawY - mPreviousWidgetDragY; + int deltaX = x - mPreviousWidgetDragX; + int deltaY = y - mPreviousWidgetDragY; - mCallback.onZoomRingMoved(deltaX, deltaY, rawX, rawY); + mCallback.onZoomRingMoved(deltaX, deltaY); } - mPreviousWidgetDragX = rawX; - mPreviousWidgetDragY = rawY; + mPreviousWidgetDragX = x; + mPreviousWidgetDragY = y; } @Override @@ -1049,17 +859,15 @@ public class ZoomRing extends View { protected void onDraw(Canvas canvas) { super.onDraw(canvas); - if (mThumbVisible) { + if (mDrawThumb) { if (DRAW_TRAIL) { mTrail.draw(canvas); } if ((mThumbArrowsToDraw & THUMB_ARROW_PLUS) != 0) { mThumbPlusArrowDrawable.draw(canvas); - mThumbPlusDrawable.draw(canvas); } if ((mThumbArrowsToDraw & THUMB_ARROW_MINUS) != 0) { mThumbMinusArrowDrawable.draw(canvas); - mThumbMinusDrawable.draw(canvas); } mThumbDrawable.draw(canvas); } @@ -1069,28 +877,6 @@ public class ZoomRing extends View { int level = -angle * 10000 / ZoomRing.TWO_PI_INT_MULTIPLIED; mThumbPlusArrowDrawable.setLevel(level); mThumbMinusArrowDrawable.setLevel(level); - - // Assume it is a square - int halfSideLength = mThumbPlusDrawable.getIntrinsicHeight() / 2; - int unoffsetAngle = angle + mZeroAngle; - - int plusCenterX = (int) (Math.cos(1f * (unoffsetAngle - THUMB_PLUS_MINUS_OFFSET_ANGLE) - / RADIAN_INT_MULTIPLIER) * THUMB_PLUS_MINUS_DISTANCE) + mCenterX; - int plusCenterY = (int) (Math.sin(1f * (unoffsetAngle - THUMB_PLUS_MINUS_OFFSET_ANGLE) - / RADIAN_INT_MULTIPLIER) * THUMB_PLUS_MINUS_DISTANCE) * -1 + mCenterY; - mThumbPlusDrawable.setBounds(plusCenterX - halfSideLength, - plusCenterY - halfSideLength, - plusCenterX + halfSideLength, - plusCenterY + halfSideLength); - - int minusCenterX = (int) (Math.cos(1f * (unoffsetAngle + THUMB_PLUS_MINUS_OFFSET_ANGLE) - / RADIAN_INT_MULTIPLIER) * THUMB_PLUS_MINUS_DISTANCE) + mCenterX; - int minusCenterY = (int) (Math.sin(1f * (unoffsetAngle + THUMB_PLUS_MINUS_OFFSET_ANGLE) - / RADIAN_INT_MULTIPLIER) * THUMB_PLUS_MINUS_DISTANCE) * -1 + mCenterY; - mThumbMinusDrawable.setBounds(minusCenterX - halfSideLength, - minusCenterY - halfSideLength, - minusCenterX + halfSideLength, - minusCenterY + halfSideLength); } public void setThumbArrowsVisible(boolean visible) { @@ -1100,7 +886,6 @@ public class ZoomRing extends View { if (callbackAngle < mThumbCwBound - RADIAN_INT_ERROR || callbackAngle > mThumbCwBound + RADIAN_INT_ERROR) { mThumbPlusArrowDrawable.setAlpha(255); - mThumbPlusDrawable.setAlpha(255); mThumbArrowsToDraw |= THUMB_ARROW_PLUS; } else { mThumbArrowsToDraw &= ~THUMB_ARROW_PLUS; @@ -1108,7 +893,6 @@ public class ZoomRing extends View { if (callbackAngle < mThumbCcwBound - RADIAN_INT_ERROR || callbackAngle > mThumbCcwBound + RADIAN_INT_ERROR) { mThumbMinusArrowDrawable.setAlpha(255); - mThumbMinusDrawable.setAlpha(255); mThumbArrowsToDraw |= THUMB_ARROW_MINUS; } else { mThumbArrowsToDraw &= ~THUMB_ARROW_MINUS; @@ -1133,14 +917,10 @@ public class ZoomRing extends View { if (mThumbArrowsAlpha < 0) mThumbArrowsAlpha = 0; if ((mThumbArrowsToDraw & THUMB_ARROW_PLUS) != 0) { mThumbPlusArrowDrawable.setAlpha(mThumbArrowsAlpha); - mThumbPlusDrawable.setAlpha(mThumbArrowsAlpha); - invalidateDrawable(mThumbPlusDrawable); invalidateDrawable(mThumbPlusArrowDrawable); } if ((mThumbArrowsToDraw & THUMB_ARROW_MINUS) != 0) { mThumbMinusArrowDrawable.setAlpha(mThumbArrowsAlpha); - mThumbMinusDrawable.setAlpha(mThumbArrowsAlpha); - invalidateDrawable(mThumbMinusDrawable); invalidateDrawable(mThumbMinusArrowDrawable); } @@ -1161,7 +941,7 @@ public class ZoomRing extends View { void onZoomRingSetMovableHintVisible(boolean visible); void onZoomRingMovingStarted(); - boolean onZoomRingMoved(int deltaX, int deltaY, int rawX, int rawY); + boolean onZoomRingMoved(int deltaX, int deltaY); void onZoomRingMovingStopped(); void onZoomRingThumbDraggingStarted(); diff --git a/core/java/android/widget/ZoomRingController.java b/core/java/android/widget/ZoomRingController.java index 19f66a0c873c9..2e97fdafebade 100644 --- a/core/java/android/widget/ZoomRingController.java +++ b/core/java/android/widget/ZoomRingController.java @@ -33,7 +33,6 @@ import android.provider.Settings; import android.util.Log; import android.view.Gravity; import android.view.KeyEvent; -import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; @@ -48,36 +47,30 @@ import android.view.animation.DecelerateInterpolator; /** * TODO: Docs - * + * * If you are using this with a custom View, please call * {@link #setVisible(boolean) setVisible(false)} from the * {@link View#onDetachedFromWindow}. - * + * * @hide */ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, View.OnTouchListener, View.OnKeyListener { - + private static final int ZOOM_RING_RADIUS_INSET = 24; private static final int ZOOM_RING_RECENTERING_DURATION = 500; private static final String TAG = "ZoomRing"; - public static final boolean USE_OLD_ZOOM = false; - static int getZoomType(Context context) { - return Settings.System.getInt(context.getContentResolver(), "zoom", 1); - } + public static final boolean USE_OLD_ZOOM = false; public static boolean useOldZoom(Context context) { - return getZoomType(context) == 0; + return Settings.System.getInt(context.getContentResolver(), "zoom", 1) == 0; } - private static boolean useThisZoom(Context context) { - return getZoomType(context) == 1; - } - + private static final int ZOOM_CONTROLS_TIMEOUT = (int) ViewConfiguration.getZoomControlsTimeout(); - + // TODO: move these to ViewConfiguration or re-use existing ones // TODO: scale px values based on latest from ViewConfiguration private static final int SECOND_TAP_TIMEOUT = 500; @@ -87,12 +80,12 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, private static final int MAX_INITIATE_PAN_GAP = 10; // TODO view config private static final int INITIATE_PAN_DELAY = 300; - + private static final String SETTING_NAME_SHOWN_TOAST = "shown_zoom_ring_toast"; - + private Context mContext; private WindowManager mWindowManager; - + /** * The view that is being zoomed by this zoom ring. */ @@ -118,15 +111,15 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, /** * The {@link #mTouchTargetView}'s location in window, set on touch down. */ - private int[] mTouchTargetLocationInWindow = new int[2]; + private int[] mTouchTargetLocationInWindow = new int[2]; /** * If the zoom ring is dismissed but the user is still in a touch * interaction, we set this to true. This will ignore all touch events until * up/cancel, and then set the owner's touch listener to null. */ private boolean mReleaseTouchListenerOnUp; - - + + /* * Tap-drag is an interaction where the user first taps and then (quickly) * does the clockwise or counter-clockwise drag. In reality, this is: (down, @@ -139,40 +132,30 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, */ private int mTapDragStartX; private int mTapDragStartY; - + private static final int TOUCH_MODE_IDLE = 0; private static final int TOUCH_MODE_WAITING_FOR_SECOND_TAP = 1; private static final int TOUCH_MODE_WAITING_FOR_TAP_DRAG_MOVEMENT = 2; private static final int TOUCH_MODE_FORWARDING_FOR_TAP_DRAG = 3; private int mTouchMode; - + private boolean mIsZoomRingVisible; - + private ZoomRing mZoomRing; private int mZoomRingWidth; private int mZoomRingHeight; - + /** Invokes panning of owner view if the zoom ring is touching an edge. */ private Panner mPanner; private long mTouchingEdgeStartTime; private boolean mPanningEnabledForThisInteraction; - - /** - * When the finger moves the zoom ring to an edge, this is the horizontal - * accumulator for how much the finger has moved off of its original touch - * point on the zoom ring (OOB = out-of-bounds). If < 0, the finger has - * moved that many px to the left of its original touch point on the ring. - */ - private int mMovingZoomRingOobX; - /** Vertical accumulator, see {@link #mMovingZoomRingOobX} */ - private int mMovingZoomRingOobY; - + private ImageView mPanningArrows; private Animation mPanningArrowsEnterAnimation; private Animation mPanningArrowsExitAnimation; - + private Rect mTempRect = new Rect(); - + private OnZoomListener mCallback; private ViewConfiguration mViewConfig; @@ -188,7 +171,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, * for the container's layout params. */ private int mCenteredContainerY = Integer.MIN_VALUE; - + /** * Scroller used to re-center the zoom ring if the user had dragged it to a * corner and then double-taps any point on the owner view (the owner view @@ -198,7 +181,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, * The (x,y) of the scroller is the (x,y) of the container's layout params. */ private Scroller mScroller; - + /** * When showing the zoom ring, we add the view as a new window. However, * there is logic that needs to know the size of the zoom ring which is @@ -206,7 +189,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, * the UI thread so it will be exceuted AFTER the layout. This is the logic. */ private Runnable mPostedVisibleInitializer; - + /** * Only touch from the main thread. */ @@ -216,29 +199,23 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, private IntentFilter mConfigurationChangedFilter = new IntentFilter(Intent.ACTION_CONFIGURATION_CHANGED); - + private BroadcastReceiver mConfigurationChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (!mIsZoomRingVisible) return; - + mHandler.removeMessages(MSG_POST_CONFIGURATION_CHANGED); mHandler.sendEmptyMessage(MSG_POST_CONFIGURATION_CHANGED); } }; - + /** Keeps the scroller going (or starts it). */ private static final int MSG_SCROLLER_TICK = 1; /** When configuration changes, this is called after the UI thread is idle. */ private static final int MSG_POST_CONFIGURATION_CHANGED = 2; /** Used to delay the zoom ring dismissal. */ private static final int MSG_DISMISS_ZOOM_RING = 3; - - /** - * If setVisible(true) is called and the owner view's window token is null, - * we delay the setVisible(true) call until it is not null. - */ - private static final int MSG_POST_SET_VISIBLE = 4; private Handler mHandler = new Handler() { @Override @@ -247,36 +224,26 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, case MSG_SCROLLER_TICK: onScrollerTick(); break; - + case MSG_POST_CONFIGURATION_CHANGED: onPostConfigurationChanged(); break; - + case MSG_DISMISS_ZOOM_RING: setVisible(false); break; - - case MSG_POST_SET_VISIBLE: - if (mOwnerView.getWindowToken() == null) { - // Doh, it is still null, throw an exception - throw new IllegalArgumentException( - "Cannot make the zoom ring visible if the owner view is " + - "not attached to a window."); - } - setVisible(true); - break; } - - } + + } }; - + public ZoomRingController(Context context, View ownerView) { mContext = context; mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); mPanner = new Panner(); mOwnerView = ownerView; - + mZoomRing = new ZoomRing(context); mZoomRing.setId(com.android.internal.R.id.zoomControls); mZoomRing.setLayoutParams(new FrameLayout.LayoutParams( @@ -284,7 +251,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); mZoomRing.setCallback(this); - + createPanningArrows(); mContainerLayoutParams = new LayoutParams(); @@ -302,12 +269,12 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, mContainer = new FrameLayout(context); mContainer.setLayoutParams(mContainerLayoutParams); mContainer.setMeasureAllChildren(true); - + mContainer.addView(mZoomRing); mContainer.addView(mPanningArrows); - + mScroller = new Scroller(context, new DecelerateInterpolator()); - + mViewConfig = ViewConfiguration.get(context); } @@ -320,7 +287,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, FrameLayout.LayoutParams.WRAP_CONTENT, Gravity.CENTER)); mPanningArrows.setVisibility(View.INVISIBLE); - + mPanningArrowsEnterAnimation = AnimationUtils.loadAnimation(mContext, com.android.internal.R.anim.fade_in); mPanningArrowsExitAnimation = AnimationUtils.loadAnimation(mContext, @@ -332,7 +299,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, * get a callback. Once there is a callback, the accumulator resets. For * example, if you set this to PI/6, it will give a callback every time the * user moves PI/6 amount on the ring. - * + * * @param callbackThreshold The angle for the callback threshold, in radians */ public void setZoomCallbackThreshold(float callbackThreshold) { @@ -341,7 +308,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, /** * Sets a drawable for the zoom ring track. - * + * * @param drawable The drawable to use for the track. * @hide Need a better way of doing this, but this one-off for browser so it * can have its final look for the usability study @@ -349,11 +316,11 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, public void setZoomRingTrack(int drawable) { mZoomRing.setBackgroundResource(drawable); } - + public void setCallback(OnZoomListener callback) { mCallback = callback; } - + public void setThumbAngle(float angle) { mZoomRing.setThumbAngle((int) (angle * ZoomRing.RADIAN_INT_MULTIPLIER)); } @@ -361,21 +328,13 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, public void setThumbAngleAnimated(float angle) { mZoomRing.setThumbAngleAnimated((int) (angle * ZoomRing.RADIAN_INT_MULTIPLIER), 0); } - + public void setResetThumbAutomatically(boolean resetThumbAutomatically) { mZoomRing.setResetThumbAutomatically(resetThumbAutomatically); } - - public void setVibration(boolean vibrate) { - mZoomRing.setVibration(vibrate); - } - - public void setThumbVisible(boolean thumbVisible) { - mZoomRing.setThumbVisible(thumbVisible); - } public void setThumbClockwiseBound(float angle) { - mZoomRing.setThumbClockwiseBound(angle >= 0 ? + mZoomRing.setThumbClockwiseBound(angle >= 0 ? (int) (angle * ZoomRing.RADIAN_INT_MULTIPLIER) : Integer.MIN_VALUE); } @@ -392,26 +351,14 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, public void setVisible(boolean visible) { - if (!useThisZoom(mContext)) return; + if (useOldZoom(mContext)) return; if (visible) { - if (mOwnerView.getWindowToken() == null) { - /* - * We need a window token to show ourselves, maybe the owner's - * window hasn't been created yet but it will have been by the - * time the looper is idle, so post the setVisible(true) call. - */ - if (!mHandler.hasMessages(MSG_POST_SET_VISIBLE)) { - mHandler.sendEmptyMessage(MSG_POST_SET_VISIBLE); - } - return; - } - dismissZoomRingDelayed(ZOOM_CONTROLS_TIMEOUT); } else { mPanner.stop(); } - + if (mIsZoomRingVisible == visible) { return; } @@ -421,40 +368,40 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, if (mContainerLayoutParams.token == null) { mContainerLayoutParams.token = mOwnerView.getWindowToken(); } - + mWindowManager.addView(mContainer, mContainerLayoutParams); - + if (mPostedVisibleInitializer == null) { mPostedVisibleInitializer = new Runnable() { public void run() { refreshPositioningVariables(); resetZoomRing(); - + // TODO: remove this 'update' and just center zoom ring before the // 'add', but need to make sure we have the width and height (which // probably can only be retrieved after it's measured, which happens // after it's added). mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams); - + if (mCallback != null) { mCallback.onVisibilityChanged(true); } } - }; + }; } - + mPanningArrows.setAnimation(null); - + mHandler.post(mPostedVisibleInitializer); - + // Handle configuration changes when visible mContext.registerReceiver(mConfigurationChangedReceiver, mConfigurationChangedFilter); - + // Steal key/touches events from the owner mOwnerView.setOnKeyListener(this); mOwnerView.setOnTouchListener(this); mReleaseTouchListenerOnUp = false; - + } else { // Don't want to steal any more keys/touches mOwnerView.setOnKeyListener(null); @@ -468,45 +415,45 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, // No longer care about configuration changes mContext.unregisterReceiver(mConfigurationChangedReceiver); - + mWindowManager.removeView(mContainer); mHandler.removeCallbacks(mPostedVisibleInitializer); - + if (mCallback != null) { mCallback.onVisibilityChanged(false); } } - + } - + /** * TODO: docs - * + * * Notes: * - Touch dispatching is different. Only direct children who are clickable are eligble for touch events. * - Please ensure you set your View to INVISIBLE not GONE when hiding it. - * + * * @return */ public FrameLayout getContainer() { return mContainer; } - + public int getZoomRingId() { return mZoomRing.getId(); } - + private void dismissZoomRingDelayed(int delay) { mHandler.removeMessages(MSG_DISMISS_ZOOM_RING); mHandler.sendEmptyMessageDelayed(MSG_DISMISS_ZOOM_RING, delay); } - + private void resetZoomRing() { mScroller.abortAnimation(); - + mContainerLayoutParams.x = mCenteredContainerX; mContainerLayoutParams.y = mCenteredContainerY; - + // Reset the thumb mZoomRing.resetThumbAngle(); } @@ -514,15 +461,13 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, /** * Should be called by the client for each event belonging to the second tap * (the down, move, up, and cancel events). - * + * * @param event The event belonging to the second tap. * @return Whether the event was consumed. */ public boolean handleDoubleTapEvent(MotionEvent event) { - if (!useThisZoom(mContext)) return false; - int action = event.getAction(); - + // TODO: make sure this works well with the // ownerView.setOnTouchListener(this) instead of window receiving // touches @@ -530,19 +475,19 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, mTouchMode = TOUCH_MODE_WAITING_FOR_TAP_DRAG_MOVEMENT; int x = (int) event.getX(); int y = (int) event.getY(); - + refreshPositioningVariables(); setVisible(true); centerPoint(x, y); - ensureZoomRingIsCentered(); - + ensureZoomRingIsCentered(); + // Tap drag mode stuff mTapDragStartX = x; mTapDragStartY = y; } else if (action == MotionEvent.ACTION_CANCEL) { mTouchMode = TOUCH_MODE_IDLE; - + } else { // action is move or up switch (mTouchMode) { case TOUCH_MODE_WAITING_FOR_TAP_DRAG_MOVEMENT: { @@ -558,29 +503,29 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, setTouchTargetView(mZoomRing); } return true; - + case MotionEvent.ACTION_UP: mTouchMode = TOUCH_MODE_IDLE; break; } break; } - + case TOUCH_MODE_FORWARDING_FOR_TAP_DRAG: { switch (action) { case MotionEvent.ACTION_MOVE: giveTouchToZoomRing(event); return true; - + case MotionEvent.ACTION_UP: mTouchMode = TOUCH_MODE_IDLE; - + /* * This is a power-user feature that only shows the * zoom while the user is performing the tap-drag. * That means once it is released, the zoom ring * should disappear. - */ + */ mZoomRing.setTapDragMode(false, (int) event.getX(), (int) event.getY()); dismissZoomRingDelayed(0); break; @@ -589,13 +534,13 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, } } } - + return true; } - + private void ensureZoomRingIsCentered() { LayoutParams lp = mContainerLayoutParams; - + if (lp.x != mCenteredContainerX || lp.y != mCenteredContainerY) { int width = mContainer.getWidth(); int height = mContainer.getHeight(); @@ -604,21 +549,21 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, mHandler.sendEmptyMessage(MSG_SCROLLER_TICK); } } - + private void refreshPositioningVariables() { mZoomRingWidth = mZoomRing.getWidth(); mZoomRingHeight = mZoomRing.getHeight(); - + // Calculate the owner view's bounds mOwnerView.getGlobalVisibleRect(mOwnerViewBounds); - + // Get the center Gravity.apply(Gravity.CENTER, mContainer.getWidth(), mContainer.getHeight(), mOwnerViewBounds, mTempRect); mCenteredContainerX = mTempRect.left; mCenteredContainerY = mTempRect.top; } - + /** * Centers the point (in owner view's coordinates). */ @@ -627,7 +572,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, mCallback.onCenter(x, y); } } - + private void giveTouchToZoomRing(MotionEvent event) { int rawX = (int) event.getRawX(); int rawY = (int) event.getRawY(); @@ -635,11 +580,11 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, int y = rawY - mContainerLayoutParams.y - mZoomRing.getTop(); mZoomRing.handleTouch(event.getAction(), event.getEventTime(), x, y, rawX, rawY); } - + public void onZoomRingSetMovableHintVisible(boolean visible) { - setPanningArrowsVisible(visible); + setPanningArrowsVisible(visible); } - + public void onUserInteractionStarted() { mHandler.removeMessages(MSG_DISMISS_ZOOM_RING); } @@ -651,62 +596,24 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, public void onZoomRingMovingStarted() { mScroller.abortAnimation(); mTouchingEdgeStartTime = 0; - mMovingZoomRingOobX = 0; - mMovingZoomRingOobY = 0; if (mCallback != null) { mCallback.onBeginPan(); } } - + private void setPanningArrowsVisible(boolean visible) { mPanningArrows.startAnimation(visible ? mPanningArrowsEnterAnimation : mPanningArrowsExitAnimation); mPanningArrows.setVisibility(visible ? View.VISIBLE : View.INVISIBLE); } - - public boolean onZoomRingMoved(int deltaX, int deltaY, int rawX, int rawY) { - - if (mMovingZoomRingOobX != 0) { - /* - * The finger has moved off the point where it originally touched - * the zidget. - */ - boolean wasOobLeft = mMovingZoomRingOobX < 0; - mMovingZoomRingOobX += deltaX; - if ((wasOobLeft && mMovingZoomRingOobX > 0) || - (!wasOobLeft && mMovingZoomRingOobX < 0)) { - /* - * Woot, the finger is back on the original point. Infact, it - * went PAST its original point, so take the amount it passed - * and use that as the delta to move the zoom ring. - */ - deltaX = mMovingZoomRingOobX; - // No longer out-of-bounds, reset - mMovingZoomRingOobX = 0; - } else { - // The finger is still not back, eat this movement - deltaX = 0; - } - } - - if (mMovingZoomRingOobY != 0) { - // See above for comments - boolean wasOobUp = mMovingZoomRingOobY < 0; - mMovingZoomRingOobY += deltaY; - if ((wasOobUp && mMovingZoomRingOobY > 0) || (!wasOobUp && mMovingZoomRingOobY < 0)) { - deltaY = mMovingZoomRingOobY; - mMovingZoomRingOobY = 0; - } else { - deltaY = 0; - } - } - + + public boolean onZoomRingMoved(int deltaX, int deltaY) { WindowManager.LayoutParams lp = mContainerLayoutParams; Rect ownerBounds = mOwnerViewBounds; - + int zoomRingLeft = mZoomRing.getLeft(); int zoomRingTop = mZoomRing.getTop(); - + int newX = lp.x + deltaX; int newZoomRingX = newX + zoomRingLeft; newZoomRingX = (newZoomRingX <= ownerBounds.left) ? ownerBounds.left : @@ -720,26 +627,19 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, (newZoomRingY + mZoomRingHeight > ownerBounds.bottom) ? ownerBounds.bottom - mZoomRingHeight : newZoomRingY; lp.y = newZoomRingY - zoomRingTop; - + mWindowManager.updateViewLayout(mContainer, lp); - + // Check for pan boolean horizontalPanning = true; int leftGap = newZoomRingX - ownerBounds.left; if (leftGap < MAX_PAN_GAP) { - if (leftGap == 0 && deltaX != 0 && mMovingZoomRingOobX == 0) { - // Future moves in this direction should be accumulated in mMovingZoomRingOobX - mMovingZoomRingOobX = deltaX / Math.abs(deltaX); - } if (shouldPan(leftGap)) { mPanner.setHorizontalStrength(-getStrengthFromGap(leftGap)); } } else { int rightGap = ownerBounds.right - (lp.x + mZoomRingWidth + zoomRingLeft); if (rightGap < MAX_PAN_GAP) { - if (rightGap == 0 && deltaX != 0 && mMovingZoomRingOobX == 0) { - mMovingZoomRingOobX = deltaX / Math.abs(deltaX); - } if (shouldPan(rightGap)) { mPanner.setHorizontalStrength(getStrengthFromGap(rightGap)); } @@ -748,21 +648,15 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, horizontalPanning = false; } } - + int topGap = newZoomRingY - ownerBounds.top; if (topGap < MAX_PAN_GAP) { - if (topGap == 0 && deltaY != 0 && mMovingZoomRingOobY == 0) { - mMovingZoomRingOobY = deltaY / Math.abs(deltaY); - } if (shouldPan(topGap)) { mPanner.setVerticalStrength(-getStrengthFromGap(topGap)); } } else { int bottomGap = ownerBounds.bottom - (lp.y + mZoomRingHeight + zoomRingTop); if (bottomGap < MAX_PAN_GAP) { - if (bottomGap == 0 && deltaY != 0 && mMovingZoomRingOobY == 0) { - mMovingZoomRingOobY = deltaY / Math.abs(deltaY); - } if (shouldPan(bottomGap)) { mPanner.setVerticalStrength(getStrengthFromGap(bottomGap)); } @@ -776,13 +670,13 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, } } } - + return true; } - + private boolean shouldPan(int gap) { if (mPanningEnabledForThisInteraction) return true; - + if (gap < MAX_INITIATE_PAN_GAP) { long time = SystemClock.elapsedRealtime(); if (mTouchingEdgeStartTime != 0 && @@ -799,7 +693,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, } return false; } - + public void onZoomRingMovingStopped() { mPanner.stop(); setPanningArrowsVisible(false); @@ -807,18 +701,18 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, mCallback.onEndPan(); } } - + private int getStrengthFromGap(int gap) { return gap > MAX_PAN_GAP ? 0 : (MAX_PAN_GAP - gap) * 100 / MAX_PAN_GAP; } - + public void onZoomRingThumbDraggingStarted() { if (mCallback != null) { mCallback.onBeginDrag(); } } - + public boolean onZoomRingThumbDragged(int numLevels, int startAngle, int curAngle) { if (mCallback != null) { int deltaZoomLevel = -numLevels; @@ -826,17 +720,17 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, mZoomRingWidth / 2; int globalZoomCenterY = mContainerLayoutParams.y + mZoomRing.getTop() + mZoomRingHeight / 2; - + return mCallback.onDragZoom(deltaZoomLevel, globalZoomCenterX - mOwnerViewBounds.left, globalZoomCenterY - mOwnerViewBounds.top, (float) startAngle / ZoomRing.RADIAN_INT_MULTIPLIER, (float) curAngle / ZoomRing.RADIAN_INT_MULTIPLIER); } - + return false; } - + public void onZoomRingThumbDraggingStopped() { if (mCallback != null) { mCallback.onEndDrag(); @@ -846,35 +740,35 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, public void onZoomRingDismissed(boolean dismissImmediately) { if (dismissImmediately) { mHandler.removeMessages(MSG_DISMISS_ZOOM_RING); - setVisible(false); + setVisible(false); } else { dismissZoomRingDelayed(ZOOM_RING_DISMISS_DELAY); } } - + public void onRingDown(int tickAngle, int touchAngle) { } - + public boolean onTouch(View v, MotionEvent event) { if (sTutorialDialog != null && sTutorialDialog.isShowing() && SystemClock.elapsedRealtime() - sTutorialShowTime >= TUTORIAL_MIN_DISPLAY_TIME) { finishZoomTutorial(); } - + int action = event.getAction(); if (mReleaseTouchListenerOnUp) { - // The ring was dismissed but we need to throw away all events until the up + // The ring was dismissed but we need to throw away all events until the up if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) { mOwnerView.setOnTouchListener(null); setTouchTargetView(null); mReleaseTouchListenerOnUp = false; } - + // Eat this event return true; } - + View targetView = mTouchTargetView; switch (action) { @@ -882,7 +776,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, targetView = getViewForTouch((int) event.getRawX(), (int) event.getRawY()); setTouchTargetView(targetView); break; - + case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: setTouchTargetView(null); @@ -893,7 +787,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, // The upperleft corner of the target view in raw coordinates int targetViewRawX = mContainerLayoutParams.x + mTouchTargetLocationInWindow[0]; int targetViewRawY = mContainerLayoutParams.y + mTouchTargetLocationInWindow[1]; - + MotionEvent containerEvent = MotionEvent.obtain(event); // Convert the motion event into the target view's coordinates (from // owner view's coordinates) @@ -902,32 +796,32 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, boolean retValue = targetView.dispatchTouchEvent(containerEvent); containerEvent.recycle(); return retValue; - + } else { if (action == MotionEvent.ACTION_DOWN) { dismissZoomRingDelayed(ZOOM_RING_DISMISS_DELAY); } - + return false; } } - + private void setTouchTargetView(View view) { mTouchTargetView = view; if (view != null) { view.getLocationInWindow(mTouchTargetLocationInWindow); } } - + /** * Returns the View that should receive a touch at the given coordinates. - * + * * @param rawX The raw X. * @param rawY The raw Y. * @return The view that should receive the touches, or null if there is not one. */ private View getViewForTouch(int rawX, int rawY) { - // Check to see if it is touching the ring + // Check to see if it is touching the ring int containerCenterX = mContainerLayoutParams.x + mContainer.getWidth() / 2; int containerCenterY = mContainerLayoutParams.y + mContainer.getHeight() / 2; int distanceFromCenterX = rawX - containerCenterX; @@ -938,7 +832,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, zoomRingRadius * zoomRingRadius) { return mZoomRing; } - + // Check to see if it is touching any other clickable View. // Reverse order so the child drawn on top gets first dibs. int containerCoordsX = rawX - mContainerLayoutParams.x; @@ -950,13 +844,13 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, !child.isClickable()) { continue; } - + child.getHitRect(frame); if (frame.contains(containerCoordsX, containerCoordsY)) { return child; } } - + return null; } @@ -967,34 +861,34 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, case KeyEvent.KEYCODE_DPAD_RIGHT: // Eat these return true; - + case KeyEvent.KEYCODE_DPAD_UP: case KeyEvent.KEYCODE_DPAD_DOWN: // Keep the zoom alive a little longer dismissZoomRingDelayed(ZOOM_CONTROLS_TIMEOUT); // They started zooming, hide the thumb arrows mZoomRing.setThumbArrowsVisible(false); - + if (mCallback != null && event.getAction() == KeyEvent.ACTION_DOWN) { mCallback.onSimpleZoom(keyCode == KeyEvent.KEYCODE_DPAD_UP); } - + return true; } - + return false; } private void onScrollerTick() { if (!mScroller.computeScrollOffset() || !mIsZoomRingVisible) return; - + mContainerLayoutParams.x = mScroller.getCurrX(); mContainerLayoutParams.y = mScroller.getCurrY(); mWindowManager.updateViewLayout(mContainer, mContainerLayoutParams); mHandler.sendEmptyMessage(MSG_SCROLLER_TICK); } - + private void onPostConfigurationChanged() { dismissZoomRingDelayed(ZOOM_CONTROLS_TIMEOUT); refreshPositioningVariables(); @@ -1014,7 +908,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, * before. Furthermore, if the application does not have privilege to write * to the system settings, it will store this bit locally in a shared * preference. - * + * * @hide This should only be used by our main apps--browser, maps, and * gallery */ @@ -1023,65 +917,53 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, if (Settings.System.getInt(cr, SETTING_NAME_SHOWN_TOAST, 0) == 1) { return; } - + SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE); if (sp.getInt(SETTING_NAME_SHOWN_TOAST, 0) == 1) { return; } - + if (sTutorialDialog != null && sTutorialDialog.isShowing()) { sTutorialDialog.dismiss(); } - - LayoutInflater layoutInflater = - (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); - TextView textView = (TextView) layoutInflater.inflate( - com.android.internal.R.layout.alert_dialog_simple_text, null) - .findViewById(android.R.id.text1); - textView.setText(com.android.internal.R.string.tutorial_double_tap_to_zoom_message_short); sTutorialDialog = new AlertDialog.Builder(context) - .setView(textView) + .setMessage( + com.android.internal.R.string.tutorial_double_tap_to_zoom_message_short) .setIcon(0) .create(); - + Window window = sTutorialDialog.getWindow(); window.setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); - window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND | + window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND | WindowManager.LayoutParams.FLAG_BLUR_BEHIND); window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE); - + sTutorialDialog.show(); sTutorialShowTime = SystemClock.elapsedRealtime(); } - - public static void finishZoomTutorial(Context context, boolean userNotified) { + + public void finishZoomTutorial() { if (sTutorialDialog == null) return; - + sTutorialDialog.dismiss(); sTutorialDialog = null; - + // Record that they have seen the tutorial - if (userNotified) { - try { - Settings.System.putInt(context.getContentResolver(), SETTING_NAME_SHOWN_TOAST, 1); - } catch (SecurityException e) { - /* - * The app does not have permission to clear this global flag, make - * sure the user does not see the message when he comes back to this - * same app at least. - */ - SharedPreferences sp = context.getSharedPreferences("_zoom", Context.MODE_PRIVATE); - sp.edit().putInt(SETTING_NAME_SHOWN_TOAST, 1).commit(); - } + try { + Settings.System.putInt(mContext.getContentResolver(), SETTING_NAME_SHOWN_TOAST, 1); + } catch (SecurityException e) { + /* + * The app does not have permission to clear this global flag, make + * sure the user does not see the message when he comes back to this + * same app at least. + */ + SharedPreferences sp = mContext.getSharedPreferences("_zoom", Context.MODE_PRIVATE); + sp.edit().putInt(SETTING_NAME_SHOWN_TOAST, 1).commit(); } } - - public void finishZoomTutorial() { - finishZoomTutorial(mContext, true); - } - + public void setPannerStartVelocity(float startVelocity) { mPanner.mStartVelocity = startVelocity; } @@ -1101,27 +983,27 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, private class Panner implements Runnable { private static final int RUN_DELAY = 15; private static final float STOP_SLOWDOWN = 0.8f; - + private final Handler mUiHandler = new Handler(); - + private int mVerticalStrength; private int mHorizontalStrength; private boolean mStopping; - + /** The time this current pan started. */ private long mStartTime; - + /** The time of the last callback to pan the map/browser/etc. */ private long mPreviousCallbackTime; - + // TODO Adjust to be DPI safe private float mStartVelocity = 135; private float mAcceleration = 160; private float mMaxVelocity = 1000; private int mStartAcceleratingDuration = 700; private float mVelocity; - + /** -100 (full left) to 0 (none) to 100 (full right) */ public void setHorizontalStrength(int horizontalStrength) { if (mHorizontalStrength == 0 && mVerticalStrength == 0 && horizontalStrength != 0) { @@ -1129,7 +1011,7 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, } else if (mVerticalStrength == 0 && horizontalStrength == 0) { stop(); } - + mHorizontalStrength = horizontalStrength; mStopping = false; } @@ -1141,11 +1023,11 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, } else if (mHorizontalStrength == 0 && verticalStrength == 0) { stop(); } - - mVerticalStrength = verticalStrength; + + mVerticalStrength = verticalStrength; mStopping = false; } - + private void start() { mUiHandler.post(this); mPreviousCallbackTime = 0; @@ -1155,37 +1037,37 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, public void stop() { mStopping = true; } - + public void run() { if (mStopping) { mHorizontalStrength *= STOP_SLOWDOWN; mVerticalStrength *= STOP_SLOWDOWN; } - + if (mHorizontalStrength == 0 && mVerticalStrength == 0) { return; } - + boolean firstRun = mPreviousCallbackTime == 0; long curTime = SystemClock.elapsedRealtime(); int panAmount = getPanAmount(mPreviousCallbackTime, curTime); mPreviousCallbackTime = curTime; - + if (firstRun) { mStartTime = curTime; mVelocity = mStartVelocity; } else { int panX = panAmount * mHorizontalStrength / 100; int panY = panAmount * mVerticalStrength / 100; - + if (mCallback != null) { mCallback.onPan(panX, panY); } } - + mUiHandler.postDelayed(this, RUN_DELAY); } - + private int getPanAmount(long previousTime, long currentTime) { if (mVelocity > mMaxVelocity) { mVelocity = mMaxVelocity; @@ -1195,12 +1077,14 @@ public class ZoomRingController implements ZoomRing.OnZoomRingCallback, mVelocity += (currentTime - previousTime) * mAcceleration / 1000; } } - + return (int) ((currentTime - previousTime) * mVelocity) / 1000; } } + + public interface OnZoomListener { void onBeginDrag(); boolean onDragZoom(int deltaZoomLevel, int centerX, int centerY, float startAngle, diff --git a/core/java/com/android/internal/app/IBatteryStats.aidl b/core/java/com/android/internal/app/IBatteryStats.aidl index edda1d9230059..b502a6c13977c 100644 --- a/core/java/com/android/internal/app/IBatteryStats.aidl +++ b/core/java/com/android/internal/app/IBatteryStats.aidl @@ -28,8 +28,6 @@ interface IBatteryStats { void noteStopGps(int uid); void noteScreenOn(); void noteScreenOff(); - void notePhoneOn(); - void notePhoneOff(); void setOnBattery(boolean onBattery); long getAwakeTimeBattery(); long getAwakeTimePlugged(); diff --git a/core/java/com/android/internal/gadget/IGadgetService.aidl b/core/java/com/android/internal/gadget/IGadgetService.aidl index 9c66b9572b931..a22f3f399ec43 100644 --- a/core/java/com/android/internal/gadget/IGadgetService.aidl +++ b/core/java/com/android/internal/gadget/IGadgetService.aidl @@ -44,7 +44,6 @@ interface IGadgetService { List getInstalledProviders(); GadgetProviderInfo getGadgetInfo(int gadgetId); void bindGadgetId(int gadgetId, in ComponentName provider); - int[] getGadgetIds(in ComponentName provider); } diff --git a/core/java/com/android/internal/logging/AndroidConfig.java b/core/java/com/android/internal/logging/AndroidConfig.java index f8002c68cd4cf..d8be889998b65 100644 --- a/core/java/com/android/internal/logging/AndroidConfig.java +++ b/core/java/com/android/internal/logging/AndroidConfig.java @@ -34,14 +34,11 @@ public class AndroidConfig { super(); try { - Logger rootLogger = Logger.getLogger(""); - rootLogger.addHandler(new AndroidHandler()); - rootLogger.setLevel(Level.INFO); - - // Turn down logging in Apache libraries. - Logger.getLogger("org.apache").setLevel(Level.WARNING); + Logger.global.addHandler(new AndroidHandler()); + Logger.global.setLevel(Level.ALL); } catch (Exception ex) { ex.printStackTrace(); } - } + } + } diff --git a/core/java/com/android/internal/logging/AndroidHandler.java b/core/java/com/android/internal/logging/AndroidHandler.java index d9fcf60756eac..a6a4c6461d5b0 100644 --- a/core/java/com/android/internal/logging/AndroidHandler.java +++ b/core/java/com/android/internal/logging/AndroidHandler.java @@ -18,14 +18,14 @@ package com.android.internal.logging; import android.util.Log; -import java.util.logging.*; -import java.util.Date; -import java.text.MessageFormat; -import java.io.PrintWriter; -import java.io.StringWriter; +import java.util.logging.Formatter; +import java.util.logging.Handler; +import java.util.logging.Level; +import java.util.logging.LogRecord; +import java.util.logging.SimpleFormatter; /** - * Implements a {@link java.util.logging.Logger} handler that writes to the Android log. The + * Implements a {@link java.util.Logger} handler that writes to the Android log. The * implementation is rather straightforward. The name of the logger serves as * the log tag. Only the log levels need to be converted appropriately. For * this purpose, the following mapping is being used: @@ -81,24 +81,8 @@ public class AndroidHandler extends Handler { /** * Holds the formatter for all Android log handlers. */ - private static final Formatter THE_FORMATTER = new Formatter() { - @Override - public String format(LogRecord r) { - Throwable thrown = r.getThrown(); - if (thrown != null) { - StringWriter sw = new StringWriter(); - PrintWriter pw = new PrintWriter(sw); - sw.write(r.getMessage()); - sw.write("\n"); - thrown.printStackTrace(pw); - pw.flush(); - return sw.toString(); - } else { - return r.getMessage(); - } - } - }; - + private static final Formatter THE_FORMATTER = new SimpleFormatter(); + /** * Constructs a new instance of the Android log handler. */ @@ -122,40 +106,27 @@ public class AndroidHandler extends Handler { int level = getAndroidLevel(record.getLevel()); String tag = record.getLoggerName(); - if (tag == null) { - // Anonymous logger. - tag = "null"; - } else { - // Tags must be <= 23 characters. - int length = tag.length(); - if (length > 23) { - // Most loggers use the full class name. Try dropping the - // package. - int lastPeriod = tag.lastIndexOf("."); - if (length - lastPeriod - 1 <= 23) { - tag = tag.substring(lastPeriod + 1); - } else { - // Use last 23 chars. - tag = tag.substring(tag.length() - 23); - } - } - } - if (!Log.isLoggable(tag, level)) { return; } - - String message = getFormatter().format(record); - Log.println(level, tag, message); + + String msg; + try { + msg = getFormatter().format(record); + } catch (RuntimeException e) { + Log.e("AndroidHandler", "Error formatting log record", e); + msg = record.getMessage(); + } + Log.println(level, tag, msg); } catch (RuntimeException e) { - Log.e("AndroidHandler", "Error logging message.", e); + Log.e("AndroidHandler", "Error publishing log record", e); } } /** - * Converts a {@link java.util.logging.Logger} logging level into an Android one. + * Converts a {@link java.util.Logger} logging level into an Android one. * - * @param level The {@link java.util.logging.Logger} logging level. + * @param level The {@link java.util.Logger} logging level. * * @return The resulting Android logging level. */ diff --git a/core/java/com/android/internal/net/DbSSLSessionCache.java b/core/java/com/android/internal/net/DbSSLSessionCache.java deleted file mode 100644 index 06e4ca8e7421f..0000000000000 --- a/core/java/com/android/internal/net/DbSSLSessionCache.java +++ /dev/null @@ -1,269 +0,0 @@ -// Copyright 2009 The Android Open Source Project - -package com.android.internal.net; - -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.database.SQLException; -import android.database.sqlite.SQLiteDatabase; -import android.database.sqlite.SQLiteOpenHelper; -import android.util.Log; - -import org.apache.commons.codec.binary.Base64; -import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache; - -import java.util.HashMap; -import java.util.Map; - -import javax.net.ssl.SSLSession; - -/** - * Hook into harmony SSL cache to persist the SSL sessions. - * - * Current implementation is suitable for saving a small number of hosts - - * like google services. It can be extended with expiration and more features - * to support more hosts. - * - * {@hide} - */ -public class DbSSLSessionCache implements SSLClientSessionCache { - private static final String TAG = "DbSSLSessionCache"; - - /** - * Table where sessions are stored. - */ - public static final String SSL_CACHE_TABLE = "ssl_sessions"; - - private static final String SSL_CACHE_ID = "_id"; - - /** - * Key is host:port - port is not optional. - */ - private static final String SSL_CACHE_HOSTPORT = "hostport"; - - /** - * Base64-encoded DER value of the session. - */ - private static final String SSL_CACHE_SESSION = "session"; - - /** - * Time when the record was added - should be close to the time - * of the initial session negotiation. - */ - private static final String SSL_CACHE_TIME_SEC = "time_sec"; - - public static final String DATABASE_NAME = "ssl_sessions.db"; - - public static final int DATABASE_VERSION = 2; - - /** public for testing - */ - public static final int SSL_CACHE_ID_COL = 0; - public static final int SSL_CACHE_HOSTPORT_COL = 1; - public static final int SSL_CACHE_SESSION_COL = 2; - public static final int SSL_CACHE_TIME_SEC_COL = 3; - - public static final int MAX_CACHE_SIZE = 256; - - private final Map mExternalCache = - new HashMap(); - - - private DatabaseHelper mDatabaseHelper; - - private boolean mNeedsCacheLoad = true; - - public static final String[] PROJECTION = new String[] { - SSL_CACHE_ID, - SSL_CACHE_HOSTPORT, - SSL_CACHE_SESSION, - SSL_CACHE_TIME_SEC - }; - - /** - * Create a SslSessionCache instance, using the specified context to - * initialize the database. - * - * This constructor will use the default database - created for the application - * context. - * - * @param activityContext - */ - public DbSSLSessionCache(Context activityContext) { - Context appContext = activityContext.getApplicationContext(); - mDatabaseHelper = new DatabaseHelper(appContext); - } - - /** - * Create a SslSessionCache that uses a specific database. - * - * - * @param database - */ - public DbSSLSessionCache(DatabaseHelper database) { - this.mDatabaseHelper = database; - } - - public void putSessionData(SSLSession session, byte[] der) { - if (mDatabaseHelper == null) { - return; - } - synchronized (this.getClass()) { - SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); - if (mExternalCache.size() == MAX_CACHE_SIZE) { - // remove oldest. - // TODO: check if the new one is in cached already ( i.e. update ). - Cursor byTime = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE, - PROJECTION, null, null, null, null, SSL_CACHE_TIME_SEC); - if (byTime.moveToFirst()) { - // TODO: can I do byTime.deleteRow() ? - String hostPort = byTime.getString(SSL_CACHE_HOSTPORT_COL); - db.delete(SSL_CACHE_TABLE, - SSL_CACHE_HOSTPORT + "= ?" , new String[] { hostPort }); - mExternalCache.remove(hostPort); - } else { - Log.w(TAG, "No rows found"); - // something is wrong, clear it - clear(); - } - } - // Serialize native session to standard DER encoding - long t0 = System.currentTimeMillis(); - - String b64 = new String(Base64.encodeBase64(der)); - String key = session.getPeerHost() + ":" + session.getPeerPort(); - - ContentValues values = new ContentValues(); - values.put(SSL_CACHE_HOSTPORT, key); - values.put(SSL_CACHE_SESSION, b64); - values.put(SSL_CACHE_TIME_SEC, System.currentTimeMillis() / 1000); - - mExternalCache.put(key, der); - - try { - db.insert(SSL_CACHE_TABLE, null /*nullColumnHack */ , values); - } catch(SQLException ex) { - // Ignore - nothing we can do to recover, and caller shouldn't - // be affected. - Log.w(TAG, "Ignoring SQL exception when caching session", ex); - } - if (Log.isLoggable(TAG, Log.DEBUG)) { - long t1 = System.currentTimeMillis(); - Log.d(TAG, "New SSL session " + session.getPeerHost() + - " DER len: " + der.length + " " + (t1 - t0)); - } - } - - } - - public byte[] getSessionData(String host, int port) { - // Current (simple) implementation does a single lookup to DB, then saves - // all entries to the cache. - - // This works for google services - i.e. small number of certs. - // If we extend this to all processes - we should hold a separate cache - // or do lookups to DB each time. - if (mDatabaseHelper == null) { - return null; - } - synchronized(this.getClass()) { - if (mNeedsCacheLoad) { - // Don't try to load again, if something is wrong on the first - // request it'll likely be wrong each time. - mNeedsCacheLoad = false; - long t0 = System.currentTimeMillis(); - - Cursor cur = null; - try { - cur = mDatabaseHelper.getReadableDatabase().query(SSL_CACHE_TABLE, - PROJECTION, null, null, null, null, null); - if (cur.moveToFirst()) { - do { - String hostPort = cur.getString(SSL_CACHE_HOSTPORT_COL); - String value = cur.getString(SSL_CACHE_SESSION_COL); - - if (hostPort == null || value == null) { - continue; - } - // TODO: blob support ? - byte[] der = Base64.decodeBase64(value.getBytes()); - mExternalCache.put(hostPort, der); - } while (cur.moveToNext()); - - } - } catch (SQLException ex) { - Log.d(TAG, "Error loading SSL cached entries ", ex); - } finally { - if (cur != null) { - cur.close(); - } - if (Log.isLoggable(TAG, Log.DEBUG)) { - long t1 = System.currentTimeMillis(); - Log.d(TAG, "LOADED CACHED SSL " + (t1 - t0) + " ms"); - } - } - } - - String key = host + ":" + port; - - return mExternalCache.get(key); - } - } - - /** - * Reset the database and internal state. - * Used for testing or to free space. - */ - public void clear() { - synchronized(this) { - try { - mExternalCache.clear(); - mNeedsCacheLoad = true; - mDatabaseHelper.getWritableDatabase().delete(SSL_CACHE_TABLE, - null, null); - } catch (SQLException ex) { - Log.d(TAG, "Error removing SSL cached entries ", ex); - // ignore - nothing we can do about it - } - } - } - - public byte[] getSessionData(byte[] id) { - // We support client side only - the cache will do nothing for - // server-side sessions. - return null; - } - - /** Visible for testing. - */ - public static class DatabaseHelper extends SQLiteOpenHelper { - - public DatabaseHelper(Context context) { - super(context, DATABASE_NAME, null /* factory */, DATABASE_VERSION); - } - - @Override - public void onCreate(SQLiteDatabase db) { - db.execSQL("CREATE TABLE " + SSL_CACHE_TABLE + " (" + - SSL_CACHE_ID + " INTEGER PRIMARY KEY AUTOINCREMENT," + - SSL_CACHE_HOSTPORT + " TEXT UNIQUE ON CONFLICT REPLACE," + - SSL_CACHE_SESSION + " TEXT," + - SSL_CACHE_TIME_SEC + " INTEGER" + - ");"); - - // No index - we load on startup, index would slow down inserts. - // If we want to scale this to lots of rows - we could use - // index, but then we'll hit DB a bit too often ( including - // negative hits ) - } - - @Override - public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { - db.execSQL("DROP TABLE IF EXISTS " + SSL_CACHE_TABLE ); - onCreate(db); - } - - } - -} diff --git a/core/java/com/android/internal/net/SSLSessionCache.java b/core/java/com/android/internal/net/SSLSessionCache.java deleted file mode 100644 index ec02fe5892e5b..0000000000000 --- a/core/java/com/android/internal/net/SSLSessionCache.java +++ /dev/null @@ -1,101 +0,0 @@ -// Copyright 2009 The Android Open Source Project -package com.android.internal.net; - -import org.apache.harmony.xnet.provider.jsse.SSLClientSessionCache; -import org.apache.harmony.xnet.provider.jsse.SSLContextImpl; - -import java.security.KeyManagementException; -import java.security.NoSuchAlgorithmException; - -import javax.net.ssl.SSLContext; -import javax.net.ssl.SSLSocketFactory; -import javax.net.ssl.TrustManager; - -import android.content.ContentResolver; -import android.content.Context; -import android.provider.Settings; -import android.util.Log; - -/** - * Utility class to configure SSL session caching. - * - * - * - * {@hide} - */ -public class SSLSessionCache { - private static final String TAG = "SSLSessionCache"; - - private static final String CACHE_TYPE_DB = "db"; - - private static boolean sInitializationDone = false; - - // One per process - private static DbSSLSessionCache sDbCache; - - /** - * Check settings for ssl session caching. - * - * @return false if disabled. - */ - public static boolean isEnabled(ContentResolver resolver) { - String sslCache = Settings.Gservices.getString(resolver, - Settings.Gservices.SSL_SESSION_CACHE); - - if (Log.isLoggable(TAG, Log.DEBUG)) { - Log.d(TAG, "enabled " + sslCache); - } - - return CACHE_TYPE_DB.equals(sslCache); - } - - /** - * Return the configured session cache, or null if not enabled. - */ - public static SSLClientSessionCache getSessionCache(Context context) { - if (context == null) { - return null; - } - if (!sInitializationDone) { - if (isEnabled(context.getContentResolver())) { - sDbCache = new DbSSLSessionCache(context); - return sDbCache; - } - // Don't check again. - sInitializationDone = true; - } - return sDbCache; - } - - /** - * Construct the factory, using default constructor if caching is disabled. - * Refactored here to avoid duplication, used in tests. - */ - public static SSLSocketFactory getSocketFactory(Context androidContext, - TrustManager[] trustManager) { - try { - if (androidContext != null) { - SSLClientSessionCache sessionCache = getSessionCache(androidContext); - - if (sessionCache != null) { - SSLContextImpl sslContext = new SSLContextImpl(); - sslContext.engineInit(null /* kms */, - trustManager, new java.security.SecureRandom(), - sessionCache, null /* serverCache */); - return sslContext.engineGetSocketFactory(); - } - } - // default - SSLContext context = SSLContext.getInstance("TLS"); - context.init(null, trustManager, new java.security.SecureRandom()); - return context.getSocketFactory(); - - } catch (NoSuchAlgorithmException e) { - throw new AssertionError(e); - } catch (KeyManagementException e) { - throw new AssertionError(e); - } - } - - -} diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 7eea8b73da0d4..558a122c73956 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -23,7 +23,6 @@ import android.os.ParcelFormatException; import android.os.Parcelable; import android.os.SystemClock; import android.util.Log; -import android.util.Printer; import android.util.SparseArray; import java.io.File; @@ -40,14 +39,14 @@ import java.util.Map; * otherwise. */ public final class BatteryStatsImpl extends BatteryStats { + private static final String TAG = "BatteryStatsImpl"; - private static final boolean DEBUG = false; // In-memory Parcel magic number, used to detect attempts to unmarshall bad data private static final int MAGIC = 0xBA757475; // 'BATSTATS' // Current on-disk Parcel version - private static final int VERSION = 25; + private static final int VERSION = 23; private final File mFile; private final File mBackupFile; @@ -87,11 +86,9 @@ public final class BatteryStatsImpl extends BatteryStats { long mLastRealtime; boolean mScreenOn; - Timer mScreenOnTimer; - - boolean mPhoneOn; - Timer mPhoneOnTimer; - + long mLastScreenOnTimeMillis; + long mBatteryScreenOnTimeMillis; + long mPluggedScreenOnTimeMillis; /** * These provide time bases that discount the time the device is plugged * in to power. @@ -135,45 +132,16 @@ public final class BatteryStatsImpl extends BatteryStats { // Times are in microseconds for better accuracy when dividing by the // lock count, and are in "battery realtime" units. - /** - * The total time we have accumulated since the start of the original - * boot, to the last time something interesting happened in the - * current run. - */ long mTotalTime; - - /** - * The total time we loaded for the previous runs. Subtract this from - * mTotalTime to find the time for the current run of the system. - */ - long mLoadedTime; - - /** - * The run time of the last run of the system, as loaded from the - * saved data. - */ - long mLastTime; - - /** - * The value of mTotalTime when unplug() was last called. Subtract - * this from mTotalTime to find the time since the last unplug from - * power. - */ - long mUnpluggedTime; - - /** - * The last time at which we updated the timer. If mNesting is > 0, - * subtract this from the current battery time to find the amount of - * time we have been running since we last computed an update. - */ + long mLoadedTotalTime; + long mLastTotalTime; long mUpdateTime; /** - * The total time at which the timer was acquired, to determine if - * was actually held for an interesting duration. + * The value of mTotalTime when unplug() was last called, initially 0. */ - long mAcquireTime; - + long mUnpluggedTotalTime; + Timer(int type, ArrayList timerPool, ArrayList unpluggables, Parcel in) { mType = type; @@ -183,10 +151,10 @@ public final class BatteryStatsImpl extends BatteryStats { mLastCount = in.readInt(); mUnpluggedCount = in.readInt(); mTotalTime = in.readLong(); - mLoadedTime = in.readLong(); - mLastTime = in.readLong(); + mLoadedTotalTime = in.readLong(); + mLastTotalTime = in.readLong(); mUpdateTime = in.readLong(); - mUnpluggedTime = in.readLong(); + mUnpluggedTotalTime = in.readLong(); unpluggables.add(this); } @@ -203,41 +171,21 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeInt(mLastCount); out.writeInt(mUnpluggedCount); out.writeLong(computeRunTimeLocked(batteryRealtime)); - out.writeLong(mLoadedTime); - out.writeLong(mLastTime); + out.writeLong(mLoadedTotalTime); + out.writeLong(mLastTotalTime); out.writeLong(mUpdateTime); - out.writeLong(mUnpluggedTime); + out.writeLong(mUnpluggedTotalTime); } public void unplug(long batteryUptime, long batteryRealtime) { - if (DEBUG && mType < 0) { - Log.v(TAG, "unplug #" + mType + ": realtime=" + batteryRealtime - + " old mUnpluggedTime=" + mUnpluggedTime - + " old mUnpluggedCount=" + mUnpluggedCount); - } - mUnpluggedTime = computeRunTimeLocked(batteryRealtime); + mUnpluggedTotalTime = computeRunTimeLocked(batteryRealtime); mUnpluggedCount = mCount; - if (DEBUG && mType < 0) { - Log.v(TAG, "unplug #" + mType - + ": new mUnpluggedTime=" + mUnpluggedTime - + " new mUnpluggedCount=" + mUnpluggedCount); - } } public void plug(long batteryUptime, long batteryRealtime) { if (mNesting > 0) { - if (DEBUG && mType < 0) { - Log.v(TAG, "plug #" + mType + ": realtime=" + batteryRealtime - + " old mTotalTime=" + mTotalTime - + " old mUpdateTime=" + mUpdateTime); - } mTotalTime = computeRunTimeLocked(batteryRealtime); mUpdateTime = batteryRealtime; - if (DEBUG && mType < 0) { - Log.v(TAG, "plug #" + mType - + ": new mTotalTime=" + mTotalTime - + " old mUpdateTime=" + mUpdateTime); - } } } @@ -259,16 +207,16 @@ public final class BatteryStatsImpl extends BatteryStats { } @Override - public long getTotalTime(long batteryRealtime, int which) { + public long getTotalTime(long now, int which) { long val; if (which == STATS_LAST) { - val = mLastTime; + val = mLastTotalTime; } else { - val = computeRunTimeLocked(batteryRealtime); + val = computeRunTimeLocked(now); if (which == STATS_UNPLUGGED) { - val -= mUnpluggedTime; + val -= mUnpluggedTotalTime; } else if (which != STATS_TOTAL) { - val -= mLoadedTime; + val -= mLoadedTotalTime; } } @@ -297,32 +245,22 @@ public final class BatteryStatsImpl extends BatteryStats { + " mLoadedCount=" + mLoadedCount + " mLastCount=" + mLastCount + " mUnpluggedCount=" + mUnpluggedCount); Log.i("foo", "mTotalTime=" + mTotalTime - + " mLoadedTime=" + mLoadedTime); - Log.i("foo", "mLastTime=" + mLastTime - + " mUnpluggedTime=" + mUnpluggedTime); - Log.i("foo", "mUpdateTime=" + mUpdateTime - + " mAcquireTime=" + mAcquireTime); + + " mLoadedTotalTime=" + mLoadedTotalTime); + Log.i("foo", "mLastTotalTime=" + mLastTotalTime + + " mUpdateTime=" + mUpdateTime); } void startRunningLocked(BatteryStatsImpl stats) { if (mNesting++ == 0) { mUpdateTime = stats.getBatteryRealtimeLocked( SystemClock.elapsedRealtime() * 1000); - if (mTimerPool != null) { - // Accumulate time to all currently active timers before adding - // this new one to the pool. - refreshTimersLocked(stats, mTimerPool); - // Add this timer to the active pool - mTimerPool.add(this); - } + // Accumulate time to all currently active timers before adding + // this new one to the pool. + refreshTimersLocked(stats, mTimerPool); + // Add this timer to the active pool + mTimerPool.add(this); // Increment the count mCount++; - mAcquireTime = mTotalTime; - if (DEBUG && mType < 0) { - Log.v(TAG, "start #" + mType + ": mUpdateTime=" + mUpdateTime - + " mTotalTime=" + mTotalTime + " mCount=" + mCount - + " mAcquireTime=" + mAcquireTime); - } } } @@ -332,31 +270,11 @@ public final class BatteryStatsImpl extends BatteryStats { return; } if (--mNesting == 0) { - if (mTimerPool != null) { - // Accumulate time to all active counters, scaled by the total - // active in the pool, before taking this one out of the pool. - refreshTimersLocked(stats, mTimerPool); - // Remove this timer from the active pool - mTimerPool.remove(this); - } else { - final long realtime = SystemClock.elapsedRealtime() * 1000; - final long batteryRealtime = stats.getBatteryRealtimeLocked(realtime); - mNesting = 1; - mTotalTime = computeRunTimeLocked(batteryRealtime); - mNesting = 0; - } - - if (DEBUG && mType < 0) { - Log.v(TAG, "stop #" + mType + ": mUpdateTime=" + mUpdateTime - + " mTotalTime=" + mTotalTime + " mCount=" + mCount - + " mAcquireTime=" + mAcquireTime); - } - - if (mTotalTime == mAcquireTime) { - // If there was no change in the time, then discard this - // count. A somewhat cheezy strategy, but hey. - mCount--; - } + // Accumulate time to all active counters, scaled by the total + // active in the pool, before taking this one out of the pool. + refreshTimersLocked(stats, mTimerPool); + // Remove this timer from the active pool + mTimerPool.remove(this); } } @@ -379,28 +297,24 @@ public final class BatteryStatsImpl extends BatteryStats { private long computeRunTimeLocked(long curBatteryRealtime) { return mTotalTime + (mNesting > 0 - ? (curBatteryRealtime - mUpdateTime) - / (mTimerPool != null ? mTimerPool.size() : 1) - : 0); + ? (curBatteryRealtime - mUpdateTime) / mTimerPool.size() : 0); } - void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) { - long runTime = computeRunTimeLocked(batteryRealtime); + void writeSummaryFromParcelLocked(Parcel out, long curBatteryUptime) { + long runTime = computeRunTimeLocked(curBatteryUptime); // Divide by 1000 for backwards compatibility out.writeLong((runTime + 500) / 1000); - out.writeLong(((runTime - mLoadedTime) + 500) / 1000); + out.writeLong(((runTime - mLoadedTotalTime) + 500) / 1000); out.writeInt(mCount); out.writeInt(mCount - mLoadedCount); } void readSummaryFromParcelLocked(Parcel in) { // Multiply by 1000 for backwards compatibility - mTotalTime = mLoadedTime = in.readLong() * 1000; - mLastTime = in.readLong() * 1000; - mUnpluggedTime = mTotalTime; + mTotalTime = mLoadedTotalTime = in.readLong() * 1000; + mLastTotalTime = in.readLong(); mCount = mLoadedCount = in.readInt(); mLastCount = in.readInt(); - mUnpluggedCount = mCount; mNesting = 0; } } @@ -443,40 +357,47 @@ public final class BatteryStatsImpl extends BatteryStats { mUidStats.get(uid).noteStopGps(); } - public void noteScreenOnLocked() { + /** + * When the device screen or battery state changes, update the appropriate "screen on time" + * counter. + */ + private void updateScreenOnTimeLocked(boolean screenOn) { if (!mScreenOn) { - mScreenOn = true; - mScreenOnTimer.startRunningLocked(this); + Log.w(TAG, "updateScreenOnTime without mScreenOn, ignored"); + return; } + long now = SystemClock.elapsedRealtime(); + long elapsed = now - mLastScreenOnTimeMillis; + if (mOnBattery) { + mBatteryScreenOnTimeMillis += elapsed; + } else { + mPluggedScreenOnTimeMillis += elapsed; + } + if (screenOn) { + mLastScreenOnTimeMillis = now; + } + } + + public void noteScreenOnLocked() { + mScreenOn = true; + mLastScreenOnTimeMillis = SystemClock.elapsedRealtime(); } public void noteScreenOffLocked() { - if (mScreenOn) { - mScreenOn = false; - mScreenOnTimer.stopRunningLocked(this); + if (!mScreenOn) { + Log.w(TAG, "noteScreenOff without mScreenOn, ignored"); + return; } + updateScreenOnTimeLocked(false); + mScreenOn = false; } - public void notePhoneOnLocked() { - if (!mPhoneOn) { - mPhoneOn = true; - mPhoneOnTimer.startRunningLocked(this); - } + @Override public long getBatteryScreenOnTime() { + return mBatteryScreenOnTimeMillis; } - public void notePhoneOffLocked() { - if (mPhoneOn) { - mPhoneOn = false; - mPhoneOnTimer.stopRunningLocked(this); - } - } - - @Override public long getScreenOnTime(long batteryRealtime, int which) { - return mScreenOnTimer.getTotalTime(batteryRealtime, which); - } - - @Override public long getPhoneOnTime(long batteryRealtime, int which) { - return mPhoneOnTimer.getTotalTime(batteryRealtime, which); + @Override public long getPluggedScreenOnTime() { + return mPluggedScreenOnTimeMillis; } @Override public boolean getIsOnBattery() { @@ -1460,8 +1381,6 @@ public final class BatteryStatsImpl extends BatteryStats { mFile = new File(filename); mBackupFile = new File(filename + ".bak"); mStartCount++; - mScreenOnTimer = new Timer(-1, null, mUnpluggables); - mPhoneOnTimer = new Timer(-2, null, mUnpluggables); mOnBattery = mOnBatteryInternal = false; mTrackBatteryPastUptime = 0; mTrackBatteryPastRealtime = 0; @@ -1488,6 +1407,10 @@ public final class BatteryStatsImpl extends BatteryStats { public void setOnBattery(boolean onBattery) { synchronized(this) { if (mOnBattery != onBattery) { + if (mScreenOn) { + updateScreenOnTimeLocked(true); + } + mOnBattery = mOnBatteryInternal = onBattery; long uptime = SystemClock.uptimeMillis() * 1000; @@ -1502,7 +1425,7 @@ public final class BatteryStatsImpl extends BatteryStats { } else { mTrackBatteryPastUptime += uptime - mTrackBatteryUptimeStart; mTrackBatteryPastRealtime += realtime - mTrackBatteryRealtimeStart; - doPlug(getBatteryUptimeLocked(uptime), getBatteryRealtimeLocked(realtime)); + doPlug(mUnpluggedBatteryUptime, mUnpluggedBatteryRealtime); } if ((mLastWriteTime + (60 * 1000)) < mSecRealtime) { if (mFile != null) { @@ -1524,10 +1447,10 @@ public final class BatteryStatsImpl extends BatteryStats { @Override public long computeUptime(long curTime, int which) { switch (which) { - case STATS_TOTAL: return mUptime + (curTime-mUptimeStart); - case STATS_LAST: return mLastUptime; - case STATS_CURRENT: return (curTime-mUptimeStart); - case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart); + case STATS_TOTAL: return mUptime + (curTime-mUptimeStart); + case STATS_LAST: return mLastUptime; + case STATS_CURRENT: return (curTime-mUptimeStart); + case STATS_UNPLUGGED: return (curTime-mTrackBatteryUptimeStart); } return 0; } @@ -1535,25 +1458,26 @@ public final class BatteryStatsImpl extends BatteryStats { @Override public long computeRealtime(long curTime, int which) { switch (which) { - case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart); - case STATS_LAST: return mLastRealtime; - case STATS_CURRENT: return (curTime-mRealtimeStart); - case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart); + case STATS_TOTAL: return mRealtime + (curTime-mRealtimeStart); + case STATS_LAST: return mLastRealtime; + case STATS_CURRENT: return (curTime-mRealtimeStart); + case STATS_UNPLUGGED: return (curTime-mTrackBatteryRealtimeStart); } return 0; } @Override public long computeBatteryUptime(long curTime, int which) { + long uptime = getBatteryUptime(curTime); switch (which) { - case STATS_TOTAL: - return mBatteryUptime + getBatteryUptime(curTime); - case STATS_LAST: - return mBatteryLastUptime; - case STATS_CURRENT: - return getBatteryUptime(curTime); - case STATS_UNPLUGGED: - return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime; + case STATS_TOTAL: + return mBatteryUptime + uptime; + case STATS_LAST: + return mBatteryLastUptime; + case STATS_CURRENT: + return uptime; + case STATS_UNPLUGGED: + return getBatteryUptimeLocked(curTime) - mUnpluggedBatteryUptime; } return 0; } @@ -1561,14 +1485,14 @@ public final class BatteryStatsImpl extends BatteryStats { @Override public long computeBatteryRealtime(long curTime, int which) { switch (which) { - case STATS_TOTAL: - return mBatteryRealtime + getBatteryRealtimeLocked(curTime); - case STATS_LAST: - return mBatteryLastRealtime; - case STATS_CURRENT: - return getBatteryRealtimeLocked(curTime); - case STATS_UNPLUGGED: - return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime; + case STATS_TOTAL: + return mBatteryRealtime + getBatteryRealtimeLocked(curTime); + case STATS_LAST: + return mBatteryLastRealtime; + case STATS_CURRENT: + return getBatteryRealtimeLocked(curTime); + case STATS_UNPLUGGED: + return getBatteryRealtimeLocked(curTime) - mUnpluggedBatteryRealtime; } return 0; } @@ -1764,10 +1688,9 @@ public final class BatteryStatsImpl extends BatteryStats { mLastRealtime = in.readLong(); mStartCount++; + mBatteryScreenOnTimeMillis = in.readLong(); + mPluggedScreenOnTimeMillis = in.readLong(); mScreenOn = false; - mScreenOnTimer.readSummaryFromParcelLocked(in); - mPhoneOn = false; - mPhoneOnTimer.readSummaryFromParcelLocked(in); final int NU = in.readInt(); for (int iu = 0; iu < NU; iu++) { @@ -1841,10 +1764,9 @@ public final class BatteryStatsImpl extends BatteryStats { * @param out the Parcel to be written to. */ public void writeSummaryToParcel(Parcel out) { + final long NOW = getBatteryUptimeLocked(); final long NOW_SYS = SystemClock.uptimeMillis() * 1000; final long NOWREAL_SYS = SystemClock.elapsedRealtime() * 1000; - final long NOW = getBatteryUptimeLocked(NOW_SYS); - final long NOWREAL = getBatteryRealtimeLocked(NOWREAL_SYS); out.writeInt(VERSION); @@ -1858,8 +1780,8 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(computeRealtime(NOWREAL_SYS, STATS_TOTAL)); out.writeLong(computeRealtime(NOWREAL_SYS, STATS_CURRENT)); - mScreenOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); - mPhoneOnTimer.writeSummaryFromParcelLocked(out, NOWREAL); + out.writeLong(mBatteryScreenOnTimeMillis); + out.writeLong(mPluggedScreenOnTimeMillis); final int NU = mUidStats.size(); out.writeInt(NU); @@ -1876,19 +1798,19 @@ public final class BatteryStatsImpl extends BatteryStats { Uid.Wakelock wl = ent.getValue(); if (wl.mTimerFull != null) { out.writeInt(1); - wl.mTimerFull.writeSummaryFromParcelLocked(out, NOWREAL); + wl.mTimerFull.writeSummaryFromParcelLocked(out, NOW); } else { out.writeInt(0); } if (wl.mTimerPartial != null) { out.writeInt(1); - wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOWREAL); + wl.mTimerPartial.writeSummaryFromParcelLocked(out, NOW); } else { out.writeInt(0); } if (wl.mTimerWindow != null) { out.writeInt(1); - wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOWREAL); + wl.mTimerWindow.writeSummaryFromParcelLocked(out, NOW); } else { out.writeInt(0); } @@ -1904,7 +1826,7 @@ public final class BatteryStatsImpl extends BatteryStats { Uid.Sensor se = ent.getValue(); if (se.mTimer != null) { out.writeInt(1); - se.mTimer.writeSummaryFromParcelLocked(out, NOWREAL); + se.mTimer.writeSummaryFromParcelLocked(out, NOW); } else { out.writeInt(0); } @@ -1975,10 +1897,9 @@ public final class BatteryStatsImpl extends BatteryStats { mBatteryLastUptime = in.readLong(); mBatteryRealtime = in.readLong(); mBatteryLastRealtime = in.readLong(); + mBatteryScreenOnTimeMillis = in.readLong(); + mPluggedScreenOnTimeMillis = in.readLong(); mScreenOn = false; - mScreenOnTimer = new Timer(-1, null, mUnpluggables, in); - mPhoneOn = false; - mPhoneOnTimer = new Timer(-2, null, mUnpluggables, in); mUptime = in.readLong(); mUptimeStart = in.readLong(); mLastUptime = in.readLong(); @@ -1991,8 +1912,6 @@ public final class BatteryStatsImpl extends BatteryStats { mTrackBatteryUptimeStart = in.readLong(); mTrackBatteryPastRealtime = in.readLong(); mTrackBatteryRealtimeStart = in.readLong(); - mUnpluggedBatteryUptime = in.readLong(); - mUnpluggedBatteryRealtime = in.readLong(); mLastWriteTime = in.readLong(); mPartialTimers.clear(); @@ -2026,8 +1945,8 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(mBatteryLastUptime); out.writeLong(mBatteryRealtime); out.writeLong(mBatteryLastRealtime); - mScreenOnTimer.writeToParcel(out, batteryRealtime); - mPhoneOnTimer.writeToParcel(out, batteryRealtime); + out.writeLong(mBatteryScreenOnTimeMillis); + out.writeLong(mPluggedScreenOnTimeMillis); out.writeLong(mUptime); out.writeLong(mUptimeStart); out.writeLong(mLastUptime); @@ -2035,12 +1954,10 @@ public final class BatteryStatsImpl extends BatteryStats { out.writeLong(mRealtimeStart); out.writeLong(mLastRealtime); out.writeInt(mOnBattery ? 1 : 0); - out.writeLong(batteryUptime); + out.writeLong(mTrackBatteryPastUptime); out.writeLong(mTrackBatteryUptimeStart); - out.writeLong(batteryRealtime); + out.writeLong(mTrackBatteryPastRealtime); out.writeLong(mTrackBatteryRealtimeStart); - out.writeLong(mUnpluggedBatteryUptime); - out.writeLong(mUnpluggedBatteryRealtime); out.writeLong(mLastWriteTime); int size = mUidStats.size(); @@ -2063,14 +1980,4 @@ public final class BatteryStatsImpl extends BatteryStats { return new BatteryStatsImpl[size]; } }; - - public void dumpLocked(Printer pw) { - if (DEBUG) { - Log.i(TAG, "*** Screen timer:"); - mScreenOnTimer.logState(); - Log.i(TAG, "*** Phone timer:"); - mPhoneOnTimer.logState(); - } - super.dumpLocked(pw); - } } diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index ac8b589341684..f21b62f32c862 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -19,7 +19,6 @@ package com.android.internal.os; import android.content.pm.ActivityInfo; import android.content.res.Resources; import android.content.res.TypedArray; -import android.content.res.ColorStateList; import android.graphics.drawable.Drawable; import android.net.LocalServerSocket; import android.os.Debug; @@ -336,18 +335,32 @@ public class ZygoteInit { mResources.startPreloading(); if (PRELOAD_RESOURCES) { Log.i(TAG, "Preloading resources..."); - long startTime = SystemClock.uptimeMillis(); TypedArray ar = mResources.obtainTypedArray( com.android.internal.R.array.preloaded_drawables); - int N = preloadDrawables(runtime, ar); - Log.i(TAG, "...preloaded " + N + " resources in " - + (SystemClock.uptimeMillis()-startTime) + "ms."); - - startTime = SystemClock.uptimeMillis(); - ar = mResources.obtainTypedArray( - com.android.internal.R.array.preloaded_color_state_lists); - N = preloadColorStateLists(runtime, ar); + int N = ar.length(); + for (int i=0; i PRELOAD_GC_THRESHOLD) { + if (Config.LOGV) { + Log.v(TAG, " GC at " + Debug.getGlobalAllocSize()); + } + runtime.gcSoftReferences(); + runtime.runFinalizationSync(); + Debug.resetGlobalAllocSize(); + } + int id = ar.getResourceId(i, 0); + if (Config.LOGV) { + Log.v(TAG, "Preloading resource #" + Integer.toHexString(id)); + } + if (id != 0) { + Drawable dr = mResources.getDrawable(id); + if ((dr.getChangingConfigurations()&~ActivityInfo.CONFIG_FONT_SCALE) != 0) { + Log.w(TAG, "Preloaded drawable resource #0x" + + Integer.toHexString(id) + + " that varies with configuration!!"); + } + } + } Log.i(TAG, "...preloaded " + N + " resources in " + (SystemClock.uptimeMillis()-startTime) + "ms."); } @@ -359,56 +372,6 @@ public class ZygoteInit { } } - private static int preloadColorStateLists(VMRuntime runtime, TypedArray ar) { - int N = ar.length(); - for (int i=0; i PRELOAD_GC_THRESHOLD) { - if (Config.LOGV) { - Log.v(TAG, " GC at " + Debug.getGlobalAllocSize()); - } - runtime.gcSoftReferences(); - runtime.runFinalizationSync(); - Debug.resetGlobalAllocSize(); - } - int id = ar.getResourceId(i, 0); - if (Config.LOGV) { - Log.v(TAG, "Preloading resource #" + Integer.toHexString(id)); - } - if (id != 0) { - mResources.getColorStateList(id); - } - } - return N; - } - - - private static int preloadDrawables(VMRuntime runtime, TypedArray ar) { - int N = ar.length(); - for (int i=0; i PRELOAD_GC_THRESHOLD) { - if (Config.LOGV) { - Log.v(TAG, " GC at " + Debug.getGlobalAllocSize()); - } - runtime.gcSoftReferences(); - runtime.runFinalizationSync(); - Debug.resetGlobalAllocSize(); - } - int id = ar.getResourceId(i, 0); - if (Config.LOGV) { - Log.v(TAG, "Preloading resource #" + Integer.toHexString(id)); - } - if (id != 0) { - Drawable dr = mResources.getDrawable(id); - if ((dr.getChangingConfigurations()&~ActivityInfo.CONFIG_FONT_SCALE) != 0) { - Log.w(TAG, "Preloaded drawable resource #0x" - + Integer.toHexString(id) - + " (" + ar.getString(i) + ") that varies with configuration!!"); - } - } - } - return N; - } - /** * Runs several special GCs to try to clean up a few generations of * softly- and final-reachable objects, along with any other garbage. diff --git a/core/java/com/android/internal/view/IInputConnectionWrapper.java b/core/java/com/android/internal/view/IInputConnectionWrapper.java index 8e65177748b9b..4f98cee688e13 100644 --- a/core/java/com/android/internal/view/IInputConnectionWrapper.java +++ b/core/java/com/android/internal/view/IInputConnectionWrapper.java @@ -23,8 +23,7 @@ public class IInputConnectionWrapper extends IInputContext.Stub { private static final int DO_COMMIT_TEXT = 50; private static final int DO_COMMIT_COMPLETION = 55; private static final int DO_SET_SELECTION = 57; - private static final int DO_PERFORM_EDITOR_ACTION = 58; - private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 59; + private static final int DO_PERFORM_CONTEXT_MENU_ACTION = 58; private static final int DO_SET_COMPOSING_TEXT = 60; private static final int DO_FINISH_COMPOSING_TEXT = 65; private static final int DO_SEND_KEY_EVENT = 70; @@ -98,10 +97,6 @@ public class IInputConnectionWrapper extends IInputContext.Stub { dispatchMessage(obtainMessageII(DO_SET_SELECTION, start, end)); } - public void performEditorAction(int id) { - dispatchMessage(obtainMessageII(DO_PERFORM_EDITOR_ACTION, id, 0)); - } - public void performContextMenuAction(int id) { dispatchMessage(obtainMessageII(DO_PERFORM_CONTEXT_MENU_ACTION, id, 0)); } @@ -240,15 +235,6 @@ public class IInputConnectionWrapper extends IInputContext.Stub { ic.setSelection(msg.arg1, msg.arg2); return; } - case DO_PERFORM_EDITOR_ACTION: { - InputConnection ic = mInputConnection.get(); - if (ic == null || !isActive()) { - Log.w(TAG, "performEditorAction on inactive InputConnection"); - return; - } - ic.performEditorAction(msg.arg1); - return; - } case DO_PERFORM_CONTEXT_MENU_ACTION: { InputConnection ic = mInputConnection.get(); if (ic == null || !isActive()) { diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl index 02cb9e4df5e35..02b604438a358 100644 --- a/core/java/com/android/internal/view/IInputContext.aidl +++ b/core/java/com/android/internal/view/IInputContext.aidl @@ -50,8 +50,6 @@ import com.android.internal.view.IInputContextCallback; void setSelection(int start, int end); - void performEditorAction(int actionCode); - void performContextMenuAction(int id); void beginBatchEdit(); diff --git a/core/java/com/android/internal/view/InputConnectionWrapper.java b/core/java/com/android/internal/view/InputConnectionWrapper.java index b92cb45c1b42f..32d9f3dd22876 100644 --- a/core/java/com/android/internal/view/InputConnectionWrapper.java +++ b/core/java/com/android/internal/view/InputConnectionWrapper.java @@ -250,15 +250,6 @@ public class InputConnectionWrapper implements InputConnection { } } - public boolean performEditorAction(int actionCode) { - try { - mIInputContext.performEditorAction(actionCode); - return true; - } catch (RemoteException e) { - return false; - } - } - public boolean performContextMenuAction(int id) { try { mIInputContext.performContextMenuAction(id); diff --git a/core/java/com/android/internal/view/menu/ExpandedMenuView.java b/core/java/com/android/internal/view/menu/ExpandedMenuView.java index 9e4b4ce14b826..c16c165438fd7 100644 --- a/core/java/com/android/internal/view/menu/ExpandedMenuView.java +++ b/core/java/com/android/internal/view/menu/ExpandedMenuView.java @@ -80,11 +80,6 @@ public final class ExpandedMenuView extends ListView implements ItemInvoker, Men setChildrenDrawingCacheEnabled(false); } - @Override - protected boolean recycleOnMeasure() { - return false; - } - public boolean invokeItem(MenuItemImpl item) { return mMenu.performItemAction(item, 0); } diff --git a/core/java/com/android/internal/widget/EditableInputConnection.java b/core/java/com/android/internal/widget/EditableInputConnection.java index f2ec0649860c5..44cf0ed1fcd30 100644 --- a/core/java/com/android/internal/widget/EditableInputConnection.java +++ b/core/java/com/android/internal/widget/EditableInputConnection.java @@ -59,14 +59,7 @@ public class EditableInputConnection extends BaseInputConnection { final Editable content = getEditable(); if (content == null) return false; KeyListener kl = mTextView.getKeyListener(); - if (kl != null) { - try { - kl.clearMetaKeyState(mTextView, content, states); - } catch (AbstractMethodError e) { - // This is an old listener that doesn't implement the - // new method. - } - } + if (kl != null) kl.clearMetaKeyState(mTextView, content, states); return true; } @@ -78,12 +71,6 @@ public class EditableInputConnection extends BaseInputConnection { return true; } - public boolean performEditorAction(int actionCode) { - if (DEBUG) Log.v(TAG, "performEditorAction " + actionCode); - mTextView.onEditorAction(actionCode); - return true; - } - public boolean performContextMenuAction(int id) { if (DEBUG) Log.v(TAG, "performContextMenuAction " + id); mTextView.beginBatchEdit(); diff --git a/core/java/com/android/internal/widget/TextProgressBar.java b/core/java/com/android/internal/widget/TextProgressBar.java index aee7b769cad58..5bf4601bdff1a 100644 --- a/core/java/com/android/internal/widget/TextProgressBar.java +++ b/core/java/com/android/internal/widget/TextProgressBar.java @@ -115,10 +115,8 @@ public class TextProgressBar extends RelativeLayout implements OnChronometerTick // Update the ProgressBar maximum relative to Chronometer base mDuration = (int) (durationBase - mChronometer.getBase()); - if (mDuration <= 0) { - mDuration = 1; - } mProgressBar.setMax(mDuration); + } /** diff --git a/core/java/com/google/android/gdata/client/AndroidGDataClient.java b/core/java/com/google/android/gdata/client/AndroidGDataClient.java index fe7d8601c2e02..1d8e9c5c1d7d4 100644 --- a/core/java/com/google/android/gdata/client/AndroidGDataClient.java +++ b/core/java/com/google/android/gdata/client/AndroidGDataClient.java @@ -21,7 +21,6 @@ import org.apache.http.entity.InputStreamEntity; import org.apache.http.entity.AbstractHttpEntity; import android.content.ContentResolver; -import android.content.Context; import android.net.http.AndroidHttpClient; import android.text.TextUtils; import android.util.Config; @@ -118,7 +117,10 @@ public class AndroidGDataClient implements GDataClient { } /** - * @deprecated Use AndroidGDAtaClient(Context) instead. + * Creates a new AndroidGDataClient. + * + * @param resolver The ContentResolver to get URL rewriting rules from + * through the Android proxy server, using null to indicate not using proxy. */ public AndroidGDataClient(ContentResolver resolver) { mHttpClient = new GoogleHttpClient(resolver, USER_AGENT_APP_VERSION, @@ -127,21 +129,6 @@ public class AndroidGDataClient implements GDataClient { mResolver = resolver; } - /** - * Creates a new AndroidGDataClient. - * - * @param context The ContentResolver to get URL rewriting rules from - * through the Android proxy server, using null to indicate not using proxy. - * The context will also be used by GoogleHttpClient for configuration of - * SSL session persistence. - */ - public AndroidGDataClient(Context context) { - mHttpClient = new GoogleHttpClient(context, USER_AGENT_APP_VERSION, - true /* gzip capable */); - mHttpClient.enableCurlLogging(TAG, Log.VERBOSE); - mResolver = context.getContentResolver(); - } - public void close() { mHttpClient.close(); } diff --git a/core/java/com/google/android/net/GoogleHttpClient.java b/core/java/com/google/android/net/GoogleHttpClient.java index ae78ba88725e4..2fcb0c30081bc 100644 --- a/core/java/com/google/android/net/GoogleHttpClient.java +++ b/core/java/com/google/android/net/GoogleHttpClient.java @@ -16,12 +16,8 @@ package com.google.android.net; -import com.android.internal.net.DbSSLSessionCache; -import com.android.internal.net.SSLSessionCache; - import android.content.ContentResolver; import android.content.ContentValues; -import android.content.Context; import android.net.http.AndroidHttpClient; import android.os.Build; import android.os.NetStat; @@ -83,10 +79,21 @@ public class GoogleHttpClient implements HttpClient { } /** - * GoogleHttpClient(Context, String, boolean) - without SSL session - * persistence. - * - * @deprecated use Context instead of ContentResolver. + * Create an HTTP client. Normaly this client is shared throughout an app. + * The HTTP client will construct its User-Agent as follows: + * + * ( ) + * or + * ( ); gzip + * (if gzip capable) + * + * @param resolver to use for acccessing URL rewriting rules. + * @param appAndVersion Base app and version to use in the User-Agent. + * e.g., "MyApp/1.0" + * @param gzipCapable Whether or not this client is able to consume gzip'd + * responses. Only used to modify the User-Agent, not other request + * headers. Needed because Google servers require gzip in the User-Agent + * in order to return gzip'd content. */ public GoogleHttpClient(ContentResolver resolver, String appAndVersion, boolean gzipCapable) { @@ -100,41 +107,6 @@ public class GoogleHttpClient implements HttpClient { mUserAgent = userAgent; } - /** - * Create an HTTP client. Normaly this client is shared throughout an app. - * The HTTP client will construct its User-Agent as follows: - * - * ( ) - * or - * ( ); gzip - * (if gzip capable) - * - * The context has settings for URL rewriting rules and is used to enable - * SSL session persistence. - * - * @param context application context. - * @param appAndVersion Base app and version to use in the User-Agent. - * e.g., "MyApp/1.0" - * @param gzipCapable Whether or not this client is able to consume gzip'd - * responses. Only used to modify the User-Agent, not other request - * headers. Needed because Google servers require gzip in the User-Agent - * in order to return gzip'd content. - */ - public GoogleHttpClient(Context context, String appAndVersion, - boolean gzipCapable) { - - String userAgent = appAndVersion - + " (" + Build.DEVICE + " " + Build.ID + ")"; - if (gzipCapable) { - userAgent = userAgent + "; gzip"; - } - mClient = AndroidHttpClient.newInstance(userAgent, - SSLSessionCache.getSessionCache(context)); - - mResolver = context.getContentResolver(); - mUserAgent = userAgent; - } - /** * Release resources associated with this client. You must call this, * or significant resources (sockets and memory) may be leaked. diff --git a/core/jni/android_database_SQLiteDatabase.cpp b/core/jni/android_database_SQLiteDatabase.cpp index 66858f9badf16..66f0118d8ad3a 100644 --- a/core/jni/android_database_SQLiteDatabase.cpp +++ b/core/jni/android_database_SQLiteDatabase.cpp @@ -45,8 +45,6 @@ #define INVALID_VERSION -1 #define SQLITE_SOFT_HEAP_LIMIT (4 * 1024 * 1024) #define ANDROID_TABLE "android_metadata" -/* uncomment the next line to force-enable logging of all statements */ -// #define DB_LOG_STATEMENTS namespace android { @@ -199,11 +197,7 @@ static void native_execSQL(JNIEnv* env, jobject object, jstring sqlString) env->ReleaseStringUTFChars(sqlString, sql8); } - } else -#ifndef DB_LOG_STATEMENTS - IF_LOGV() -#endif - { + } else IF_LOGV() { char const * sql8 = env->GetStringUTFChars(sqlString, NULL); LOGV("Success on %p when executing '%s'\n", handle, sql8); env->ReleaseStringUTFChars(sqlString, sql8); diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp index f6cd211b20c48..2f1f9b8c64199 100644 --- a/core/jni/android_hardware_Camera.cpp +++ b/core/jni/android_hardware_Camera.cpp @@ -15,9 +15,7 @@ ** limitations under the License. */ -//#define LOG_NDEBUG 0 #define LOG_TAG "Camera-JNI" -#include #include "jni.h" #include "JNIHelp.h" @@ -47,43 +45,38 @@ enum CameraError { struct fields_t { jfieldID context; jfieldID surface; + jfieldID listener_context; jmethodID post_event; }; static fields_t fields; static Mutex sLock; +static jclass sCameraClass; -struct camera_context_t { - jobject mCameraJObjectWeak; // weak reference to java object - jclass mCameraJClass; // strong reference to java class - sp mCamera; // strong reference to native object +struct callback_cookie { + jobject camera_ref; }; -sp get_native_camera(JNIEnv *env, jobject thiz, camera_context_t** pContext) +sp get_native_camera(JNIEnv *env, jobject thiz) { - sp camera; Mutex::Autolock _l(sLock); - camera_context_t* context = reinterpret_cast(env->GetIntField(thiz, fields.context)); - if (context != NULL) { - camera = context->mCamera; - } - LOGV("get_native_camera: context=%p, camera=%p", context, camera.get()); - if (camera == 0) { + sp c = reinterpret_cast(env->GetIntField(thiz, fields.context)); + if (c == 0) jniThrowException(env, "java/lang/RuntimeException", "Method called after release()"); - } - if (pContext != NULL) *pContext = context; - return camera; + return c; } static void err_callback(status_t err, void *cookie) { - camera_context_t* context = reinterpret_cast(cookie); - if ((context == NULL) || (context->mCamera == 0)) return; - - LOGV("err_callback: context=%p, camera=%p", context, context->mCamera.get()); - + JNIEnv *env = AndroidRuntime::getJNIEnv(); + if (env == NULL) { + LOGE("err_callback on dead VM"); + return; + } + callback_cookie *c = (callback_cookie *)cookie; int error; + switch (err) { case DEAD_OBJECT: error = kCameraErrorMediaServer; @@ -92,32 +85,29 @@ static void err_callback(status_t err, void *cookie) error = kCameraErrorUnknown; break; } + LOGV("err_callback: camera_ref=%x, cookie=%x", (int)c->camera_ref, (int)cookie); - JNIEnv *env = AndroidRuntime::getJNIEnv(); - if (env == NULL) { - LOGE("err_callback on dead VM"); - return; - } - env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, - context->mCameraJObjectWeak, kErrorCallback, error, 0, NULL); + env->CallStaticVoidMethod(sCameraClass, fields.post_event, + c->camera_ref, kErrorCallback, error, 0, NULL); } // connect to camera service static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobject weak_this) { - sp camera = Camera::connect(); + sp c = Camera::connect(); - if (camera == NULL) { + if (c == NULL) { jniThrowException(env, "java/lang/RuntimeException", "Out of memory"); return; } // make sure camera hardware is alive - if (camera->getStatus() != NO_ERROR) { + if (c->getStatus() != NO_ERROR) { jniThrowException(env, "java/io/IOException", "Camera initialization failed"); return; } + callback_cookie *cookie = new callback_cookie; jclass clazz = env->GetObjectClass(thiz); if (clazz == NULL) { LOGE("Can't find android/hardware/Camera"); @@ -128,84 +118,71 @@ static void android_hardware_Camera_native_setup(JNIEnv *env, jobject thiz, jobj // We use a weak reference so the Camera object can be garbage collected. // The reference is only used as a proxy for callbacks. - camera_context_t* context = new camera_context_t; - context->mCameraJObjectWeak = env->NewGlobalRef(weak_this); - context->mCameraJClass = (jclass)env->NewGlobalRef(clazz); - context->mCamera = camera; + cookie->camera_ref = env->NewGlobalRef(weak_this); + env->SetIntField(thiz, fields.listener_context, (int)cookie); - // save context in opaque field - env->SetIntField(thiz, fields.context, (int)context); + LOGV("native_setup: camera_ref=%x, camera_obj=%x, cookie=%x", (int)cookie->camera_ref, (int)thiz, (int)cookie); - LOGV("native_setup: mCameraJObjectWeak=%x, camera_obj=%x, context=%p", - (int)context->mCameraJObjectWeak, (int)thiz, context); + // save camera object in opaque field + env->SetIntField(thiz, fields.context, reinterpret_cast(c.get())); - // set error callback - camera->setErrorCallback(err_callback, context); + c->setErrorCallback(err_callback, cookie); + + // hold a strong reference so the camera doesn't go away while the app is still running + c->incStrong(thiz); } // disconnect from camera service -// It's okay to call this when the native camera context is already null. -// This handles the case where the user has called release() and the -// finalizer is invoked later. static void android_hardware_Camera_release(JNIEnv *env, jobject thiz) { - camera_context_t* context = NULL; - sp camera; - { - Mutex::Autolock _l(sLock); - context = reinterpret_cast(env->GetIntField(thiz, fields.context)); + Mutex::Autolock _l(sLock); + sp c = reinterpret_cast(env->GetIntField(thiz, fields.context)); + // It's okay to call this when the native camera context is already null. + // This handles the case where the user has called release() and the + // finalizer is invoked later. + if (c != 0) { + // Make sure that we do not attempt to deliver an eror callback on a deleted + // Java object. + c->setErrorCallback(NULL, NULL); + c->disconnect(); - // Make sure we do not attempt to callback on a deleted Java object. + // remove our strong reference created in native setup + c->decStrong(thiz); env->SetIntField(thiz, fields.context, 0); - } - // clean up if release has not been called before - if (context != NULL) { - camera = context->mCamera; - context->mCamera.clear(); - LOGV("native_release: context=%p camera=%p", context, camera.get()); + callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context); - // clear callbacks - if (camera != NULL) { - camera->setPreviewCallback(NULL, NULL, FRAME_CALLBACK_FLAG_NOOP); - camera->setErrorCallback(NULL, NULL); - camera->disconnect(); - env->DeleteGlobalRef(context->mCameraJObjectWeak); - env->DeleteGlobalRef(context->mCameraJClass); + LOGV("release: camera_ref=%x, camera_obj=%x, cookie=%x", (int)cookie->camera_ref, (int)thiz, (int)cookie); + + if (cookie) { + env->DeleteGlobalRef(cookie->camera_ref); + delete cookie; + env->SetIntField(thiz, fields.listener_context, 0); } - - // remove context to prevent further Java access - delete context; } } -static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject jSurface) +static void android_hardware_Camera_setPreviewDisplay(JNIEnv *env, jobject thiz, jobject surface) { - LOGV("setPreviewDisplay"); - sp camera = get_native_camera(env, thiz, NULL); - if (camera == 0) return; + sp c = get_native_camera(env, thiz); + if (c == 0) + return; - sp surface = reinterpret_cast(env->GetIntField(jSurface, fields.surface)); - if (camera->setPreviewDisplay(surface) != NO_ERROR) { + sp s = (Surface *)env->GetIntField(surface, fields.surface); + if (c->setPreviewDisplay(s) != NO_ERROR) { jniThrowException(env, "java/io/IOException", "setPreviewDisplay failed"); + return; } } static void preview_callback(const sp& mem, void *cookie) { - LOGV("preview_callback"); JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("preview_callback on dead VM"); return; } - camera_context_t* context = reinterpret_cast(cookie); - if ((context == NULL) || (context->mCamera == 0)) { - LOGW("context or camera is NULL in preview_callback"); - return; - } - LOGV("native_release: context=%p camera=%p", context, context->mCamera.get()); - + callback_cookie *c = (callback_cookie *)cookie; int arg1 = 0, arg2 = 0; jobject obj = NULL; @@ -228,18 +205,18 @@ static void preview_callback(const sp& mem, void *cookie) obj = array; - env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, - context->mCameraJObjectWeak, kPreviewCallback, arg1, arg2, obj); + env->CallStaticVoidMethod(sCameraClass, fields.post_event, + c->camera_ref, kPreviewCallback, arg1, arg2, obj); env->DeleteLocalRef(array); } static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) { - LOGV("startPreview"); - sp camera = get_native_camera(env, thiz, NULL); - if (camera == 0) return; + sp c = get_native_camera(env, thiz); + if (c == 0) + return; - if (camera->startPreview() != NO_ERROR) { + if (c->startPreview() != NO_ERROR) { jniThrowException(env, "java/io/IOException", "startPreview failed"); return; } @@ -247,30 +224,32 @@ static void android_hardware_Camera_startPreview(JNIEnv *env, jobject thiz) static void android_hardware_Camera_stopPreview(JNIEnv *env, jobject thiz) { - LOGV("stopPreview"); - sp c = get_native_camera(env, thiz, NULL); - if (c == 0) return; + sp c = get_native_camera(env, thiz); + if (c == 0) + return; c->stopPreview(); } static bool android_hardware_Camera_previewEnabled(JNIEnv *env, jobject thiz) { - LOGV("previewEnabled"); - sp c = get_native_camera(env, thiz, NULL); - if (c == 0) return false; + sp c = get_native_camera(env, thiz); + if (c == 0) + return false; return c->previewEnabled(); } static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject thiz, jboolean installed, jboolean oneshot) { + sp c = get_native_camera(env, thiz); + if (c == 0) + return; + // Important: Only install preview_callback if the Java code has called // setPreviewCallback() with a non-null value, otherwise we'd pay to memcpy // each preview frame for nothing. - camera_context_t* context; - sp camera = get_native_camera(env, thiz, &context); - if (camera == 0) return; + callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context); int callback_flag; if (installed) { @@ -278,31 +257,29 @@ static void android_hardware_Camera_setHasPreviewCallback(JNIEnv *env, jobject t } else { callback_flag = FRAME_CALLBACK_FLAG_NOOP; } - camera->setPreviewCallback(installed ? preview_callback : NULL, context, callback_flag); + c->setPreviewCallback(installed ? preview_callback : NULL, cookie, callback_flag); } static void autofocus_callback_impl(bool success, void *cookie) { - LOGV("autoFocusCallback"); - camera_context_t* context = reinterpret_cast(cookie); - JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("autofocus_callback on dead VM"); return; } - env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, - context->mCameraJObjectWeak, kAutoFocusCallback, success, 0, NULL); + callback_cookie *c = (callback_cookie *)cookie; + env->CallStaticVoidMethod(sCameraClass, fields.post_event, + c->camera_ref, kAutoFocusCallback, + success, 0, NULL); } static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) { - LOGV("autoFocus"); - camera_context_t* context; - sp c = get_native_camera(env, thiz, &context); - if (c == 0) return; - - c->setAutoFocusCallback(autofocus_callback_impl, context); + sp c = get_native_camera(env, thiz); + if (c == 0) + return; + callback_cookie *cookie = (callback_cookie *)env->GetIntField(thiz, fields.listener_context); + c->setAutoFocusCallback(autofocus_callback_impl, cookie); if (c->autoFocus() != NO_ERROR) { jniThrowException(env, "java/io/IOException", "autoFocus failed"); } @@ -310,20 +287,18 @@ static void android_hardware_Camera_autoFocus(JNIEnv *env, jobject thiz) static void jpeg_callback(const sp& mem, void *cookie) { - LOGV("jpegCallback"); - camera_context_t* context = reinterpret_cast(cookie); - JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("jpeg`_callback on dead VM"); return; } + callback_cookie *c = (callback_cookie *)cookie; int arg1 = 0, arg2 = 0; jobject obj = NULL; if (mem == NULL) { - env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, - context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, NULL); + env->CallStaticVoidMethod(sCameraClass, fields.post_event, + c->camera_ref, kJpegCallback, arg1, arg2, NULL); return; } ssize_t offset; @@ -352,51 +327,48 @@ static void jpeg_callback(const sp& mem, void *cookie) obj = array; - env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, - context->mCameraJObjectWeak, kJpegCallback, arg1, arg2, obj); + env->CallStaticVoidMethod(sCameraClass, fields.post_event, + c->camera_ref, kJpegCallback, arg1, arg2, obj); env->DeleteLocalRef(array); } static void shutter_callback_impl(void *cookie) { - LOGV("shutterCallback"); - camera_context_t* context = reinterpret_cast(cookie); - JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("shutter_callback on dead VM"); return; } - env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, - context->mCameraJObjectWeak, kShutterCallback, 0, 0, NULL); + callback_cookie *c = (callback_cookie *)cookie; + env->CallStaticVoidMethod(sCameraClass, fields.post_event, + c->camera_ref, kShutterCallback, 0, 0, NULL); } static void raw_callback(const sp& mem __attribute__((unused)), void *cookie) { - LOGV("rawCallback"); - camera_context_t* context = reinterpret_cast(cookie); - JNIEnv *env = AndroidRuntime::getJNIEnv(); if (env == NULL) { LOGE("raw_callback on dead VM"); return; } - env->CallStaticVoidMethod(context->mCameraJClass, fields.post_event, - context->mCameraJObjectWeak, kRawCallback, 0, 0, NULL); + callback_cookie *c = (callback_cookie *)cookie; + env->CallStaticVoidMethod(sCameraClass, fields.post_event, + c->camera_ref, kRawCallback, 0, 0, NULL); } static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) { - LOGV("takePicture"); - camera_context_t* context; - sp camera = get_native_camera(env, thiz, &context); - if (camera == 0) return; + sp c = get_native_camera(env, thiz); + if (c == 0) + return; - camera->setShutterCallback(shutter_callback_impl, context); - camera->setRawCallback(raw_callback, context); - camera->setJpegCallback(jpeg_callback, context); - if (camera->takePicture() != NO_ERROR) { + callback_cookie *cookie = + (callback_cookie *)env->GetIntField(thiz, fields.listener_context); + c->setShutterCallback(shutter_callback_impl, cookie); + c->setRawCallback(raw_callback, cookie); + c->setJpegCallback(jpeg_callback, cookie); + if (c->takePicture() != NO_ERROR) { jniThrowException(env, "java/io/IOException", "takePicture failed"); return; } @@ -406,9 +378,9 @@ static void android_hardware_Camera_takePicture(JNIEnv *env, jobject thiz) static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jstring params) { - LOGV("setParameters"); - sp camera = get_native_camera(env, thiz, NULL); - if (camera == 0) return; + sp c = get_native_camera(env, thiz); + if (c == 0) + return; const jchar* str = env->GetStringCritical(params, 0); String8 params8; @@ -416,7 +388,7 @@ static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jst params8 = String8(str, env->GetStringLength(params)); env->ReleaseStringCritical(params, str); } - if (camera->setParameters(params8) != NO_ERROR) { + if (c->setParameters(params8) != NO_ERROR) { jniThrowException(env, "java/lang/IllegalArgumentException", "setParameters failed"); return; } @@ -424,20 +396,20 @@ static void android_hardware_Camera_setParameters(JNIEnv *env, jobject thiz, jst static jstring android_hardware_Camera_getParameters(JNIEnv *env, jobject thiz) { - LOGV("getParameters"); - sp camera = get_native_camera(env, thiz, NULL); - if (camera == 0) return 0; + sp c = get_native_camera(env, thiz); + if (c == 0) + return 0; - return env->NewStringUTF(camera->getParameters().string()); + return env->NewStringUTF(c->getParameters().string()); } static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz) { - LOGV("reconnect"); - sp camera = get_native_camera(env, thiz, NULL); - if (camera == 0) return; + sp c = get_native_camera(env, thiz); + if (c == 0) + return; - if (camera->reconnect() != NO_ERROR) { + if (c->reconnect() != NO_ERROR) { jniThrowException(env, "java/io/IOException", "reconnect failed"); return; } @@ -445,18 +417,18 @@ static void android_hardware_Camera_reconnect(JNIEnv *env, jobject thiz) static jint android_hardware_Camera_lock(JNIEnv *env, jobject thiz) { - LOGV("lock"); - sp camera = get_native_camera(env, thiz, NULL); - if (camera == 0) return INVALID_OPERATION; - return (jint) camera->lock(); + sp c = get_native_camera(env, thiz); + if (c == 0) + return INVALID_OPERATION; + return (jint) c->lock(); } static jint android_hardware_Camera_unlock(JNIEnv *env, jobject thiz) { - LOGV("unlock"); - sp camera = get_native_camera(env, thiz, NULL); - if (camera == 0) return INVALID_OPERATION; - return (jint) camera->unlock(); + sp c = get_native_camera(env, thiz); + if (c == 0) + return INVALID_OPERATION; + return (jint) c->unlock(); } //------------------------------------------------- @@ -540,6 +512,7 @@ int register_android_hardware_Camera(JNIEnv *env) { field fields_to_find[] = { { "android/hardware/Camera", "mNativeContext", "I", &fields.context }, + { "android/hardware/Camera", "mListenerContext", "I", &fields.listener_context }, { "android/view/Surface", "mSurface", "I", &fields.surface } }; @@ -547,6 +520,7 @@ int register_android_hardware_Camera(JNIEnv *env) return -1; jclass clazz = env->FindClass("android/hardware/Camera"); + sCameraClass = (jclass)env->NewGlobalRef(clazz); fields.post_event = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V"); if (fields.post_event == NULL) { diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp index f625ffbffc4b1..d9effeed19aad 100644 --- a/core/jni/android_media_AudioTrack.cpp +++ b/core/jni/android_media_AudioTrack.cpp @@ -688,33 +688,15 @@ static jint android_media_AudioTrack_reload(JNIEnv *env, jobject thiz) { // ---------------------------------------------------------------------------- -static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz, - jint javaStreamType) { - int afSamplingRate; - // convert the stream type from Java to native value - // FIXME: code duplication with android_media_AudioTrack_native_setup() - AudioSystem::stream_type nativeStreamType; - if (javaStreamType == javaAudioTrackFields.STREAM_VOICE_CALL) { - nativeStreamType = AudioSystem::VOICE_CALL; - } else if (javaStreamType == javaAudioTrackFields.STREAM_SYSTEM) { - nativeStreamType = AudioSystem::SYSTEM; - } else if (javaStreamType == javaAudioTrackFields.STREAM_RING) { - nativeStreamType = AudioSystem::RING; - } else if (javaStreamType == javaAudioTrackFields.STREAM_MUSIC) { - nativeStreamType = AudioSystem::MUSIC; - } else if (javaStreamType == javaAudioTrackFields.STREAM_ALARM) { - nativeStreamType = AudioSystem::ALARM; - } else if (javaStreamType == javaAudioTrackFields.STREAM_NOTIFICATION) { - nativeStreamType = AudioSystem::NOTIFICATION; - } else if (javaStreamType == javaAudioTrackFields.STREAM_BLUETOOTH_SCO) { - nativeStreamType = AudioSystem::BLUETOOTH_SCO; - } else { - nativeStreamType = AudioSystem::DEFAULT; +static jint android_media_AudioTrack_get_output_sample_rate(JNIEnv *env, jobject thiz) { + int afSamplingRate; + AudioTrackJniStorage* lpJniStorage = (AudioTrackJniStorage *)env->GetIntField( + thiz, javaAudioTrackFields.jniData); + if (lpJniStorage == NULL) { + return DEFAULT_OUTPUT_SAMPLE_RATE; } - if (AudioSystem::getOutputSamplingRate(&afSamplingRate, nativeStreamType) != NO_ERROR) { - LOGE("AudioSystem::getOutputSamplingRate() for stream type %d failed in AudioTrack JNI", - nativeStreamType); + if (AudioSystem::getOutputSamplingRate(&afSamplingRate, lpJniStorage->mStreamType) != NO_ERROR) { return DEFAULT_OUTPUT_SAMPLE_RATE; } else { return afSamplingRate; @@ -784,7 +766,7 @@ static JNINativeMethod gMethods[] = { {"native_set_loop", "(III)I", (void *)android_media_AudioTrack_set_loop}, {"native_reload_static", "()I", (void *)android_media_AudioTrack_reload}, {"native_get_output_sample_rate", - "(I)I", (void *)android_media_AudioTrack_get_output_sample_rate}, + "()I", (void *)android_media_AudioTrack_get_output_sample_rate}, {"native_get_min_buff_size", "(III)I", (void *)android_media_AudioTrack_get_min_buff_size}, }; diff --git a/core/jni/android_os_ParcelFileDescriptor.cpp b/core/jni/android_os_ParcelFileDescriptor.cpp index 1429f58406843..465e233bb0720 100644 --- a/core/jni/android_os_ParcelFileDescriptor.cpp +++ b/core/jni/android_os_ParcelFileDescriptor.cpp @@ -60,37 +60,9 @@ static jobject android_os_ParcelFileDescriptor_getFileDescriptorFromSocket(JNIEn return fileDescriptorClone; } -static jlong android_os_ParcelFileDescriptor_getStatSize(JNIEnv* env, - jobject clazz) -{ - jint fd = env->GetIntField(clazz, gFileDescriptorOffsets.mDescriptor); - - struct stat st; - if (fstat(fd, &st) != 0) { - return -1; - } - - if (S_ISREG(st.st_mode) || S_ISLNK(st.st_mode)) { - return st.st_size; - } - - return -1; -} - -static jlong android_os_ParcelFileDescriptor_seekTo(JNIEnv* env, - jobject clazz, jlong pos) -{ - jint fd = env->GetIntField(clazz, gFileDescriptorOffsets.mDescriptor); - return lseek(fd, pos, SEEK_SET); -} - static const JNINativeMethod gParcelFileDescriptorMethods[] = { {"getFileDescriptorFromSocket", "(Ljava/net/Socket;)Ljava/io/FileDescriptor;", - (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket}, - {"getStatSize", "()J", - (void*)android_os_ParcelFileDescriptor_getStatSize}, - {"seekTo", "(J)J", - (void*)android_os_ParcelFileDescriptor_seekTo} + (void*)android_os_ParcelFileDescriptor_getFileDescriptorFromSocket} }; const char* const kParcelFileDescriptorPathName = "android/os/ParcelFileDescriptor"; diff --git a/core/jni/android_server_BluetoothEventLoop.cpp b/core/jni/android_server_BluetoothEventLoop.cpp index adfd912b31053..9100e81013e78 100644 --- a/core/jni/android_server_BluetoothEventLoop.cpp +++ b/core/jni/android_server_BluetoothEventLoop.cpp @@ -721,7 +721,6 @@ static jboolean waitForAndDispatchEventNative(JNIEnv *env, jobject object, #define BOND_RESULT_AUTH_REJECTED 2 #define BOND_RESULT_AUTH_CANCELED 3 #define BOND_RESULT_REMOTE_DEVICE_DOWN 4 -#define BOND_RESULT_DISCOVERY_IN_PROGRESS 5 void onCreateBondingResult(DBusMessage *msg, void *user) { LOGV(__FUNCTION__); @@ -756,14 +755,10 @@ void onCreateBondingResult(DBusMessage *msg, void *user) { // already bonded LOGV("... error = %s (%s)\n", err.name, err.message); result = BOND_RESULT_SUCCESS; - } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") && - !strcmp(err.message, "Bonding in progress")) { + } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress")) { + // don't make the java callback LOGV("... error = %s (%s)\n", err.name, err.message); goto done; - } else if (!strcmp(err.name, BLUEZ_DBUS_BASE_IFC ".Error.InProgress") && - !strcmp(err.message, "Discover in progress")) { - LOGV("... error = %s (%s)\n", err.name, err.message); - result = BOND_RESULT_DISCOVERY_IN_PROGRESS; } else { LOGE("%s: D-Bus error: %s (%s)\n", __FUNCTION__, err.name, err.message); result = BOND_RESULT_ERROR; diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp index 73254320bdf4b..24404a87e821a 100644 --- a/core/jni/android_util_Binder.cpp +++ b/core/jni/android_util_Binder.cpp @@ -1223,7 +1223,6 @@ static jobject android_os_Parcel_openFileDescriptor(JNIEnv* env, jobject clazz, if (mode&0x08000000) flags |= O_CREAT; if (mode&0x04000000) flags |= O_TRUNC; - if (mode&0x02000000) flags |= O_APPEND; int realMode = S_IRWXU|S_IRWXG; if (mode&0x00000001) realMode |= S_IROTH; diff --git a/core/jni/server/com_android_server_AlarmManagerService.cpp b/core/jni/server/com_android_server_AlarmManagerService.cpp index 1d66fb11958f3..0f37921b8d714 100644 --- a/core/jni/server/com_android_server_AlarmManagerService.cpp +++ b/core/jni/server/com_android_server_AlarmManagerService.cpp @@ -52,17 +52,12 @@ static jint android_server_AlarmManagerService_setKernelTimezone(JNIEnv* env, jo tz.tz_minuteswest = minswest; tz.tz_dsttime = 0; - int result = settimeofday(NULL, &tz); + int result = ioctl(fd, ANDROID_ALARM_SET_TIMEZONE, &tz); if (result < 0) { LOGE("Unable to set kernel timezone to %d: %s\n", minswest, strerror(errno)); return -1; - } else { - LOGD("Kernel timezone updated to %d minutes west of GMT\n", minswest); } - return 0; -#else - return -ENOSYS; #endif } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index e9db5f080d6b0..2c3b590229443 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -704,7 +704,7 @@ + android:protectionLevel="signature" /> diff --git a/core/res/res/drawable-land/title_bar.9.png b/core/res/res/drawable-land/title_bar.9.png new file mode 100644 index 0000000000000000000000000000000000000000..a48d9674dd6d5cc6616a35217058f86bf78305e1 GIT binary patch literal 5751 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 diff --git a/core/res/res/drawable/btn_check_off_selected.png b/core/res/res/drawable/btn_check_off_selected.png index 20842d41c8f18a8e9d60b543e14448c6c6840203..68545503931252861c44b5b209f59e509a3b9d77 100644 GIT binary patch delta 1532 zcmV&G!k&Xr-QKz7wNKHdS7bGMqBpMKiG!YSrKq8R^govQnP6)O)iOIfq9+&^l%)Y$# z%to>i#g23|v$OZ!^WAgKJ@?ENQcC&ux$_^rb^64@p<~mzR1y1aRqC;&v@fjOzWCDnpP%EKA1K$tz?6kvU;XsW zGYf|jB{(kNy8fU0#ny3(#s^);+P&s#>FqDh^37LdxwRMAYu|kM?3q_i1^}u$;%yAf~Yw z*rSD%HG`G~*a6ro|@MCz%VMG)vMvieem90VL#5YZOExQK)i zhqHOzTc(l$CzJzij1c^6-$n-xWy2x6p5Z3rWK@-Kr^U<)L;s3jv#KU z<^dNJl-fxfz|r&nu@J9Dz1)pFw>pl zQd-o~icMg4ejZMBli7WHXq?@2MCLJcI_tw*qQ>`muDEhTM@Dyoy>~Fz)wCEEmw%R+ zaw>5CS?^6<>{4{-foZf+T&bIc;#NYf62qH#f`g@*cxv4A(sX=BuNPOGP2sU)(AeMJ zy6KnB9U8I2hn+&v(`SybD)ofdL9!Nya0e_RgJ@8xqpfGqXg81yMo@KDwpcx0>VZIyr`%<~m7!7RW#(#ZTKax$P z_^nKjI0K1hughhu`J=^0hf?9j4_*;7aO1wMcJ+-guxpoA>!+5U$)|*7L$e+KJYneD zQatSE&`^KDy-gUJS14Xu*;LiQwJ@*?@16VYKMwabW~B{EjlLp0|dKGDXStm^n7f5)Hwzl igN?z)VEcFdE5HCYrt`#@C)P~>0000Rt9L~P;S2k~7edCkwF5$^9up6N& zK}skl6?%L7n|D85I+ZAq;}W^9`tzjN+LNN;hI87v-`p;J@ckEf@*`OG1}V1o)90_e zzm%?(sQQq|aen|drT{G6M(4DY(o3?>w?4bRi>Cv@R@Un?H5#i;kSa8>0cP*-0f{IyAFU;})7>x>cT(NHF%75h^&+lwBbA895gu$qoW>l#= zR1tZ~*hi`@&LY9Ma1@xZtU#y`VZhLWh*s>6eL-0RQF}`B+$xU0TqA=%DoO<1tILOh zX;QI{pLvRjFjz=25gD|8zpGxK&oa^+Mom-pnxjlIL2gs7dXt#VdbY=2#Q^1*<%10q zCxUAoN`J{J#VMi~Zp;=@ol>;8v_NjvfM;xiz(zkP^$*$z59S-8Co!^1EHi+ za;t5j4J)3bQoca$y*u!&qwu7jR~1l_*ZFD7*WoUsR&U9LzxHU-eHw? zntz#2o%I71T?$D*9N>KugJ`f6%`YsITRS4>!M~mQp+1~ZrqT~n!Kff(P#vR6>ndBx z;P-r5Dp#deHci!9O(}(EaZPn*<9F48voDs2Im+4lO?@CF4p)r)l_IEXr=fz-6V&vx zAlaCNTL6gLs(HW#3B^@?N2n=(s<2GSIDeeIybV>H&VWP4IqQp_Jt+E5mZCbIJe2EeEDl*_@{58>=)J-l_YZssGp6Qd7PjC*QnzG}g%CVk7K zip$CLM|#{`SPQ+hVpBA~xJXX*0MY%Zr=5O%M8+{{zs!5LL=DgLSaIbBrwn)ey?-|x z>uOqzmRDC1aw_CJ-0cpX^+`IoFO4?JRB{7Q*hFZkynn#hW_>=eAoO zu8})UGqVebRlA-qFe5!EXY3@OOezKem;xKF7#UE^;VSI2;i>h~G|`ckM~0A~nVA`K ztM{-1o1jdNp7Y~lgbX8kOOjv=S%8pWnj4u>lapE&Zn4W zlV&^WJfY{?l0EL{P|y1edmGa=FHyXA=4CoEsqhvZ0{s}lZo|ql uNj`o)#wN$<6R-)`1Z)B}p7Ngn0|1Wfy_eb&Kve($002ovPDHLkU;%=2*zmLf diff --git a/core/res/res/drawable/btn_check_on_disable_focused.png b/core/res/res/drawable/btn_check_on_disable_focused.png index 8a73b33f0df551d797f546b506f323d76c570a8a..4b6064dcabec1a1bb7c5dff196bb47c297ee0ed8 100644 GIT binary patch delta 1074 zcmV-21kL;M2 z-6$c0zv2h(%zyDG=e2<84&LwD7rZ-&-&@&qH`a#u1;#4oTa2sUno%l+aA*aE2e~)Z zA)27AW`0%@%U42$7OMuP6Vuv2{D}PECc~4?kUnI#C2T9FTTj1GXz5hJq_j3rW2v$J z;LczjG9a`PSZO@4e849a0mf>PF`Ov^gPJf}r7Ca#BLzHX(x4bsKJl^xR z{jHs>AtZg!zXY4l+3FM&T1?q8_6uq&9Oz{zeu)o^7)Lz#yjsR`!9)$93^EkA%q52s zLmmrnNfIz|^Wg2G#XC`1II6TuUn&Zf>lW}ZTeExM0km`USg zU(_BoqkmO|`hESL&M@WYqF=5X5ZA3ly9d!(0?{CFDy`TobYN22c2hTHvn_=GYlos z5@yWa_S@_^U{c{y=KL!0CL+Js((> zmU_ETyU}I+Wf%8_OQH}3z;H%Ly0J#S5(9rns9~`|7-<=KR%Gi_1=FcrX)#-pXTxV* z*nc}@+fAGUhFS~Dpa5(VOpyzQ3+@tnvaaNe;ei`uU!dc0e)}lOZv1c4seJDYFM|n7DDGfb1*BM~Ao2YEVikt4hgOW?Zpe zaZkUSwr8@q$#q}7!4`+MNg#IPrTiM#*MACR%LdW0aJNgV2N7~_szWqETPRFdP9Mcnt^6a<4u z^v?{#OtEZ~xpbtZZ-*h=VG`x+X))%LEl+PgUUc7{LsM9LBY#7+!OLEVcDfpBH7oG4 s^%@xbm46f~U=^?mSOx5V2m2|&06y^!1U0}V&Hw-a07*qoM6N<$f@mlBbpQYW delta 1080 zcmV-81jqaA2=WM!Nq-bcL_t(|+U%I$OH*MO$KP|Nr@2knv7DB=GL~d2gs_4lLWm@~ zsibZaDZB`ZAnd;g0wJQ?E(`>bq8nKRyRZ?|O+vcpr)`->tgYNnH@DOCyysobv+dZN zX9(?qhwW_VobPAP``z=t@8M)wCR;IhvPGi;RsqvHs`7ovaerJbyoiu>kR~1VCCDIj zhS0iT0M#%u&~ftI@y^Q)#?`JGF1}kYDqqa<^wHGJ1JHa1a7zWj;Dow6{Y`yWkDBfn z(_R~i>N{L^LQa9!p;WBt7HB^KxaC3>YdC+nVbB=&+sfr7BO$i)hZ_fPO-L``upn5y zP5#zN;>!1L#DD(r8S(6_9zdPJ#|OKD6BqEkjZbx=Hsr@b|4OTA<;QN4OcG4JpfKpY znGV$iZ7uWja=LsiL8ZlOff>>%eIR~?e+i?ZQRi~?vc(>^FJ5Z7^jf85&;*lH`aq2& zNBV;Mg7xV3#lT`y&q9w+E&`0#qheSo3WY5@tssO`VShoT#cNGT9FBV?HzV#X+&lJu z?|TQGLumP+e@S+qv&AW?w79ZW><`p-IH*>j#BX9?$TZ}^@3ktH3zpUa%BVmI3qs;z z{G!JyS`!p3{qI9b!7`~f@T70j;a%|77X^h&fCyxmkTbzEo{n7|fy{X-ExzbJhA^Y1 z(cXw7Vt*kkg!K9PJg4oaKdcL7VNkGkaLzfWPqd!!ZM=`=0i#eY0EGsQ5#rkBIz|9X z4VMEIV`lf;eb~3u_f=^biuPF2kQ9gjZvjCQk%V`DJkDJvwy#}e^#1f;#lw+1_zyIYCixA>@$Rt z*$`&T-ul<nrJj_bRwdqhbLkRTky*^nZfjV)L#>_q0P?l0Y5wb}E5 zWoc=*3#}X7tiI_ImV^Xd&czs<35ss2Rjx$fpM*5dH%ddzLoZ9&7^y)FT31>v*2I<2 z6@M3chc3IRbHGrmAq5nG&5}8M&3Mhdfu3yGaK$jNLG}iEU!jL+t}wu;V)lXPfE#~6 zsawgS!7#8zI6pb3u^rG#MHNT{&hG4G8_Mj!hKY@n1QcI&fA01cnhiEGlvSnd%!h5m z?#U06j!YFd^Qk~CSdkA6N&@2leJH=js(npiPmh>QG{3m}Y~KBFhK!;1+RaCvSsUP5;pG72UNJTs y>J>O`y#)q;4nyUsbp@;fRspMk{byjm1sDJZFWMdgPPr8T0000PtJsDYz=5?RgLAd$NlH3AwfJl{3w4!EC$%cO2p>1H zI6-fN#U)qa#y-9!uChZuf37(~NCvp(+=IzmHP_%KE9X{O{6flF+qH@`zB#yBXxZ8* zQz|qCXX=rG>wRZrA6J9ZMXe$X7A!($8woi$ZNZDBUQ~y{1h|pKm-+ZbPeKmLvm-WG zn#MM_-vze7`Me$BW;upZRBwEyl`D`CI_VLUB23ve~GIwdAW@O6~{Hq zTD3~tP-`?E+2TT5a+1Xq_wjY$$D`3`n#<)#pT$Z8 zPA>8Yy5DFt?p7+5Z*)GNzhV=7I2``!bUKrIz5Wi5E$9_A4Fji^h3-KWs0iJ#9GhRE z0n~xsLgRDg!HSz@vOL`???IO>ga3w3f}osg>zZA>%TES)(%Sz6PA6Y6xqy+c{t;jR X=_2*yEM${?00000NkvXXu0mjfK8S}; delta 737 zcmV<70v`Rd2KxmeiBL{Q4GJ0x0000DNk~Le0000Q0000o2nGNE07A9Pm60JRf1OE0 zK~#9!#F)>El0g{9eP{L-*-B}!prO)UmcVO)U4n(~vgfXK5B~<~-nnyl4+1X*V~RH z`tFkXKiQBijS&*M1Kib-9wao`+AFeEx%Gnb$VoXAWQUJzX^aq%G(*A#f2mwcd)_%g z8p45D^H65y5%rDpC>C@r9&tcyk9GwT8bqI*CWO!+5e(uM1Occo!7>LK1;GR9(D`5* zpu7nNNqf=Es=T)ztyZg4IbwN4kTf0{p_A+!r3~FQ=E!k$$_C^(p9yp8=7KmY!#{bH z`8J^^w(8FZg)XdA+FX#Ze~(n$b3<^B>|zL6>+}t&Nz2>#>|(Hix&X}cf&xmGN4^}H zVDg0eay$}gs?O>!GAnPZKfk==LS-*IX+S~`=<~?+A18FeTuyXFg`858=8^09NG7bx zAuG2tbRy0p>r}%%Knly_$OSr^&1Op}<#tY(G6&OJw<)qATlL`Vf6dWoI2>M7DwVu> zK#3~~6HFkor7=PtmXD!l-EQ}3ywmVLdBg_M$(F>m`y;>r4=QV3)lIJ&G@|Pat^m6?_1Fl%RW;gh+x=JJcHG z79H2V2@kP5)hwjWEZ@M#2#Wmp^Ns7Oq^|2hTZ0e+r>{vX=WY|;<{15w))*!OY8z^+ zW7h}N9O?yvedmS)+Jx!A_x*`we_6Ylrm0=3tEze{isCs4f-A5*0KWXQRp3CH@NpQ1 z=cZ}ueYQhcmao(4^a3{Tz&ZcEPhlKydY(7w8~p_V1GUi2<$Wx;VcYhOD2uSM7(8%Q z*Y&X|@W!I@z!d?ne#-LigOqS-6aNW06c9e#=){SDaDs`8m^iiyw#ud_e~zt!t-?y2 z-Xcl~XFT`7#fgg(uj2?uI4(|X73^{BaZFsI#OWO^3pva4d?AXsvCMeV&5|S$<{e^V z$#~$mQ4~F;Y1%uU8mNVuR+^smf)@VHox*hHy6&FiIK;N?P8V#JWi?GYj$?|x1miUq zyulyBbOLn*wcl~rk5KneH8J_VZjhM+}2OF%wQo-$>M zy@-g204c%q=FOWAIXO88fy}!=e{(+}%Q0b5FH%)iWk{+eV2waMAiW?ax*Rr(1m)!9 zgvgC_s9r&0EaDXq5a1!#BB)-BIAy`2mWc|fnF&4LG10>!T!zxkB4#RB#5|~c#7K>z zZDjgrH0TDuk4A%zI3IzEaJpE8rF}M<7)JBaXkr*m45M*0*nLEo-UO(If52ww>&K5D z|0CB1sNUDaxc<@At5?Y$6M*V{M2tnZ7A#os>h|s1BwGg31JVmJgV^rB4v?~mkB=AA z*4AbO_Dk_5kVlUm{RjDE;lhO=OO61|yh6%=hAfcM0Ad9o7AN4Dmq7dgh;IPRdptOY oXhtm>x)#A&wxkXW0t6TU6lcGhcY)MpkpKVy07*qoM6N<$f-wuj5C8xG diff --git a/core/res/res/drawable/btn_default_normal_disable_focused.9.png b/core/res/res/drawable/btn_default_normal_disable_focused.9.png index f506179795bf55e27cc8b012537123b803e3267f..b2d45e57a2ec3d6e4f61440ae2e66339daed95b6 100644 GIT binary patch delta 670 zcmV;P0%8531-S(wiBL{Q4GJ0x0000DNk~Le0000k0000o2nGNE03)sG*O4J8e_KgJ zK~#9!?3%$#8$lGt=S?&AiwIUwUBxN;fKu8*6LfrL@(SzHGS%uxajr-tZ64>4O<>PzVok>8~b!Jro z0A5}PORjAtxRq5E9Nl`1Ln|tXfAZVRb&ATOPLS`P?0}{!(4mi0FGt=C4^D-B+JFyA z9d=R|bnpIgfp4w+++0MKb%f8R$1?d#8d zn-H(VtQ@`SwHw7H=PCZ;K?f`5n2_DjqAusWn*WjonangNXXUf{XXGXWH{Ktl;JQ|S zZUX~1<+y%M0Q~&!;2uW6aRY>AeeDCDm0r@Bd{nk zFz^PC3IWHB%Y?>pT(X7We~gSv_B}YksF-X{hk^s6ut#*S=5&DLT)O6@S1ve7a3BZ{ zZd6?Ghn8{q-XV}fHF?YD zH6`BLoP8qRJl|iQK-uqjb7fG=N}RE5$_)74{0}wuek}09r{_cUbWBSD0-5;@H71y9 zf@6OE;&N^YJb8FK`t()ApX&~275D9`JP)Q5r^=rX-__WsZMGzsBrE!=KhSpK(2I(o z+HE%b5S2jf%Ajurr(Q0&3+{sd|7~N*C%x+*axMfI05-c7*|(#)Y5)KL07*qoM6N<$ Ef*Hs=nE(I) delta 646 zcmV;10(t$p1)&8YiBL{Q4GJ0x0000DNk~Le0000Q0000o2nGNE07A9Pm60JRe?v(` zK~#9!V*LOAKLe?Nk&zLo?LQ+)ddRVe9DvgzpsRU+lpqlE0WlW=bG`xbCm?11GMZ7L5qM2`TE1< z+)}N%`Z@ky6=V29I9NCt7^LKYe>la8%kb|v`68ehn}L>n!W(ozMM@9)EN95Gy>TTc zE*}08*{x7?JOgO%JwibzD9Z3co8cG4D_3~ER$t}yyoS$k?a$k_bUtqj1+hgL{%Awv z76mY2(Z|d6^SKnm&(91XOvn-t0IPwj2kQlzK}=#`V)*le^e{u!!-Ssif3RBg{~zi0 zpy^>E%18hIl3~$b(k)_UAj3y!dYFmw(LXXQ`bS34F;XFp7>SD`Iwc0W`G}DUaWq1M zj_Ds6l`fhdra=~TWcUcZS{pbYVQD(iCXTSQ&zPtXbVMcwI$6ZXKu(*Iti(VAA2DHV zGf)mjs6~uau!wOqj)qo*n?1LC{CQ@O%uc-j_2ne`U;fm3C0zT>7lY{SV?hT;MAc z--`#|c<)cz_4L5v%M8mwW{@(VAq%85fLH;D#R&x5OCWv##5b^6GB}24MlBk;7J*u} guwsQ2eE=e8WlDP=&I9Q&sSYlGc`TkGu1miJ=ucC>@?k7 zpZV_hy?WJ+LhJ9n_)QKXuvt2a_r)mQER{4zM z#FP8qUYwiR+5!~=D9TJS&cPf)M+8q_yj|XT?D|DMc#C6om{mT%{o~1Ve{<9A7PMb8 zbi!w=dX0jD!6nR1H(HwItFM1~=D-J8W%t3B+z;`;0CC%ZYqe_>+^8=3vjHg!Glh8k zli6l_2ejV;Bo2HM<->r_Hn;B3Od;SABUf&Q=EnX(}=)%-&M+O!J{B>r?>%6{ADWxT9xA68s4vX zTn4;t6i>XW(gDwd9z}5v9=*SH3GP}Y2t4(83Y~(-9&iSF)CLVPM|t}LIQ@t}QAWWY z7aH1tzvIui7n*219>-pIlveR1MHD5#89ILFJT|~4RVHWm2M{UKe}H zq;0DmHm%-o;GPePwF+gVo!d{C8f@iwSK2WT|=e-?on8yn)9)E&j z0erB>ZFh-TXsltc?0FrroZ`|!qi+?=&-}`j_S$mnZjwrXe+v&B3xKJ5V1HNFVF>j& zqBOm*w0Ual5{h6F{iK==j#oo@!?SL$U{w$$* zWG)cA@AEnW%6lv^($=lFjPy81tDV9}ztT*7r{=u8 zI>qt*uQ&D_Kh(kx$-PdYf*QWj)su?VPAf{(fZvztfAx`XR_^i9%N##jn-qe7#BrA6 z^py+S7rt0%Y@6RDKB(u-n|b55^jN*Q`=I^m{H4Di@WG!re&G0T7`Pt#eC{RYKyau0G{?sr+iC{azW#^frBk{L`2TWH(I#}Wj41m{Hp|%j miifYp9!O*IZmA@DFTel>QW;<3u+l^T0000PeVfq<__1rH*6 z@#evMJcKCZB-w+wVn{GqSWSdog}6y(rrWQ&r{9~IH?yxg#0-4Q?!2o0=Bujit{(Q@ zQ|`sgaPyqylZfC<|HqZaFOINze;GIptOJt;`U)Oi1@_vZGXrYQeE-dR7dO_*O)3$Q@_?wqy*d~{e`5n%@eyAc zLle5!-rlrtQuQ|mDWRs0D#nVFlPZh*5(Qt3p&@!{eNvvJ@-b1Jh&1IDiPk5}CuIx` zQ9<<~ND`4#5=j=2Pvhpsm3cQrWPK=r1f?Rfp#sU-<{yosKv0r*ZAC{W36~2z4N;*Y zN{VJgiNO*qEh83gv^+bTXpDM zT?K+bG9_9tUxf_I5J!8ZqS}GPBXocpNDs}YiDi{GK<#phA*M#|e_lC_7&Z)hQ&Uck z8j=Ru6^PP{Le$qN>FiVWaEG+hcq z@O>|GJPj)+qAW#n1hGJEd!^02qVUuC6Z0AKq;9ti9GrACf7Z?xvIVsrNeme~Pb53U z&=R!w+g^2O3X9XCIPwgphxTt`3m@@K$I3-(-7i1>{OF-s0nxG{3z%aV=opQFqm2MQ z;wxilh^}4!Z1?8&@72F{6-BXX$*zKM#WZ)0Xg!NI1&NRN${3nc`3t~D!26$n^2*us zXP1s|oi;1odXqVIPUJgx-J>72%ZHaf{c{@+zXQGk{%N1e$G)7%$BYZWIbaLeSTKur zfgRvRbM(L8|8jEFCmK<<2D}IyUqB>zIRO4jN^*#v>9-(5&*|c)`Hc27*K<>pO(dPI eAlL6d0R{lwedFI?qTZPR0000Ur`uLHPN9She!C7ir&cczu;NGLb`mMG5zr6n8msk0lA2?Q3t#an;&t7|X;lO{3f3UFu8eAVt z9<`q~FUWH_H1G_*a3EO}mN!2BZry>`S!MC`F?b0cKLi-2Iq(iQ3l3=lnuVE~c>HjG zX0s2QLq1W!DW}Y|D^G5mm?KM|Khx{`ih~b4hT#C+%6>f4-1;3kfiT3iw#XNdu=ATx|i-I5?WH_LcTA_nBC6{zn-G zfNN;0c$O6biJk(u<_2^*&h5v{8u9g20Js2C>O7upl|xfVi_nu+oYB02)qVL)%2*|d zLagFEJ~WDt>Nu5b(}LnyhIe(`DxNh5k2JVe{7DJi!BTru{|Fq5e-jYJX5WBE&A{0r zT5*Bb6VNu64!95WRud~m-aTR!nflW>0Gwedb)Q6b<4SVN~R z7LkA=BSYyLZi-seFgY!FIy$j)@X@prFaZ@6&vMKifEU;&R@}jNxirg*pM@%}EVMEK z9e1^^I%;SYqPQ|Ge@fmeoiB=oT`Hm)qqyf0f(8e-e%PU|Ry0QUi~GPm&pl!{yXRY! zose9{M+)&cc-oV$ZSKT_5Rcmvh&n2RzT_-6pAFmEVh0g0cegO<`2VY6TZ?ApY+v9m~H+~$jbc1-WIW%$Y8F|*7RJjRi%82F8sSS9II6qk}e|+-}DB`iPm%#GM!wq3-0{;C+ zS8knq`Ne~;oSmPYr8MJJNVhMqkin%etgH_P%<`i!Rr~eoTes&pE^)kd`Ta9zUtK!5 zf9crlJ^`o7GQ8boJzDV9KL?vPSO4Dl;ESJD_?sIXS2_N%{vHc1+fj~-92YoFalFuR zdj7%jPcz3d$2T1Ja*0_B?vy{mF~_mLV{q~HBaZt{=@9T|a&x>9?9weM-^p&-cE94y j%Pi8Ayc?8c{|hhxWwayt?aPtZ00000NkvXXu0mjfNNZ@K delta 1077 zcmV-51j_r43d;x~iBL{Q4GJ0x0000DNk~Le0000Q0000o2nGNE07A9Pm60JQe*^7F zL_t(|+Ps)SOBGQR$IqFWXTGPTq?ivw9~K&jNVG7bO;OOUeJv8&MAR3EmeD7OXj8PQ zeY>D2h!(a>!pNY==wXPdMeq6Y&D`5LbMNT9Y39wnQVt%K;hy`O|2gN*J$Fz_3APs^ zlAA;;p9n%FO=)#TReVr8u1b|?O%t{!5L*_d0 zWwr5no^GKe8EmXwy7+P?3S1s;@(g>qW)q=8&$ z)&Vv(NQewb0v3=WLDOMD&5>Al>7bwqk_-Z06@t-%;ao|;0R94HDv}|<*C3G{u9n-R zh<;>%7N8KK6>%{@o+@1oe-4ck79a*lKgv;{Kr)*V{*tZ=o#)tuF3J&G5G(JrS3^|Z zu2K}3gPaf)D$?PTaY!;psQ%@;LWn?)8Hhp_D)Kk=g3V76NTH_pT?-IRE`6Gv#RM5q zOGZzE4xO+8DL@GE4VMwac)WTr$FLYQ$lr1_yWFkuuDznbD02EWf3#CYK`ck@-*gHX z*eVhlB9s|PLJbi%iiCQ_#Y1OQ3|!$NLs3fW6oMey?}T9?I0_`QKq>v13o^EQo3?#= zJW87!!8XLSzr^U_z$Qo9p{2vhD+U=gj20VTd~OLj;ghk~P|6(b6`|UhWvp~_1-1GZ zDvBK9u#BBt#yYOZf5*HS9FQ@dgIl?kJ^>HZ|CUFV>12>@H2iY z&-!vQKz5q!7};U613BgJmFzv)EZH-%<>Z%>cAsciSwC4XSyv8-^RiC15-G6({nKwj v4(!r}JNb;ZlWW%$S%bK*n1ffzXV#=f~Sc^|Vwl2!KhsZ^fA*EgUqqW^%6zuxV3A7``K>UzC45}3nh zGMOqcJ!&)>pJm|JN~O|`)oK+$n+h*Hj-SYcY_za)@WWIpRX}i)p*cJv@5Lp=&y_Xyy|5a9m2T_teS3mmQJq2PFtSZV`22{}$8*WFpw<5YIt!O?-P z>uy(d==8{8#Z>{<%^*>Qe~wi2&``HYXRv`uN~mLw`+U3CaTRb~j3Qgs=s{&?j>qx1 z4m&s592mIV<8;@i`_VLNUNj1nt2+019O%DoAeG%(SYeBu<6;w|bDqnL;cr#LbDSUD z;(+hN2pm-9zQ0}7b;|J=pn>C*s=9arWAZvK<{jq=j7z<2`UZv>e`3Sq4hLtIFcB>* z)H(RK$z(E50z7^Cf=tLJ3-wQf!C;op=P%LXVCtI`%xyfGArrD~bhGgd(8ErrbH7+D z9-8{>jTW`hXmr+WHebQd7ocu1hW!UU{Qz{Y-EQBh)oSTNp>WYe@WoSQC-k&PzjVXG|j(*PC;)$uPyT4EDBtB{;KuswaW!V!GD0xKojce t|LtFGwyDe2AFuJdc6&*1Y*_m#zyRYx$<8lav#$UE002ovPDHLkV1jPheGC8q delta 652 zcmV;70(1S92B!rfiBL{Q4GJ0x0000DNk~Le0000M0000c2nGNE0Km>`mXRSSe@RJ1 zK~#9!)RwzW0znjpcXzlHCMc0hqA@}M3oCnLX{CiFofIa%gKywN_y8od7KTQ=)P#mc z6cQ2=&^2hlL=3Fw=#I_~yEC(>g_HbQvU|?A{~pd2P4VdsqeSRw|X#cDvmge-4M%U@&k9@0q6gRIOI8Aa>8rae#Tp3D9Pv(Kt>f zlR44bb^SB7+wI(It9D|ErE0@cMi9{kdnM}0tc&y>oP4rnj9?wC}0p_xx z00&-9r_<}0M4ieU;}vr-mw9IK;Du;3x`JR4l!s#u=87B#5Qd-V2W%L|e-vv9Ol#-| z?8ce`)B4JwEZmM2f(g2%U=_zym@5Jsv=n~8c8v|8W7?m7z;+x_0@FWGHqfmr_+wsw z|GN&bieu)>h_owa1UtI|rysL?emGWbIRv8tLWpZAbfy#mcA-%LV~y>6c^~@$GgqQC zrDp((9ka7eWm+qD#h*ELe*^O`;DGKm=9fMmEZRYS?AWWezPf_CRIRb{di+~m!EgVB ztGV(nA_G5mI-O^3XOQk5n1i_@@Lj!LH*rxx;W{7^jl&$wb-b4YZ-e%W#o|sXm0A$h znl3=iX0xBq=g;8Q38?&4Q!f4iG*>E>#+ghe0)xb2v2ZXL)Iy=qVwb|bp`~qr$u0iMYKqxyOM?f+A*fi%6^9JgJI-qCm-w$2o mj5f=Jkxes8#hBZ87hnKNJJdjs!O1}Y0000OW8+#M+%in|>dBWX%TIFZpOg!|S?coOAXEfuZZ21OL{4;{x6?*cgq4JV5TT ze#QrKgIvQ{sguc@sh2xvXb!_Lf4s15dt#dAxR2_0L{St^K@i;Gas}h#k8pH|6+T`r zmsiv2)MOe&S(dN9@896#J)D~_xS{-Rh8a571ua5YU^){vxnG4(9LKSkX3>}?@{Lu6 zo0etm>jrO3X4i@vOy4lNpd*dpBZ5<@OPd;v;ha{S-~=BQydLD^OnDhVf2B@aR@%8y zsZ*&_sZ*&_sZ*){+Z9)iXa-yAWuE6--NcQl?1E=Wl4u8SOqtZhRro^`Me8(8wZRJu zOwYn5_qQDyo}#(*Ja6v0uHiUNFW`mXRSSe`-lY zK~#9!?3d3HU0T`hG{xG8lrS=0zE z3dX)W7|0zp&8A_<1BdIqp6|!;_~#x;p68^cwGL!PtH6}fF$M{~2j8jDe!%DO85kL- zCv=%g368}HhJD+%&s0^FMNu4Ae^K9INs>HSmUV;a0~n9BU@Wi<4_(*2P!vUMbIEC% zzM7_ag~MBL=3iiei<=;W)3#7%EEbv*rY*1YU|G{NiFC9=BbRS94;Cd!+U*K1G-6Z6 z0{OWKO`uT^@Mt68wUvVQ0Mm_R{LjJpS{^rik?2;}c>CVGp%g^%_zHMWF!v^pwxW^Aot^QMh0RU+> WhkN2<|CIm$002ovPDHLk0$_rbPrSYW diff --git a/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png b/core/res/res/drawable/btn_default_small_normal_disable_focused.9.png index 4ee1b3fb17a7eed1c881d277721bb05271bd7780..a343515309086c4d8c46bede7ee01579c8b39b00 100644 GIT binary patch delta 661 zcmV;G0&4w;1+WDniBL{Q4GJ0x0000DNk~Le0000!0000c2nGNE0Gvc9vXLPue^N*rf3hTp()0f>jHr$OKbzt?S;KfrzhfBFq)9tQ%Z z|Nj_<4M6h?6F!eK|NA?9JdWlUX1pH%Ka4#7p9GIH4dWQco75SHaUN$Jjd83VA4W0$ z@877$3444b)#Lw>GCuP#j&aoL3~exAG^vlcCM%W!nW5|P|0J~BhOx()aB{HlhZDf- zapqy{aput&AJHC18=xOef9k_M#xbh1VdZru;`8{M@2q?;z%6$mR(!BlYpD8J?$H)i zm_NXN0{RVKj6Z(-m-n6;^Ct-qNAcn6P#_-ixf^ z|9ur14ypYoBgcmsyPtw)QEuUkabQpF39yu3!Nl~HG1o=fQJ&+oYa;hQNbC0 z+snWF_gZ(n+O^~=!(x!%kmVVn9!Ajw^t>#P(g0!wARemoXrL+2hd_K9=)cEk{=@F^ v;SN9^XJQzkVASIy4G>yM^MAPd4`mXRSSe=12t zK~#9!V)+06KLe3~XoVoah|OR|Mn+yBB?!cPK+J_h?{6Uf1jMg^W_(7|&%gpAkPQd& zMJL2)x&+#4Cx~+V(cxtLA%)G7buor-xV;M0$SuOaV4QBvf6@QvhXhFPdZ6K-uo?^mqCsY&aU4G$ixC@^Y``E3 zG!>67TJz!vG-$9IEF|{-nKr`@i2N17;MG?J1Fm5+P~+n^RsFZiqd;siroY-Cy+C{y z7ST*->iM~TzLjG54U88c#$_l7+~D`R4O0i!1JsK%jDdjZ|3BiB6q;Hle|!cr|NBe4 z!Dwok@f!S}1cU#RU@#K}F2)-aj1+`1jCP;=iv z+EJe4vm*CDi0d&Lg-q<>f?3oBh^OSMQ*dk`$eg9l3w9z1wb3KskWJa`n(Uc3t4 z?7@TR*^6Ejp(0*Hq$*X4Rs7LQwRCNpWb%A7Nt$eu-9!&=MjiO3bdt&DllNoZOaKv~ zORal9Ow3Fj7)zcTBJCs9NCTi}f7>E`A-y84Cc({&0sBcuAKg87;owOBSao;LFoa%# z8sIYjuxWc6OYgrg9+|m$ojRV7mRc@LSbPs@W@X{*mHLp?0M7*ly%P=?-noPgBXaqO zj012JKCEsp@144Rm3r=xK805&Eq>_1trK(g!OaFZ>yQT5rAc^_VM2Ydf6^eP+3DGb zD=pxO_#PQ=kgGdu0Ky@O;7ww}%~{&;_$OVtC15jMT{S^=H7hXQU^0A1;-iuluhs@c z4V*0>+!K1HwJ;*lphE>}13fZHSL2r?!7C_ig0=&2543I=cr53NtpK<~V~ScFyBo_L zAI=#f3OoMmH?QgW1I}9yx!m`)+D&$sibDdERKmJf+ewb@&$z8 zu|As49bfh|k8~Na#@S)MM{dpWP z!`fIVU3&;aE<C*xJ;g&)lI0J?UZS$tR7!^7!o)XXk56pRB$e&El#U5 z7OU5l#g&JPpzzVSNh*(UnSlIxTrI}DNTqY{U#)4pok=Mt#xa_~5K9i*&LAx6V-ZJ3 zi<_w!N!+~5?|`xNe{*9S)|9JPm<59@ZCXKeyJIwv`N6nm{L;ii=aPi!xLeft@Ij8?5)^iVG018_a})tM>5Es#u-t&_!HFD%-V2c~;_B{p(5 z*l9(5*uyl=DM_0qFw264#pZ@&YnKXTJ4L$qbbfSdqQU#*Hk8_TL(RZh2ws8b%U<)? z+`DJgdky^0e@L0>aTn=4>GX}uwTa`0t-i6k(bMAYW&C`Wd?uQ{)|%ixeqlGyT>AKu zdhU?sN$Z{F1^J2iBx#Z~MjF;MsY~~ML%JVmwaA1hEk8)=C-rFxPH_s~!2eLV4*%Of u-uy~j*COS&Ya5oEpYd-nY*zazzyMs~kS9?KLBIe23IG5}MNUMnLSTX+&HS$b delta 911 zcmV;A191Gy2&e}kiBL{Q4GJ0x0000DNk~Le0000M0000c2nGNE0Km>`mXRSSe@aP2 zK~#9!)K|Z26hRbzZ+3PsYScvTf)^9@f)XT%jfGf=DCxvjK@jY$ZEgJz>;xM@K?D)B zP#ZyFYb>G?L8IW0;IC*jxxJko-5GYYi1gbwlDr z^MjawH%8b+Xc9&X{MQK|3C{`3e^rS05)MAPdHUSGsgdc%wxJ0~SH+VtMOX{t)y1Wi zg#)u!FVll3gvB!Aal-7|xl

    $AT8b5n07H2$@K*JqiHf!Mo+~_0GdLF45C_g!ie5 z$SrUGgKJ05PS)32(D@7rzGP;LkdZu_tgpAo=M4L1iDWJeQ!_0JMdurUf9epFRjPZp z&V~b&BnBU5TFBv>%7$6y6gQfqstKL-gg92k`M~7bqaPodqeHyOjUL50b6=~FNJC2; zJMzk|NSKKF6^J|JlTi#fIHgIkc~gN{>e!M-VUiJLgFb9B&=Y-Jd15a%n-=C27Ys@_ z-g~VKu~$m0BT`Iic{X`Ge`xbCLrgDGcy8jD)iQA>>=G9$mgXDic~umL#K+|AOdiAF zeDjnEg{VRtM+z9aqk3bk2P8<$r(2m1xQHdErcT4_*gK{Y`1hFgWrfb@@R%@#lQ{K^ zpkFanH_X%vqnHnzQSKmSubAjifjf`6^qNW;yU$0$3~9M`#5gTxfBLUOX(+I3SE^W6 z?sR?K%n^zt<8vrFd087*D6rpQkh&gXtg0B(wua?BAF$thj}Hjv^$ePWWJaT(ts4KxI&IMWis4pAfEUNTgVWSWwpm8QJRumZlqe zR5r<8$e^D%*Zx1ffBK+*?`Z@Zb*wFMJh-}X{3R0yz&`BT6Q!Jv7jp~Yst5u|Kx%x3 z>_W=q8Nai3a|`WN_U(yMj<|OB@yhNKM@P1gkI8`FQj;Jcfi}t~1a_`b=G1(cUsAtL zUU)N4zSpz&w>&W~XTz1-Uxz1l1Y3tU3(=@cDSS)_13T9QWvsMC^zdo>=kfDP&&cN% z;SQk>SCa+$dFcQE002ovPDHLkV1o2nt)Bn@ diff --git a/core/res/res/drawable/btn_default_small_selected.9.png b/core/res/res/drawable/btn_default_small_selected.9.png index cc209c6a21c579ef146ab8294127c4c64dfc65d9..8ab8d63595e448a71ea8371465e9c943e2eff694 100644 GIT binary patch delta 1082 zcmV-A1jYNr2hj*2iBL{Q4GJ0x0000DNk~Le0000!0000c2nGNE0Gvc9vXLPufAdL1 zK~#9!?3ur76j2bzXZG#Nc?U5>J#!)#NMaP^z*uP1RuF6i3(-PT2zLGh78aJ;*w|P_ zOA8A-1)G2n3#*7GNRWs|6fr-@oiVq&5Lh;VZD+tSw+8JrjXwwhpMPyE z4qbnCkIy`JJ-}(Y@3z{DyQi*IOZ6dGUj?u%2B&;Fx(r`kK(#1_nCa^Ie>-nJ#eomk z%H}B4e*!d3a1^H;g9{D7(4kg_Q8#C`6RRJ5f2G(Qgg;FH(*@6Sli;=vm7*~y*}Omb z!F4h>8G4(56N3XY2nw)%@dHcB~*^#TsPg8LQkz^Ra@6gvSULK=hDINK@B;Yo#>X3<2l)IC{oFUBTrj$LM zBKjbrLp&u%d~$PQCM<3!0ha!y{{|n~9@%^yK%L~5P_nlE(CvWs6EFb~(~V~esaVk! z(ETmJ)lrqWtz!Thf7A5y$z{~6d&cqxAJzu-aIARVIIv;lhUEQ~) zuA|uPEYcxYFNAhiP-CRXl%m=YQM2;(IT0gnsbpTaQ1CkB{`9sa1+4 zGSyBBIe@WO5xPaNEMxB}7gW5lfl&+6$lI`Ndo3-O-$M%%Q28)HHlq~HdJ#E+F8(ui32ii2Vuk7UjYUHQw5B}5InBEmH+?%07*qoM6N<$g3$B+ AdjJ3c delta 940 zcmV;d15^Cb2*d{=iBL{Q4GJ0x0000DNk~Le0000M0000c2nGNE0Km>`mXRSSe`ZNU zK~#9!yqC{w6HySy=l$4Z6H8j!8k?%El!}7ZLoZgndQtEq2%hxd)xW@_;KftV9z;a& zqz5meAO%n2MXCs`wTDWpScnc6ar^Ym@q_9V?Q9U0S(`+aEhxHHx1!JCeYflNoITm!{b*|Ge-r#a*He)I zkBk+)QQBI8lSkwSMD2>pQ7cL0Xc{ZhXjGGWp_AbKrF?aO%2gsS0=HZrCQ1jufu>U4 z8DQUC#Y+~`coje`;CL`tz($!ptQKH~R+_+~{jydum^uY_7_pJj4+tw*89xM@Dz1SA z97xQ^@NU?%!jfRg5u17{fBbYX*0B-Txn2z{(<27d#1Y%Tfx_ZI#GXB36(CSkg)w9- zT!CF#i&&EtjN$=YgX5D0Y)}Hh3Gk?c;=w4WhVVK#x%ounIfJFsI%3mg8m6L2={+|r zS>Uw*qaTZ=)~PwKJjH;cwJl@V$e=zmODdu%m=50=O(yBZM?oE|Ybh}c)*wzEVW zzf8$-?A?vQ!b6{Be=u*WwBm6pbZ6l2^Q&fiq~PWST9%Q1v|CzqA%5L)@iLm`SG{fa zO|Hb|G4p0&dsE~Pwd<11;+oAil!@;%;dgG9B*Z?6BbG>>gtE`4SB_ko7#t||w|2sQ9Y*n$@JU4k;JPW$5E_dF#sLyJ`47hUVHGv3NSUfBRF5U586u-GxF%7W;Bq zXBBBT62J=Ab)UScxt|*s?!0{upC{4Tt=#TV$fF3IhbEw7(Lu4*;OWmoFC#6doi^i9 zfcl{xXkQx}etE4yU!isSUqk&XunrH8=C4AzP3ZXM5C5TQ>-bxM0RRY5Qxgg-a_;~D O002ovPDHLk0$_q3ZpgU+ diff --git a/core/res/res/drawable/btn_radio_on.png b/core/res/res/drawable/btn_radio_on.png index 25a3ccc54e4ae648e204ea0c9072b5f238d124ab..7bf696d8d075b4b2264c9f0464fa079cea7d1e13 100644 GIT binary patch delta 1619 zcmV-Z2CVs<4T%kqNq;LzL_t(|+U!{WPg7SEKeUvBEl3?uHe?cPODUGQ(Yl!iMrNX! z`m2eSp|H(=8!kGMdH(VNMZ7DX_Zw1rVr|)>3F; z=e&0xxjya-+lL<^Lgik!FsF^iA1K6 z;2-t%_21y@D1XAIWWkLRdmUlFdGqGy4u_*wvW#3%Qa|D3ktO^3`rOBk9s3Gj2M|xU zLhMb1qqn!W#cVd$tcT32Ncw!f{sRXNv|+Um@y}+6l^|UG{rz8*m6cWT{WeODmrHfO z-#=JWQ}ZRhdYJ#Mn;5OM4?G^vS&PN8Up{E7#HfsnjDP&;a=Ff7^;fonUy`d*khTBX zwQHZ@^zC0>UWP;>0n$^dZv^}}=}EFl2kA;iAX7fa_(!E!t#&${?~)K|+wLGtRwIxO z(uMdN5l|$?iv9Za>nF8ZZSJdx-5uz*lgX9*>Z<1|w2!oduK>f6k$ELBZ<)lPH*JPS zOCvP68WjCarBcEC{QUE(s;aa2`W@;BD*4#n*4EbdF?i<3;m|z zk<{Bb%EH!g39DlpeWO0qmme#aOS(uW=}tA3dw(h_Dt6NVX$s|*df;;XO3YYXTx^t9 zPBP!R_2d?e8gXYS6iMZ1i$Sl_t$yF7Hb7XL1yPs~`iw?Kg)x<-l}UY#rjvAn=n#tG zB7Yw@WP{w?JbI(OqCe?HOYx*uH&$$;Z^90XeQAtb4lkc{vP?yBD)qQhbg3-nUG|De zjv7{{FIk~)LG`TAm&TAxC5w?xmMAC^Q%fsRi5U4#(jcQ$GQ}}U#5f)5R8twp<@6Co5f|)BW8`vp9e<=#?5RvFIx{m9;z{uW2o8+{a~KeiSe%9M za%2rDYNKybKN=&K!^&ZwvZG*~ zwt_q8hC54lz_;QPzL_)3;M6#wwtuJ=$_vVczDi+&3h5%9OtsT?dy zRuldzGZQo#jR2|(2E%~4w6r9E>Pndf5kt~ZwAK}D{sGa&>qr)nXuo>P?RNW*963_S zJE=U&SX^8bu$e5DKsxaCFMf|qc@oD#bnrNN@#4jg>~?#Jd?(m!YAsnxt$$X-z`(%c z=H}+_nYH@Yn_3Sd+&J(juh%U@+vQIuA(J3I>BwJey9PIdkR? z9TS+P?z0P*E#F;G2rWjuhoDr{(%9HoX|vgO;$c`{SXh{YIaQXhd51!a&z?Pt;-NM? zG&D5V-ri2DZiJFw#P5g+rRm$sZ4cdB6tK+R#O^id2FSp!qJUjN1x(q^&Qo@gLd2#K zbN|&flvHwHHIEetWwT6;$`Z3kgx%__$s9IJEPd6PCYC0aCYC0)edS*P1^}WgU`JzQ R;0*u(002ovPDHLkV1iQ77X1JK delta 1638 zcmV-s2ATPZ4V(>-Nq;^`L_t(|+U!`}Ph3S5KkNbvWua^ZmP%0qyRblkDj(WxKq3jX zg%=;1R2maZc`z0K0SGoVDg6T^#0Q8FOO^283#cKfMF?rbhm}$gSU@VJd=%KS>~;(6 zg6G^jmrQT(-2%nLhn?h?J9qBPIlp`6%*;6xu(PuR|Hl&GCx7NA<|jrk0Rej*r$@Yj zh(tsn!Vo(4Z3E##I1o<}D+uRagucLKpTuGiClGOsjg4n57E7YhXpE1Dh=>UZ2{}p~ zo(` z1pg>3ENsBnNq>Y*&4T+Sb{vt>(b4f`PEJm~WEr_2ML*%>ktGKP26{?LO1{C@VZ{9F z5PJ)e)7RHmWj33$_d@1XByBd^U|wEcEmj8*{~Ux^9Kt#{IQUgULP9#&i)!-dzt_3nHa6K4|{uiuOufYpOO!HU1C%wCVwXWv|6oKvHBZZ!7s?wsK`3i z+S>XBPT#5R?QQUSy&yfM`hLKVlb$4-bdWA30)g^5#y^V3YG!V3?t3JJ+75dYCaV!h z2kAomjhIy>#!5z8TiXSlP8a?vV)rNS!>#dKaA)ogjM>M8HjBXmr{hjTQA!bHnlgP7 zBORpc{D1lL({f^RA2Zfx@ z<;mqxW-U|oH;qOE>+9=J)6>(h;OqCO!>;CINi{V!AK>O0>G61WeS@zPZuH)O>r>ak zmWia^!BNR<4ac!Mw$V50Lw)(Na=E07bdqjgQ-Aq(N=nKJ8X!%f+)@u_9zgR#GdMGF z^L|r2CAGoFAVL!^8f<$Vyn(9#LAbqZoX|Yo3~5toa5CYf;&jrikWSLg_BKUg#@N_c zqqK6AeCzh(+c0UwlOD)h~+T^0J$7?P=GG1AEb1yy2NX(g%=Bi~WnWYkKaI7W>ar$g&&Dm}P- zpYe__-^EjcQ?M8I^oowIR)lZF1^dz%xqlp92k8`hsuOdstgJYAQoH~{PEZcUFd)FY zxeCs0*Gr_RjlN0!XpCGAFPn6dZePS!XJ=>a{5ByMW<6>J(~=2*{t@BcSb$Zp9XvZ8 z0aT|p={xnMG4h|}Ws^?Q?TgrB-1S$KrchcCrWg~H9Vr9-j9!dG5#DF3V0S+hK!0_q zo%&E;8pF$wPbujn-M)^bG<IHq2*Z%OvOwAgm4SOBTiq^ zQW9J|auG@sOJQSULveFuN0PI+xcED4{ucF&s;x>o@?-KLF)C5$tF}#0Azh@C=~mAxaZnLHE}+#e zhGJ2(n($YFfe;iFB!KFI!EnRe+S(F8b+yQXh#_e=TB`+{e?;8kbtvsfbY5lk^z_V} zIddkJcT#zjvAMY^;2=>ffpp;OU;G*AGZV)_lz3dIudn|kBO@bDei9rsw11W?rPXR- zczAg3^5x4vFl!C^jQKf1}8-Ff=qYUs+k%&XSN{*)_tx^Gdp(C`1%gRaKqC zl^TzMolaVpZViE5nC=^XDFE39`OG`V7$*?{; zIyw|%s$k*pb~rYlJbB{Aq}Dk)I=a@>)I_Upf`VVfUBrUqQ-^umLtpn6Q7p1Iv3m`= z0Wz?wC}3Amc6PHf&n{Ak*fL`6zq*E!N+|5cu>zqG7O7F$Vis|+Tb-98hkXJ4 k`HA_7`H3A~`B#7e02XF{VSLgpUjP6A07*qoM6N<$f|_?24FCWD diff --git a/core/res/res/drawable/btn_rating_star_off_normal.png b/core/res/res/drawable/btn_rating_star_off_normal.png index a99441dc1a7025776bd0b448c192978c1d23c5db..bb154040df73853a9be8d832962138762991728d 100644 GIT binary patch delta 2994 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 delta 2716 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 IM6N<$f;V_KcmMzZ delta 3575 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 diff --git a/core/res/res/drawable/btn_rating_star_off_selected.png b/core/res/res/drawable/btn_rating_star_off_selected.png index 5f71e0873ee1f0a7ae5404dbf1338f486ce556f4..3fbe92ae7bea62ca6d32c5140566ace933367ba3 100644 GIT binary patch delta 3834 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 delta 3584 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 IM6N<$f`Lq^9{>OV delta 3250 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 diff --git a/core/res/res/drawable/btn_rating_star_on_pressed.png b/core/res/res/drawable/btn_rating_star_on_pressed.png index 4052445ab945a86f0e6ea712a7c5aec0b3f3ab42..2a965a7466fed0a9d2a180cbde34707fd5127ba9 100644 GIT binary patch delta 3869 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 delta 3718 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 ZFaSuf`C1zFp>6;G002ovPDHLkV1iwGi@5** delta 3732 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 diff --git a/core/res/res/drawable/btn_star_big_off.png b/core/res/res/drawable/btn_star_big_off.png index 7e9342b5c33e98925c55367a12088c98a345459c..21ba55751b39a6930a5494896208b419e2f0f071 100755 GIT binary patch delta 1442 zcmV;T1zq~23bYH5B!2;OQb$4nuFf3k00004XF*Lt006O%3;baP0000WV@Og>004R> z004l5008;`004mK004C`008P>0026e000+ooVrmw0000ObVXQnQ*UN;cVTj608n9R zZgehAMN}YmGcGbRw~-fp000FJNkllNJ-mH45!q$kpn`5`04VsTYbiqFr_>pPC&^Z3NLBn~C`nOT#8hN#B2 zkcz8taC2}3Na|=x^5^qXE|;xc%bU_-sV+);)O?=)XuBO zm#d?_V>GZSAjzXikxS?X*=%JEFNd?goUQo7#ebjz?E!(-N7Pi|KwIEtASC&DQp%Ug zvi#TbWr>Yue>z4s1p%y+*}2XRd(&d;UMbep1#)W6X$^y$0DcMKZ07+N*LUUWX<^?JX=1UOLF zrGI#_D2s(f$KutZ6r?Zs{2IO=1-IIT-RNiqez3*U>iHIf)rhGwKNBaBGrj4_G{qE; z$1@3^o#0_`GoY46%pG zf=oT@cw#J}?+N<~`GS=GE@_Emd87~UlChMQXida6@i%G2V~(>oo#)QybhB|nhEuIb z{Q0Aqna!#w$MZBZ#_Z-&n*LXfxGLqNG~(%^4zXtO(YRJ1QxNSR;CJ(xsf~}sbu1^q zU!umlgi~RDV>>iroXfGHSY^E`X@4UHa1soH{oo5QUp)c-JmQ&b^u5JYJBgUW8^KbQ z7@hnECct~(ZSaNx9W$LLz?{vdjOPGY<3xB32C|qu0}cRIp3lGl2!lSr&G)RqRu8 zY@Jpxd;qi=PFUn01h;{k0JB0^9N5RP9792-m(S|~Pd>+Md=&;WY91VPdOP5e#*#`$ zthZbe!h804j4>Qb8y*PsL0^u9S-a_w2G;=okC5A4&QMMC&BS->4U!h w{X4dmPl}juLUj&og~vQ_Y8&kA8;j5X0InqIz-mRI>;M1&07*qoM6N<$g46!Ppa1{> delta 1297 zcmV+s1@8K^3#1B=B!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o000EW zNklv{4bSXq@qG)mX2=YtrXAe349useiH9+4R6eKF{U-oy+^a z=csbIT;gpMl^d*5sR9`n4w)eh^cp(6?ZE4W^5YJxwhRvsfB*93%jf(KWZ*UL4&a2k zy1K7UPEK4@Q&ZE|s7wAYz#oo}kNHO=7xrbZw?L)oXgA0E{fmH z&CTDUE$!aGYJau5VQg${W@~H9H83zB#qa6q=_QRu(?B1+Em$4E7H2g!HfEd6=11%6 z>(>VOosf|5u%)HtG5Tcxn{Z-?L@J7fVjz7+M#g(RJw0E<#Kf3wHk(LFN|K$|*49L7 zYN|LqJlrZPEBg+spGNgQv#2tE&P-L~wAh&}y|( zk&%&df`1ru4jaet{>Ae0@@J^~#l5ZW5{ycXPNy>xxUsPzmX?+TW-kqfhK35G(I~KT zfjNou^K&_f->kRW?ECcKg0Zo&A|)k7#K*@!piS5gVs~F>oD9I1ZEbB&OG--e zSiifwD}nIlH`Cos4x{*q)9I8G;3PQ~kuY6VRe#lYc6QbZ8?U{=Vfe{`ihFx|>n#>b z7Pk?d<*II*%W03h5fTz2k7H_TYN5Ki`Uf0QADVwhyTcpIt%!p1aYi4vx3_ zt#-q2Q`}H)H8Py7zP|n^EZ|o({RaI7-j%O#BAnh`0Qje^t*uW0Put$!mIjd|{6a4; zFMs6(O zva(%SS=op1`q2aWMjZRfT$f767jTdTIGBT5jRYaR)t}ghec{~>Kwo)7J!sH9k%}d{&6~KX=$mYqN3tqK|w)0fGWay4BRa~lWsEZ51f*jnW^XM zV9+%>I{IgKclYwp(9k5>#vuNR!NEZ*lvh+#WT~mCc^AJ40ISl|({;3Q7x2o$!oo4O zbQ8DMDqfX@Sry=}$CGxGbt5AqR(~kJxVZRnZEfv4b8~aNgKc+tS8Jiqp*-HB(3Enq zA1Dsv_SRtKoy~hP8hRh%Yh(iI^>!|Qnaf>5l-CE(`P2i*xb(iJRLTUjO1=+MULCyj z&jJOjmHShzBotpjal-_7gid8woPNP??SH5L!S`MM7GMC7!t7VGsP|C-015yANkvXX Hu0mjf*i3@P diff --git a/core/res/res/drawable/btn_star_big_off_pressed.png b/core/res/res/drawable/btn_star_big_off_pressed.png index f1b8912f90c5344e985fc35b20d19003b6d7efc3..2c704ee2a787a7e195014f10d450308c13ede29e 100755 GIT binary patch literal 4401 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 diff --git a/core/res/res/drawable/btn_star_big_off_selected.png b/core/res/res/drawable/btn_star_big_off_selected.png index 0be64c41609522c367a06ef233ada955efd1563d..101357db07a2d4d96f872de8e74fee34e294a671 100755 GIT binary patch literal 4407 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 delta 1453 zcmV;e1ycIABEJieB!3xnMObuGZ)S9NVRB^vL1b@YWgtmyVP|DhWnpA_ami&o000GH zNklV;cL= zNB@BS0Zn|c_CaGzlNQ@5Vzfy$QCdLSs8v9@c_GVQ*vq&(JAZR_dd@fyLJ(OJ;!7v_ zWlzre&iS41cD`>J(=_2_e9Sa4!!Wt*6A1zY9Ki@de6bs66s3bDXuaw3A*tiqC(=ba z&Sm2?A6kNyirP0iTkBV_`_~t;dk#19Zb$FK=EmV^IbZ(+{A$| z8u^xW}8l$47REA8`oY zpfS1}#A}Xh;Ww--76Lb(R)JC41Udm7m%Jhrf3w3?M`SiE_Au@_b8Z`cf&v1$rU0!y z+9b72nhHGhw?IWjg(W-;Eijq94_|Iiw{_grAKeOK>VNMkf)GL2PPGJq{=7U^Xlf_| zvwdR`D_8oEhx`_ATkWd$yIG$supSrBIxnZ|AX<44%F3Pv^7!~Tc!y3wv#Sr%8qUO1 zI1xRAPit-)<iK_GGoB%+w&)Is45SRtgr$QYo;(t1?I z31W$%{ioGqgs*e1sU0MEIKP|oWfebMiIu>gPs$()K5)5QAP55F=jVgp@3+PnV{4N& zU%nQG1wVwtVMwJ?kdCFn3lZ4t8HcU;j~sq9>3?H_m?h%Q`Al8rVBzz#?~8kytN41X z6uQgsqBo_K%~0e@+m?KXJ0m(wS4XyI0<`|dvN_u{J~qNlD|!*%`UQhgCI)y@O;&Y zlGEsJ6rIezOCNh$8>^*2S9~2rs}F%FiVG5}stU@$53t8`8~O&551YS_{~FiK3uNg! zC8b`N=9{YmwsY_=HDjLNbt2w%XG9Hdm4EI-B9VBZnW+qw9UN1`J5R(r32CRTDLvD8 z(F0=Gx9d*nX02v2cq+p}JRS!{Q5Mvg%EWXQG(b3+F^6YqsxRi{noaI4@pAIx6!Cxq zW>RROFGOTZJ*=B$U=21cP4&e-nKOA^kjGSuJaUF(2#^=em^7J8TK=?J5#o1Al7E0@ zSu6O$X#{H&(NFp3>yECwLSv+3+L|Xy#)2URz2NB`mdEctDHsH$TBqrtcRYl6ymYJCx38Kap_Nv z_p0NU9~hLZ*Cq_jYH6R)IkMhM(C~VNR`*$hv%Kdqra^FjDSdSw!FvStw2l(ovI~36 z4w&g^b=ZA2t&{l#>j`K#(ob-9Zg9=;EkMlM-3RSN(z6I@Ue0aA8T$fx_IoebT?Z}t zTCT*%uAj($Q060q=UjlgFeYnTCA%Q;OZ)HiKk;&Z{|PVvV9lF#OK~6O00000NkvXX Hu0mjfA>y~9 diff --git a/core/res/res/drawable/btn_star_big_on.png b/core/res/res/drawable/btn_star_big_on.png index a9bdb052a97045083df59295c0d245bc29fa999c..9c2f7d2023f9d5baf8d883164079b61af6a93d8d 100755 GIT binary patch literal 4449 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 FV1h{t?4bYv diff --git a/core/res/res/drawable/btn_star_big_on_pressed.png b/core/res/res/drawable/btn_star_big_on_pressed.png index 159a84bb8dc74b5537bad66257c1f066e07cc792..8ac4bab9075db5b28634363b0f08ffc13a131273 100755 GIT binary patch literal 4249 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 delta 1522 zcmV|%seHI+bw(g`?RaD1P-I44WG{LIC>pv`&&8U&eVrX_1X zJ&;|BGQ|m}Qr()ah ze~sHvzYv#Q2s^^Tr{qo35ahN;#!q zS%KucKb)YDTVYSltbvnf0h|;0aB#Z0-De($}TR_~~JaLQ%u_qyz^ zKsSn;kbiG%A#v6DuZm8rEtD0?WsH*N6c8J_z`Nfk}73-Fw@6yYf)q3FK>Dc+?Dy$E-?C zQjYjpIDc*ku9}9x?(~3E0_Y`{Dm7sG0OXJh2!GBhk$HVB2W?$uxM4x>@nAhucs~j$ zY$(;j)|a)6I@PD7z$-xUq*zC-O%hUdXTL1kQdO=m8=3OMPmNchZifd{DT$Re#{|Il zr={@j?hT-pFwkWhGQV2i*Tnh5KOo=Tg;8zy2P0>;95J8lGTpbRr4;1rbXkt${#^0opbh@&g2FxIn$0(0c4TD3$mFvfwD;iF)YL1f0pIaraw$^|r45DG_JbAO~u zmdq$}CM}g&A(Jv9r`f_u4R<>9JuvQO{t%MmFCl;BMd@-A@WF#YY zKZCaXan~=R16QI#`2ly=`|S~b)Olmjcs-l zxs@H893{v17v$~Uy*Zu2j%4Ki4P5qtPA!s>HYx6BF={-wDo>IEkuYQ`Sbu15ZGQO8 zsR#F(u8b4Q*Ae6wPPaRZr`tQqs@I!Kj_u9XRhBQ$gn*YS(o5vT#?uhrH(IMc3!(hJG<(ntwlOzM91%gePo(Tw$0$mGGj(|Mj5Z8IAuR@jn6# Y0OO6orKei(b^rhX07*qoM6N<$g2-9xKmY&$ diff --git a/core/res/res/drawable/btn_star_big_on_selected.png b/core/res/res/drawable/btn_star_big_on_selected.png index 0592d5180afd6292c32bda4e8dbed93849095a4a..d453eabb15778c85bcf1d394d3b4215efc847777 100755 GIT binary patch literal 4232 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 diff --git a/core/res/res/drawable/ic_lock_airplane_mode.png b/core/res/res/drawable/ic_lock_airplane_mode.png deleted file mode 100755 index caafcb2ef53d4f4f32dd735a67812c0358c33d56..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1119 zcmV-l1fctgP)v8+EU3* zZ2x-os_NCZ>-qUvI6210$2FYh-EO!3^z^i_va+)3WF5C~c(`1yNPd34Sx`{m#W^xD zG2wHvPPUVmg2ABS@p!zowY5UiG;wrvB+kyxe&E(>MgSmUZ&_KHC@(J;U_fMNXY=gM z7z4Svxms~?G0)O@PEL+^e0&rc1CW)KC7q)V1dEu)>x=i)iQC&-0{K4x82!V;gFLey60C@f3DL>PiFSH=YNvp9b#;{)0DiyUK;&T- zA){7CKoBT1tpI#Jp8?9F&;YHnveKrWR#H+zJqVADjhSfyFfuY?J8x`kq#C}`0RpP3 zs-hx>M@L7^Zv`+sJZw8}YHAWiMMYBmUNS(duC5k!b#=TSMykwj0WdT)q#@rC75PWb zRZG^?)Yu@9GV@CS1_uY}Jerr6r`Oll+s&juRUa`5b>=Utde9 ze#yka!GYM_-KAm%*VosrcMSCQ_G(zz&Ur#uq%r^OakSYsuIKQ$=l=eFiwiU7iOCoP zKz~I=MNDng2u#%k-{=3-3DlSQih-V<9y@Z<&d3RX(I$Yz@a*E`?$2G&D5$ zxXDEHaV)%mh%7kX{;0wk5%a84fZu0tpD|4{j?*vN^768Y00UUp%k+SSxV;}heqyiy z^9%G=s+$r5U;_bkx}5A}y1Ke_6kN2mwN+=mkXl5v$_huX z$J4qW=002ovPDHLkV1mG(0kQx9 diff --git a/core/res/res/drawable/ic_lock_airplane_mode_off.png b/core/res/res/drawable/ic_lock_airplane_mode_off.png deleted file mode 100755 index cb2cbdf181a6badeb0fc3573906470aae3b0cbcd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1570 zcmV+-2Hp9IP)LE^+o7cpi}W9 z9|p!GK2n1-zTeulE*`mPI(kzNZ0?+M?zwyIwI64X*xA_;$0#ASwY6WCm6iS4-roK> z=AS?Ux!%~=m}WMcI~y7rvM@J5ydbXb;uuGLeSOyG=;%+Io0~peU0oNvy}e8F^76(z zIyycb9v-%AY-|{YhKABzTwIFE%gg`7ku4V@Kdw<(S-EuL#0eiL7H{9a6;L#J?%cVW zk&%&aJv=-N0RaJGYHCWXuCCgzUAuMxGNzk>f`S4QK71R%ZJ6G9{P?j$?wvVvW*Y#6 z!{HE~o}OZMb~a*cZ0!5Mz(5fe7ADr$*M*;-pIBO2+Ex@rJ);XiVPRpcySsZctWf|$ ztgWrZVmV#zCnqO={pQV^M*Q?yTwE0X{{F(%)m7ai(>^{veA>^RJzJ8IkuizoZC5=2 ze0_aQ27^IKN=g!xn3x!2MMXud+)qnOdma%HQL(+fy-a`{_$?3dZ;_(Q;Pt-ri@@gfjM+;jyYsU)>jOnUc& zNJvNsAS3iQl_Lo4(b3W0y?*`r4z~TsL}Fs1K!6(Fzklzi+Xd36Qn`G}fxxUnd~7g2 zkSTV|%Q7=FTTh=peGBW0WF|N`c=`PK^IzrU_ps5uswtRnd%jfN00F6S7IK zQ3>nKrAwEd;`zt!e0^7r&Hz4ahV@kpF3AAn0g-(l1xk@&0$GAAK$bbbapMMotZCMl zcIPT}N4g8HUcG9DPn$t6i;tR)1j3+v_39N%uXTBOIUN^}LvLw6lz}T(u9%Vc%?vEo zbJhTvhWvf%)F}c=0l)#Uq#P@N{QP`XIU-k8&J?5NGWaM^ED&(4jw%SSr5pvw#7oa>gJo}N;t3}k0# z)A9kJR?twW3Mq6$XlN+!{BD3tN4Fa!mB>Z|1_a?;HQuwaPVgLWOoGEjq%whc_)jKW zva+&Nk34{43;Os2m5m=|Y_JINV$u$jT?-zT zM~@yE@!b*tH4`jjYI1VYjJ<;ZP|2(e8h{vtRS$}ain^Tz4P8L$rSCs9z}O%jgH26M z)lhDR+y)Tahu(F^M+Wi1I9O{tEMjrDE3}5b=0)`G-8-wZ_YpJv<~>SXU0sUPEI4eS zlQl9$87t^~)Ij5(4_rc4xaEt!zCN4yh;gLr7(M(wnWC(WDs`w2j2q-Vi_TvFX!;lc zP8on={sHNNG9xoXw&b!aW)RX9)6>)Z7sS6@bx6 Uub`5Cwg3PC07*qoM6N<$f;`aJy#N3J diff --git a/core/res/res/drawable/ic_lock_power_off.png b/core/res/res/drawable/ic_lock_power_off.png index 4405b437e59c37607c357c985529aeeefe094fd5..14c002e9d5e572cd40a8b0b9e080e7aa232ab0d9 100644 GIT binary patch delta 1659 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 B94-I= diff --git a/core/res/res/drawable/ic_lock_silent_mode.png b/core/res/res/drawable/ic_lock_silent_mode.png index 439a6f59ec5a4cf717ca80b38b1b0feded85ea69..c89291a2073168c418a91fb0045a0adb5dd8c09a 100644 GIT binary patch delta 1297 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 D%&nvp diff --git a/core/res/res/drawable/keyboard_accessory_bg_landscape.9.png b/core/res/res/drawable/keyboard_accessory_bg_landscape.9.png deleted file mode 100644 index 8f828f6fe7eaf8523b21d86596c867db9b00d97e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 197 zcmeAS@N?(olHy`uVBq!ia0vp^+(4|$!3HENA}8_!DajJoh?3y^w370~qErUQl>DSr z1<%~X^wgl##FWaylc_d9Md_X{jv*DdlK%YvZ_jL%kdnf}^*{ZH0K4Y76DJN_X=F<~ zGvnY1rlc1yUmA9Fbs6oc`zy7cO^r>6;bNELzXiP~7k9af@>?HW@WyFNQqI%E85aFo ua-lse4l`TI&LtcPEkC@*O^ltxfZ>~{!tJFsXPyDAWbkzLb6Mw<&;$UF14xVj diff --git a/core/res/res/drawable/textfield_default.9.png b/core/res/res/drawable/textfield_default.9.png index cc78e6c92a9755b174353ae50624fc692208e4c0..12cdd4c981d2004a4f9b825d5b04ae68276b7ac7 100644 GIT binary patch delta 847 zcmV-V1F-z|1?L7KiBL{Q4GJ0x0000DNk~Le000160000o2nGNE05i>}3y~owe*+0g zL_t(|+U(oCZrV^32k;Bnfca1W1tEb%SdhB)1(-7A0Ww4kSr|HIV(r?Y1L}~S35hL_ zkSuwDY+XCRf?z>>n9rVLagi}xV-uAM>3^gvV=xi=`OmR&t^@1!T3lKM0s;Ei>%hf* z?n}hJ)Y1+;S*=zp!{P90wOZX#e~MC@G(k&IGO*)BrTL~@E{j+!e`Y}kgTWnW zpzo(zt}mBMadmZNjc_>pg%W;GFCE5Cr_;BkQb}Yo8KLX?9yXxW=)9z^AQp>-h(@Cp zJgwg<50JD+zNS(s3)+s2@>Yy314+TPJeAmV6x|*W(4wEs5P!Hz^C zR+1$&KSr|sC7a!N$!_eae@wQ7mdL<9E#Y=YB{qKz?8vf>pgdnj*kU`+;tnR;Ie_gy z)vB%l?Ei)BY$L$_9QM&RVh5LxQQpr+-0Y4f8`!6(+tUG3{*VFo>Axa9^=xMwLC^Mg z>gQ&65F5$2DX1}H#=aT6Wcy50NDQ+e_J*G0@$Zxs|u$Y zXDna?8`vmd0~-ZwU;`WTwofZJH_f@B9QJjTKWL}pQEb&4Q0~}#J=-(3+*tne64?H* z<&cg_Z21PB?keZ3ap7W=_f+#>ze6G2!PYdbM~f_P%=3)7Fa^y!wsezr8&COqU`j^Mcs%~hv*l^S>&aw-IodvZ_2zB^zQu#r zyM+C`6H@0M>UO)2wDGU$bb37=kGEe5V7p^;k{OxrMbdTsk7=6U^Z9(s6`N}?7*yy@ zPxJ@wXf=fv;<=T4(0HY;@RClakKYH0!nF}#qks);6tK@)C7Pd&dG-{@_D=sip9}vL ZU;rvTr#ur}!r%Y^002ovPDHLkV1j=DnXCW+ delta 733 zcmV<30wVqA2KEIZiBL{Q4GJ0x0000DNk~Le0000O0000o2nGNE07gI?sF5Kje*&0E zL_t(|+U%FTZW=)lfal=&|1)4DgoI3)&M!da!VloWl`EuF$ZtSNic~2~NlEQTaGJb; zyR>N#k_A-!|7GUHpk=*xyK99=QCMkocihZ;GsE89jI-PAz-Bp)gC;x2SlG=X$tyUeQ?v=~st4gH;sZA}G zNC@(|-EJQ;aYZ9^cvmPCu4=U!BoYa5T~`^s2-$2lkj-WxlgU6V7W*_Be~s?&mKu=D z4+J7rJ_>quWv-3M*xiCnxY}+A|PlHfWiAru6+Tx6TC>M z?kuYMizT9aoC%ece2CA?5g;0kdJ(g8IycFHbm>UC909O(|BlY?SF6=ggeCwwQc1~&ZwAR^@`)xCRJ@$c zW`Q#T*PR?w5Y)EgbsxvDr@$$*-|s)5^0)bXemR{^52>pFJP%-CG!gw;EEX*s9(&q3 z83(yK8a<+eTfDr`Gwh;Qlo!nS8D~5FocvcN{WIV{22dBsuK-h<-vSH(=Crc8$IsL2 P00000NkvXXu0mjf31v*b diff --git a/core/res/res/drawable/textfield_disabled.9.png b/core/res/res/drawable/textfield_disabled.9.png index 9c77149beaca2aa56c671cb8379efc3b52f5f182..ad8ba70735c6a12d632af5d2137a8530332e33fd 100644 GIT binary patch delta 580 zcmV-K0=xa81l|N8iBL{Q4GJ0x0000DNk~Le000160000o2nGNE05i>}3y~owe*yqW zL_t(|+U(muO9F8m$MNp3cVak5dT2wCL{mXcwYW)B&!EN0N8p3-5jeT@44T5trKTE! zAf%un1+7Jj()-)@8w#iSFE50H&l^PKeh0_PyPxOj37+Szg)Ko4XtO;bblV+9?65Ww zyHF_Xbi3VS$8q*(FWLgrVv*&uevTHrgnm(}RIaCDmrA89L7!zZnP@7N`cf1H$bZbTEV12g>&<5K zlfci*686(P-2L zSMb=8Jx6Aa@pl9thW`^g`ez9KZXkkXbpadLz(&9ZHUc)VfsKF-Yy@mz0~@Udn=k!= zVMW+s{Qm`}5d>^t0~-Mw*a+CbM!*I(uo19BjxEcwOAiSw!DC1EoQkcgYEz;>6+Cui z&*5vnx;lcb>v}^F1RjX#e$3nTgHS>-B9~`G5|EU3$66 zhXk74!10BiA86;i&E;}W<704#?+ODpuz`($4Qvz?8~>h~c*?i%8hP=z00RIGXu1cy Sz#`fJ0000n z+h$mZ(r&jC-EQ|Cpo?m?dL0TVm&-YrpJlUIBb`ov#p7{rkunU2L)PhZ^j53&3CMY+ zQh6MmW5L8&EVgf1R)WWzf^tbiTJi{kd{2g zsxrBXunW3KkT$q`dS=+#l0yIlKmY__H30NVT`GX5#}OA<00ck){sjQNy@#J1)r_>{ z5!zj&J8oe@F&)QoqX3|l$s;hoNn<RGpEdYy?%%x;>7d3T#bIeKS0=FC8L_Fs;X$3ro#Lc!{BA1P`H^pCpQ|6ZHN!B z}3y~owe*%$7 zL_t(|+U%RXYZO5k#%E?n*^~1VgN>kAS=&g|B#2fvVv{PJjYcejg`J>SXeA<^q_Dfn z+9GfPErJ342M#2tA$Aes*WJd;&iKB&w;x9iymLR`xaWa)caEEbJL* z4InlxPuiVMN1bfFKQ*o2T|TmR`v84)l!Ez2uzy~Re$;54f73oO^Krs;e|^Vs49)x? zIXH0X`@a0vzSLY^Z#%Q1akcwZz&EsQr!_&rcd=1D`^hEH>}r4>z9eOC%m(%s*!PkjeQCw3a|kiupz((YzVLc zdu$Xg*Rctz7|DOYc1WO(egFOA4l&;S@?;PnjZ^3!Rq{B~8vf5^Mxd7k6@{vO`c z4Q#`UxiLTHnC2R%5#f1eI3>U`ej!_D|j2*?!yVvw0fm>?E>b_8M&&2XC4 zaXYDogTO;R+xur&9d^LX0hs@>sy}F3cRTnXpv!|1Tn` zvazxKBi90uUSzYFfO!TI2mh#;@c&`S2mh&P!T(VU2B!u8sA$1ItUjP(e~FE5)^G_T znx`U~#{sP^pk*8|L7E{Do2lUwbhDU1Z5&!!0I3hC*);k;+)@z}1C7C`1)~-W0Sh2S z1tS$rWW?qJMg(SIVPPiQwIIDnW?{8}83@R=0IV0uEKo_!1h)o?f%OAOArl#fgX$I( zv*12pVrKXO#2}hM_jI)#btfk$2Pu|-)JlH2CS!6aB?4v+$V_-A@IxVE7LYxa$_Xf2 zp#T3gcsKS-IpcI7l|iK{XC_bQ|4fXY{*OAaPg;OjkW7Q00C5LL)BkC78%h{0i-wp5 hpjIFVlcEP8zyJnz<$^XdI-&po002ovPDHLkV1nDu;m800 diff --git a/core/res/res/drawable/textfield_pressed.9.png b/core/res/res/drawable/textfield_pressed.9.png index c909ad2a5d548035a2382b26310c610481801f08..bcc0152e0ccf3f3e29c1f5014fcff6b71ee936e9 100644 GIT binary patch delta 1123 zcmV-p1f2Vj2>A#hiBL{Q4GJ0x0000DNk~Le000160000o2nGNE05i>}3y~owe*_yz zL_t(|+U%RZZ__{&$KRdp#3B7nTNr?W1x6S_NT`1TOQ&uOKqUsmz=i~3fEiK5z{bRk z*g=)Lvk(}lkPwv+RjJxUPGaBj?(DN2$7$@Q6h(SZdOp|jNztcYec!#)g-I!4+=4NN zUt6-V``+USdtAfr`Rnbt+E&?IXuv)-@l*H>2Xx`sJP zxQ;A-W8Q z1#XptW$6_FFoHc8wlBeJOW11$u(RvKhsGW(Uye)SQc@thtp)Sc=QWs{wP9|?hKUIa zmCb?k2sFXYkWPRHfkb5ssGv9*^4i?eT+N#cF>Dzm%fFc^3nnKK^i-&92W^Ctst@Lk z7a=4#Xd|dh=n8<@rs&~{e+*@)Y>`ZMU9=9g5x0h_#*By=%uVHR*vd9I*Qv~2O{OSbE*X~*KZNZMfvu|{e-D)%tDB;PaYy{v z0A-8xLms_slub5LZb`yr%uwXoh|E#8YGgQhb}7%6DX}VL%b_*`32413LJ-T8NXA73 z8w%Kn?iN|fPDt6M`bi$~V}ooYuRul<2zJTdoee3FX>SQPoHD*mQ5<#zS|QB$>}-L| zCPj%hGU1jBTZq2Cf0I0WBxQ#Tv!2bvV*zFpJfh8#36zJ)@TQk5DqEeu*uKSNpRysT zsuTrXgc-4hL#~a09N<3`hx6^UtsGb&DUP&zC)oc9HZ|kN7zCSO6KskR!yecP#Vc}J z1D2|YI*Y~jU!uqpc1EbfV8;_gf0X3v#ltW&Ld}JpvSqd5 zEpdW0lSFvm4hc<&0H^p%{?8-cJ+rJ>_ z2%Vr0?U1^Q!1jFsekVYF0dibKXy4NBFgv^24xD-LIy>OCe0>PsQKwkB*>xr0d8;=W z9U0aK;#&cDe_eD3XR)u|Y1rHX4+mG>pZxi`-8_G(>TiF7R?|b+3_oXPi<=^6rL62a zK-k@`gjO3d@^f(Z`$iYJI?-!h4BK+xJ`OL`{h7{Y6&jmFaisX7E>4UZG~eW>dHWC8 zOB`+!s3UK4UQIlccY0uJtv_U|I6T3eB~Bwl{(hu&L>uc2uw|ajC7y#Q4y?XaotU&+(002ovPDHLkV1l||3dsNf delta 1017 zcmV~f zL_t(|+U!_6Z`42#{&sEOgS$LQ0tHaeKnW!X3FRlyq)JBvkth%a9TJEFYD5qPT`Fos z4~mqYhJ%6#2@wf_LX_OecW3W1yY~8Z#`Yy45>i(BY@anV-#qp)J|?BaID;`pDw0)} zAD3X6u4R-Dr<6FNyY<%uw;Q44ZIO;XZ6$d!w3}I=NPs%Y8 zL4P38bp;xZg{v1@I5nkB&JmPNL$JGOsNZ)yv`*MKJ>{U?ve2k=SeBkWe_&YxPr~g> z>~?)@?|69E*~QZ3sH}@|k%zr`^VZ`{%+A=Dowm_#TND8Y=b>>08I$|y zqU9-Dxdfc147UR?g@WZ4l!a1g%RtAfK)@`f0dwcY+YVF32xS$@2~2e+bm#;uUHj6HciJ zWNC^J8`qmq>5)RRA|ybC6zNsV5~(ULvUZ3C5eQMW$e}`c4bnQYtOmiRmZ?J-L1`bBKftELNzF;2~{GEfMN*QZJ1H;+atd zW=^8;mL;&`6C@|Mf0etdOv(z2e83@(ntk)tf@I$*6r_e$5 zzB31Runo88=?@P_b=TbN;PDrT4BL185z_PF4k>bHVWehu(D1@lox6HI`Tb+Rd;U`0 z`}G06u1f^e+*-^W5%Gp5^_L}vLy2CWRQWla{kkzETTW=(jR-6U_vrRqJ)aqD*3sGA z$C~}5E>2_~Pugbu8M}9%y`bBz!`QJ2FWXP$?U65i_W@g>+hfAaJ`H~(JZU_Vt4H=% n!tr_VpAo1oP+=UMKLQK@5q84p<)YCJ00000NkvXXu0mjf?N!LK diff --git a/core/res/res/drawable/textfield_selected.9.png b/core/res/res/drawable/textfield_selected.9.png index 0c1b4461fe079350e49276124fd07765d95f01a6..47115b608303d379201b97a2faa4a15c2d4491e3 100644 GIT binary patch delta 862 zcmV-k1EKtu2KELaiBL{Q4GJ0x0000DNk~Le000160000o2nGNE05i>}3y~owe*+jv zL_t(|+U(muXcJK!2k_tJ?vf@((qLNqdJGnSWCmpI4hfZ#4#X(&h)D#D| zPMyWkK?)8k2qFlsf*@9+EhWh%@A-b0yvxfaA@5?668-+*<% zeBUS6bt7Ov_Xp=AW7ldm+A9|6?Wcgw?>x~j3w@i|!QOoI2^~I3*=&|FnM|1KR4N5g z%i>^aukw-8L?0jOr{*JU*=YYe||3v(@zK_dw-K{_AT)N z63HGe+06xx1$Mll?6J+(6I%#ij|01_&*p6b+snY7NV0kV#rCozf6Wu(C!&&J>-#;s z5yIAyF|BY043MZ%t|o!KZ`fF|Ot63rY+$2+J;m7Ob}G~`Gm!p%-k=kJJ{str*c#Yu zD0^(ap54!_iEUi|&@a|sUIIHAwr=c4js-SvedXOyqIHcB7o+S`t^KUAgCK~$4#O5S zdu&Fo*XyBQ9GkDMe|qsb32)}ER4N^xRva7n-GiXH8J_+47@zBf*eRD-cZTmDcy+s4 zUc8fGP`yuEryR)r(RKI1$@YJKp@r9LfpYa*FALKf{(z~x>a3{yPeC`fx<30zmZG2L z?cQ|O)!`~!MjL$9p5-6NYf-XwRc?g|zo%LePJfO3RkiywG(^b07*qoM6N<$f@7+weEKd8Mea0&z1!Ux=k4b0&Q11qc9Ycv$-=w2+nx8m_ukCTyg4R>fGQVb zOsWW0x_?zb)oT>+dg+qLWw#DGB{Q4BGtZ(iGyqsH-pIs@F2Xy*} zloh!4emw(p&!OjUq@1iNGYDCP<`Qv8tt>q$)0;tCSe`5gWqd8TLmzhOsf1VqGsBsnvLyG9dQX?@g)zWR!F{Vh* zf0=2j>TrG-5vY072f0cF$xBxPpoMV^+gM487{~BPyU%rk3M-ZTvh2>|?cpb;2U;>#Oe{%8^bTI*NKN#0H z0kF}{gOrjz)(jv)9bhE@SdwE^$9LD>qT(0(kWOhp5CrK~SyVpK`5+9#SVsroO6}-# z2@ey#?~izB0+0^2`n-$*mJMieB0e9yyEo`9-1pEZof9Y;{e(lQ!3f-+Uto4)HITO4 zUE6+o2<)w}W%>PCQ_b(#t*OVNn;v7g@37~xxlz-W^WwxKadXc>+`k(~@=!`=pN79m vS(|tux`*^v!ZF~;1F#CDC7`U%9{~mcyMVyO2)zM%00000NkvXXu0mjfj#6VJ diff --git a/core/res/res/drawable/timepicker_down_disabled.9.png b/core/res/res/drawable/timepicker_down_disabled.9.png index 7d8e0b98352c83bf7ab77aab480d406770bf45ba..af72d229993dc9956de1b47f8fba6d91e7cc104e 100755 GIT binary patch delta 897 zcmV-{1AhFx1H1>2NPh!fNklfapJ%XtXqWz93FGT0^*I{eGWm`+sY_UJrq@$z*a3m*2tf z;Cf|hH1RC$_lJBwkIHmh8XhE|$Y~8<`=vQd7rp>3%W?taL)``O9QpGpm@16000R~1 z2auX+fH8)!fENp(kT_LC2c$&v)OFMrqk(3{mbPttJmwS-EPwah%^3ry=Kj3 zlV!8n$bIMYIWtX@t^$k2BCA%bER{+{29e2RSfNm0m48ZwEFgX^Mb?6ND8C^QJ!hHTue*uYtG8{0x0K0 zZ2XL?kKz!vB`!M-a>w)EL7jykCmrsl5)Gn5*pf;-IohH^F@nkzz2)hejXeeQTYv!o Xhw-&8L?IuxC{2&A`kd@cTX#~v`a)?|Z zXUM9n0dXk_RO2G1erz1yU>2=L2~44e`9JVbXv?Jhn0E?^tF?Aa@^Z8K9#Dn>&@382b|8QN0!WMiH4J8eE`JP+Fn|C8NB{&7KmZAV z00L-H_O^NPvMhb2)S1Z|Q4~FdVYsw%2b$t-Y7Iu%R={rj{=*uRJp;S5Yn$g6BMcyb z06IKWG6v+K5+e*CfB+Hz0R#|00w92s2W;!Qet~8^y-7O;aG{iXhipB)$zlxPU7Dt| zs;XMpzS3EACU%|8_s@0*zTZd>@;pBYf?(FRV| z|8^_uTzVS~tS# bQ-A>gnLl7H92(KL00000NkvXXu0mjf^;e|# diff --git a/core/res/res/drawable/timepicker_down_disabled_focused.9.png b/core/res/res/drawable/timepicker_down_disabled_focused.9.png index 6f2373ea88a1cbb32b296ae1e63789683fb4fb7f..2d80424af4c297c41a7da1f6c33d42f92ea2e9d4 100755 GIT binary patch delta 879 zcmV-#1CadV1gZy+NPh!NNklnrKpZ+sD zUay7gx{%a_5TP%E-zVT4?V|q|K>+bf^Vq+Eez)0de!yesbbmTv?2onEZ2}J4+uIND z@H6@z9*-=8CYhy!KDhtx8I;8Y^5d_p0gYCw(06m#%lf8^K!7*r-@%>^*(;0$WZMPo z-HE0^dvpZv?fM&)aEUlOfRA22K2b=40Kq9Hm~6Op^Kd~aC{z=Ze02A~0Wxd8Pge$HDvi~=uHfl7TwfiVE;n~OMvaZm{p z8lZO|XMcb?i=b2%8lVnuSs{AW7Ym>X;e;XVJ&}N^wK~-TITsRIqz_zsGR-i8S;mO8R_A4$ED~CX*)IHEyEuvBbNE&sJ z`WBI2fBh47oa^l2^+f@me@d&6-cp#d z?hnakDp|R-lBEDT@`DM6@O#W_1@wn_LW9yEXMo6HhAeimeT7Z{iRer+JAPY}K(3&d z(Ql#OMqfq0hMtq5&QXdgDhKG_(09>k7eJpt5?oz@bRxaew5M{X97q6Di~;_VlgGaF zp=e~~_~k$q@KZU6;AJ!ga)GGNw1-kmL+N9c1N{K%`H)VwrTRFAu&Z&IN{~~T|Be9) z&lX;#GRxBnrXlQTC7#~8s_+&kEtr}|o`228z5@C!zyO&LHI}1~P^ka_002ovPDHLk FV1n~?p``!- delta 550 zcmV+>0@?kl2jc{gNPhwaNklmZ7rpoQhC zmuS_-Xw|BhXk|sTY8geFmMzVYz=A{ZBCqz_%sAGZ1BcPU8T8})=Uy4c z?2*a-o^1Kfisamxd9c37pjKF`d*}SH^!1!y`pH5Xw1|=eEPp?N46z2}04vX*FZV;c z+g>KLmfhIuK7sEAWQ)k64Zs(GBeIYKtX2Vz$U+LxtbrSqg}bz09!ZH07zzm z5w; zYMVq;rpW*ud)-ry~#l^5o{<4Ol7Kp@a&)w5`S-|^}{H)cM~{JKV&L_JI0I@ z1>j};M4wN@)ZDOH8p8}T_Nu74__1yXHk1hua>tg#EV{Fz1*ZbVN!6^U(QA5B)cj3x zB)!Suo!&Arh6!$iQjrtf3*2*}3b;ca4PT!7n){0Tg8QMHHAW;+jPNM8>ecCOK+Jtl o9t1%U)E{{f!P7bds}BJN0PaN1<=V>5KmY&$07*qoM6N<$g1b`wTmS$7 diff --git a/core/res/res/drawable/timepicker_down_normal.9.png b/core/res/res/drawable/timepicker_down_normal.9.png index a9463552ec68cd5f542a567d62535fb2c97b3a87..c427fc34831d97424ff18f83a39ea219fcadc812 100755 GIT binary patch delta 825 zcmV-91IGNO2J{AyNPhzsNklWHR|3`+rcaR)Ou_DwT==4&83| z9d>`9Ut|A|kI}d@W8E+E`8?BcFkP$#IG@j%kOSioK2!*cM8d`jWPnc|;5LOP8!K@C z01v&iVg<5s8N&)ZB?X$MxlkV~@Lw)=TYt6yIfR|>4H$L<8J-ITib4C>r9MZ1j^{uQ zVFq|SfLsTjP=6uaZnvRUt3kit-|75lGz!IH5i*&~(*x-99lpk{*XuAIk0FsrKrk5G zx~v!s2GD3UAe+s4Q-P641mf{H=(@i37ZwNvARG=uEEYTJbaPaIg+c*3oes=qvz-)g z7zU)%Y3~9|rBVw&%Ovs`b0BA7HZbU(NQeRMW*nz(6@Mu1iO|zoyp-GLT6otS(CZLoE^rJ`p0Iis%4;B3ljypnYHUl~>q>MS!kZLG zuST3b99KzXUFiO=e~Kpm2MKajEZYEFeieSdf3c+{AM=nG6|H>y4nmxFr@ve}nWtVEYmM6|adOMA&ciPbi$v*j}OEAe%cG z!h+}&{T2s&#gjtl?{Po^k6n1Ye3>DOD{Q}@e}BV6W3f;pW=jPMkk3hluZ0pxfiKXX zQK)-yNg`^w3Hkv2Cn--n1#lxk3b?8Q#lR8zH66R969qus!vOCndHf$dD$k1{Y$_$*vb7Xw+NLsvUjuuPjco<=SAYQkEX`s%QG;?100000NkvXXu0mjf Dk!*2R delta 746 zcmV1#o5XblU62Y=Xfud9tR)qLy>;^i^E)Xw3 zkq3wn&xG;-DR_a1B9TQyWjE-sWLc)OEX#rvd=x-tNzN>nz1!P`10OphjX=k-vVZ*N zW@lyz*^Vtp@N6r8v%$Icb2J)VE*3##;-49YK@y3?FL-;!UVo49Zl2HQe}5u`_y*63 z1s5Q_8R4z-pb&W<2?6R3(g7TXu&nx&LKp$AROqBcM+IUCuO|>GfT%!E3FHmn!oDAL z19<3AMM;AP(BMI0!&o=P@t}r6A^B$@hVe>~*3JY0DrR8mB*H>OfC?du0L6Pi1c(3; z;9&!FO5M7dQ-1=H0;ro3y;dYbfEdCG{XlCUhyYgrrQ2D%0NCwzNu$x&XpLH}Mhb<( z`vmBB7H+rOq*AGnWHPDr{lQ?cTqB>)`>I09La86tE zgi1sjAeM6Lk2Ix@H0}de3Uup8bB9VSMBVFPkpc}-7S>gTtn#F0B5p}Ur?I9r6W-`( zhi)entpC#v5&`aGA7}@s3q&?#t@qLZW#I)4u3MjvJr5&_z{s|M$et+);&V|7pdEHy}KKC*WVe%gtuK-fN-rrE7ltF&!Shd1BBe~T1I z?IZXF_&N9~_$N&tfv?~_@Eh=J@MkX}%qlSjPKUNfngSgEgZN@s9vT`N8k&0&!GW*` cR(}K-0Qk&!LZSv%6951J07*qoM6N<$g1v5A#Q*>R diff --git a/core/res/res/drawable/timepicker_down_pressed.9.png b/core/res/res/drawable/timepicker_down_pressed.9.png index fb4d817c48f0c5dbec38b5c5c43ab081c2c2f9ba..ac6ac53387e9be661d63854286199023ac5baaf5 100755 GIT binary patch delta 1428 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 P00000NkvXXu0mjfm-RhQ diff --git a/core/res/res/drawable/timepicker_down_selected.9.png b/core/res/res/drawable/timepicker_down_selected.9.png index 1db8bc1aacf8ca7cc2b9cc5a55c976cc3c69495a..f710b57968529cc9c1bca773d8986ff2e5aec475 100755 GIT binary patch delta 1404 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 QSpWb407*qoM6N<$g4BY*aR2}S delta 216 zcmV;}04M+C1DFDkNPhsjNklUWP0000^Qzb{PO?Imy@uF&=$qa+ngwtzb@Y7x&lCdao7I&tzUO; zxOxg_J{%rt97jSC9gj!a?;j{A;N$)6-akD1_2Sp7Q$9KpW`8oqoEC~s93-;I%PG=7 zzsXt)dNaVlr2`<(qys!CaH_x}nH9XMK#mrM0v83Q?rZ{_jwJNJ9AG6wIGvvWU@=6b z6QE2k2f)(88bcQY?hR!v5$R$M8!c544Il#a~v#~xzVBu1MT(NN80eRWG0${=- zaj>)%=nrOW<$p>GGplphX|w@Q2iO&3cwP}CDzc!yAT4YdQ@Ex;F4JJu!cbtw#0#r6 zg=Hpd*qjFm0H&fcl#G!xFWtfbSO7GhOS~D=XW=yeps0HaOKW8R`#Um|1gi>^waf#6 z7d=o{panp+Y=;6bh6pO_flG{OTNnylRbbn~###W>dU4?L&0O2UP~g{k;GC?*LV-HK zO9fVUB8V}4F{V01#5pKX-Ep`=f!K+B$4>K6cZ5(e|lp(=J~Yz=$8EBLd(6+JkR%+%f)=~eV;tf6A7{FI%?b2 zv^Sd#9S(=DpXSFDK-%qgv|g_%3_}BOArSur96n>~oj}Pc%naLi-l52rfd2c-dY6;C+zpnpX5-NQfuz5*Z{3)xhItHc9U zX25M{fb5F{JlMPVbXFQbHdunih{4jc0)(LuemHajZ=6(f5fTDIf{C*NPp1=|&u8Ng zWS_KDk2KVWWYfJ9z%0usO;g<^_u_awTJPT@D``uy6Ps@V1_0%dOHj3_0(JlZ002ov KPDHLkU;%=Y&g3-! diff --git a/core/res/res/drawable/timepicker_input_pressed.9.png b/core/res/res/drawable/timepicker_input_pressed.9.png index 30d8d5fa15af4797e0d4a1183ef4b35f9abb5814..c83b1eb4a4aed649bf0fd95b692633fa0de95639 100755 GIT binary patch delta 531 zcmV+u0_^?V1knVLNq_T6L_t(|+U%QAN&_(vhG()_D59?(K=1%wLGU6T%!>$K!2>8B zz*k?2EuBuv?sk(*wrRyh=|2!!Xu`5z|9@r@c3DJdj$r0_F4TqI7teBE0ifR8rGCHG zapT*?bGY*I>6Q@tSUkQ_P{4Y%e9(^%9iKYBoblI@fLD&CV}Fx|H>5vWfrz+N0OW!6 zXzt7F;w+)v-z{@tDWii5)SMVo_E2B~u?%pquK-|_#tJFT+v{Qrw*W|`((27cNe9)o zuy09)zH4x=C{2-L1-1fUJsYX8Fo&72aKs=mv21Lk;Z%VDXsOQvxZgkmUJnViQyImoPEDV5(#L=jX47_X$CjcD)l2b0-Vay2@cIU}&Bga=^an5A` zad;3E==$@(q5`F#2!N9SqhB%wHUMY>Y$_C3EFu6HwSO_w7KQ>3DsbAuPP=9RG;*MF zsj@H>cv=qZJ8Nm6KpSAJz~W8>ZA@JoQ!FCly`ew>z`!L@;1N3!04(oB!gF*Q7gLLA z1AwLQRg0m(695tb)&vv?3;zQPZ{EM*)gLJk0f4_1TzXGr?)N(Wd^#+=cd`{=0F2?@ VS-S8w`V0U7002ovPDHLkV1m)y>>>aF delta 542 zcmV+(0^$A91l$CWNq_!HL_t(|+U%E6P69CyhG*JB7Ko7eWU`0w3VH({^@RH94fF~= z_^3w^0vdy`9oy~-yRgC9?gMc;Nuk+5v-9QuXQl#waw?)xl(Z;zQ;A*+qj>i+2ObkH544?*BqiC@3Rv_u^J{w9Hj1)-8OM*o~kgW`h zDZ~L(eF?oxf@J1lVLYt*)L;<=5Ulc~kuoz2yRK<+j|XUqAByrYR{ZSjZgTHVfy@B9 z%TKTZi>3lg3x6{NXcbrl0Ms?=&c0?LI|Y`x>-ZXoj1?GaVMkKlJpoRzq*2SiYuZ3;y7zvO(5Bh%!tV&l9z*=wCYwZ@d8mJ2@ z^A-UBvG%9gd<{w>2+0qi&Hd~!Kx_pld)s~f{K|I5%k4)mK!K{C2IQzgT4f20Z~UdO gQDUDYwRtg70bifnoAB`(j`whUSmCcT41ZoFmX1vxUXcE11|s3o z0FVaKqp{By_ltyf{dQLhD=?Z=V5o`7Ip-WCm_pP64(U4@Ypq>y;WO2e=H+<|fEhH+ zTD>?a>!213u%^f!VAtTDn!H3ZYG473%5!20QyhsDP8dWcQX0!9LNJj+fuy8xK81wI z0GKf3x&lKFxPR*d0WeKrBGHGvuxkQ<3c#i|hI%7zn7k|#X=|jJEWw2}1yWfVn^G7G z3=Aw)U3ggiTCzJM0l-{=){Jaq;3cOp01B-f_1l3+;X}GGN5jYgV)Nj~NW1+&Re{_O z1i&i5tqYTpC6Pf$Hj-xM!O27OqzyOiz)@RZYq`m+E002ovPDHLk FV1ji(>bn2{ delta 454 zcmV;%0XhD{1cd~UNq?tFL_t(|+U(guPQx$|0Kj$PqMV{gNO=Iffjj(wV|f6t;>ZDx z`~aT81)dP1luL`^1xK>us3sUYh)TOFrM0Rw>P~m-RSIzUfrtFzgy*$Kyj!0G$3E88 z{nOXeh5MTHp85X5T7lsQ+`h3)8enUe4<|QJmL&)wNWmZ?bbnn3m#^0mfV+)d)^!b4 zRgnZNiUQzyGkcmJ@MAj)O9^?NLzZQv0F_ch?yf~}1)>_)8cqXJt3aKv&fT?$1~dn? z3S_{qT<8aU#UvL>fb0H)+9ERlV2NblcZ<4oQ zz<&UAwibP3vG045H&pfU(>Ch`6waHPrm=spPy=k+7C*}Qw1pQiUybY2+cUBw%CUY} wMO2_X;`uIV4wMDMgvM`fGb7vV$EN@T0CKp-*h;~hpa1{>07*qoM6N<$f`Kf|{Qv*} diff --git a/core/res/res/drawable/timepicker_up_disabled.9.png b/core/res/res/drawable/timepicker_up_disabled.9.png index 93d0db48326c46e91d8005326dfdcc4af480a660..1814bb4db00399fbfda86a8edff0d6275cde31c2 100755 GIT binary patch delta 1222 zcmV;%1UdVF1pWz-NPh&NNkl?Dq3|MEZg zocplhx-NUJ8HUmKN%-#>>;>($uf+gB{-geD&lAd)TsL#TIe%p9dVc^*$uPMm;oIBW zp9+P-=X^e2&Sta4R4T>b0G&uAhMSn<2r!mq34eHaXw+)8-_>e$cW-a+J3qwYZWBaO zAi+y-ZEby=nVH!&O|z8AWEdRq04|wK%4!`-0}tD_g#+N@<0Bxl`}_Mpl}hEy!NI`~ zepm|-`LS+FQhy)za~#-L{>2jBoSvR$D=RB3m&*x|fCzvDaTs6%7^x0h+6T1T+go;i ze$Fm0F9GviI-UN;zw*-yWryFtLjVz%Y3?RJ@I#}~U~6k@Y;$u{KqIFRmLU!!K=}Ch zxDXA*0|P{^%J+PC!c!nZnaK*w03e5#fqa*imKZ=1EPoZ?Fomq_vI?<mu&qXafk~u!XJ)QQi_b+T#7YyF0-Hj67BeRe>UjG@DHU4_^+0 zrb7~ul}UzZL}YsKl2q2o3KVr8Wgt1@>H<+!qP%UjT1;gn1N4h%k}UudtYHq{UJ6vh zTJ2P%I)9yr6gUcD#=3QPy8@IIr~^DTGxvhm6(DulbOjieNCpBZL(>i5AeQomf6S2r zUqFGnC6G=Wx+W0}Dss!k4dBViiRjSd;?XZ%U0sc52**`{*Vosg1COR;c6K(l>W?iz zRQ?!B8yg!F{m?fDFlxh4(!|6B%Vx8FO&Ujw^?&&MTNrzcEkJp2Q|gC~0QPHFS64o~ zv$M1K7Sd7v`0?>EySTUzE{7@h(f-lU8eZ@3@3UI1CdMks3Wb75H0$f@dIChI#X#la z;-W|zGQ@N`?az?S&(Div>-D-15btBsC+hHy6yW6Kq=1AhtIju50`W$H#Xd4J${PB- zSbr>vb7%_?P&PI;1SAO+@q zZf-909GEd1W#JHmve4cEVx>|Ul`(@F!WfBzGVuuDfQGQeJnX2Dey078^^32XMB;M6 zNE%p|f_e~HIIe$W+q|%4*@2~$QFY{}rhleHfsG7(dU_gJnML3%w8QQ{PMs8J#HGPr zUS9V9`Gtjr$gjt?Y*}b+3iOxp#yR6f3eXM!^i|lVz&K~TC{0<~(K(6Owxj2A@?HuA zK(~)1Vmmh9X&(jFX-ZR_%EW7j3(NJ^mCGtjD9=?GI1muuN*(rEr3;vVP0tW^uzzab z4XRGZqLg|y+pH9y)z*eheo#qO<0L8xK2$PELJOBUy07*qoM6N<$g7Y>^00000 delta 450 zcmV;z0X_cy34jEUNPhvMNklQvAJIN8c^eSG$1BjRK zDlU73;4WmNU8K+wEEG5PSuAKU?KGx#9RCLoOaehZ{`b#6;wZ{xs#L~TW4veiihc8& zLA{{9q1GqL=bieM`h`0G4ZtO}9fslBG|iQ!X}43PR}{q|O@GrT-}g84F{6Iw0az*S zK8m6T!!TADQj%Vt?>*0Zq{}V!q3NS)m->PrSOZ?e%ZNqAq@K)Hbpf1PmbC=7cGXPg zJOF39t}lSBT{V*#4?q>TPL|38i-8k=?1KXTK!E@VfB*=9Qvz6G74EkRGXOjv;FYL3 zFw3&*BuPH^}}hA8%qup0^k?C<7)(IY~|pA0EiLB2umGf22)@&s{B-O9N%?) zKXAkmOM#b&Cj&)7*L*WDq;AjTlZK!GwXA{b$e zu(%3r#*=}g%6MYTxe*5nga^U{p+G1Q3Y12Hcr&4=0y`NL2oDs>0|5{K0T2Ku0+0b< sPX)5F>^^tQ7{h_&MiHk@VSNZN019MTpB$GOBLDyZ07*qoM6N<$f)a|v`v3p{ diff --git a/core/res/res/drawable/timepicker_up_disabled_focused.9.png b/core/res/res/drawable/timepicker_up_disabled_focused.9.png index b5bf68d1b7c0877e374624b685b7a2655fc8f18b..9ad5b85c908ed2e76fdaa4a438b5205a90890aec 100755 GIT binary patch delta 1202 zcmV;j1Wo(Y1?mZqNPh&3NklUQG6-^B;G%lTBh`ZQV7q4?OH< zce6=;`+r_`cA_|rLvCt{qV#2x};>-w0gsss+uu~=-diP<&-W11%Oi;Ig|xm^BMDwS5&*494K zLrm%xhsYJk;c10J;mO3r#EM}UxkMsC;D85k@pxQR>p&WKSeC^c0GrJwAd+gedR#0P z-)wAbe4>Xn0DqAl>!^bIu%4p8-qJVb9;rXbGvzx;o&6*-TUDPVAGG^q-5ej+H0>ST zwCRSjO~qvMc*IhpZcum+Yqc7A?tCVxn%wYUU;q|Wfl%cGx@p*D#n_1oOaLH-mwPkQE&{kmo@xUv9o)EC7&(GZ>|)pMO)YivYO-b@xC*nwLAy&(9e! z?ry6vaCuK$0-U#WIaDeYmJ`9Kn*v!8sn_e505#HbvO$G+6->77azI)`WV-O;ysZ-z z$of8Bfw+kwJLnMoN)&H08jS|=vl0P%O*B^=H{QBPt3c8kiT;}kwbu#J14ABx_|WxF9O(SF1!&yneyM?nCcGy7?A=a1qP!)3@TDfg$>}&&JG&|feMnzBw1Kk z2q(a>D)8jwgd83ovJ^5kH5FR*hZZ0@|M~fOGBh;A?nCb^z@Q8Rxx>T5MAvn8HxyP2 z_4qvR0K#0nLJN?O%W;nYUek__jy!n#`}^T-V}FAD@a^qwa&U0KTntmJBmeQCHN0M5 zUnk{q`Esn%wM-_%3eDo;qMQIxX)#baJ3GsYh6qv9H17%7^z<}47Ng@FAhw^Kodq7= zfdU*E8DWr6W&O{ac>&>ryI4m>Mq9)8kByD7b4UviP?naK7$gxOl!o39A&Y(Kbeb53 z!GFS9G=N9=OA8R8$w7#Q+*T@;JoVw0E}PAEJV!2h!ZgR+qC0I^ssMs3V>4PlJJ z;eW^#0qoNdws;O3HPSb@eFCe%SU{8oR}wW+WicV4-u z!kF)W6$%an#Jkdm-B#-YCScPugl){)cUrH8jMLlNw%bmp2=*SV8>GwpK-s2t@PF{d z?`~CKfAa&S2gp_E|E+yjVLw1V!BV!|cLl&J?}eEHQHA%MQF2cyk;khA>06k3Ea~Pz zr%iz|zbyIeOjS>lJ$poYc)w_QC?zI4&01AD^?{e9X&HX;1w-iBsDt*plVh=wR$Q?u z?IG;8G5LI+oSvRa4UPZV5W{I(TPt5Vzm^bIy7fKR`Qx%Ag{5N)@>_rb00^mwyda}_ Q3;+NC07*qoM6N<$f*_nb)&Kwi delta 664 zcmV;J0%!f|3DgCUNPhx$NklZ=4*mU11S`^(#{ye`kj~mfa-UiX zTi3g6^GRPvc>p_aR|nU;a`+F>CH3#Ud9Q8$c#bWv^Z;efu?VJ9JpHSCL^rKg0V?0LUoL5&B{qH5QXQGBv;i*de_b(0!CX9{o7@h+q z@)kkPYD#4xi2;0n12|2oEQA131v7fGODLJA7QO@H0Qapp$v%Y@08Ba%00GeU02M=V zqyT6NklREkx^RKJupJy23WaKd!C;HJ_W6AG9*-wt$A1*&J<8EIJ4uUDNrPuxTRz34 zvJi40YG9T%Fg=A)1I=on1P5B+Ky=}}yD$LemBNx$-B&-V{G>o2(9YXm>=7rP%NV0l z*TSk%rIgqB$$>f+NZ~@Ka7i7grk@?IQE&%Z_0@=4yUgmBvF7>x{+rTRFo!0B6wY^$ z20-CCP=Dg4Fk~hP04)GW!O2wRlfwG(q}ZcMJ`R-a>cC7R4jhOk0)S{DNMSoS5qQwd zbKI8+Xi|m7!FK71#QI4b7BB1WN_1DU?B+5mE0IRom_G>L01j{ yWfz<$I7m}IKsQKk%Uotd@EJ0000z9*+|o@Bl6vjk?v^mIfZCX>td^hldA1q??MHKS4evdHJ`GVO#xH@ zB?Z{-Yu>*G&}sjq8nlHJomZHW*;^HerXsVXYy;ch->03O9o`+8nVF%<$;tOM2mXyt z^;>LXV}FCr&d&H;jBd!p#DoIaYUMvNGD0049ef=c^mtkZ7__00n@*=Gkw{2gQc0^o zQA(j2fWJEh20dV`J>CB900!NOK0iOF-rin5j^pEFX*=VAD)8XofL2#m>Gbr}Q@GGfVKLyK2j17$ zN6BQ8hcM>CpvTkf`E~okhGFunpa(oRH%BKYC%jY{7#IkAJO(NP`-xLC1!|&n2ztO+ zoxo)YWz#U-LaS3??HI2t0A(}RSs~An=YKi{hW$L?D^_OOvq{7>Eh*+e=@bZn_A8Qz zX_@Ro?FrW@kO|9vBP;*utrO6}|O!pk+6TV2ZeYty4Q6 zXsSfga1L}5$@6uf%EE8V!V2Jv0H0k8a|I#`tMh@4=0N+|m565rfJgumWB(3f}-ZBPCSLQ=0MfzL)a-}rlzLo^71m&(8P}o(M~%&{3ZB#LRf3IWNYPz i%OMHjhRcgT0t^7fYE1ygkI?P_0000 delta 1000 zcmV4(lhk+^Tz{Y?&bO{w|AOlJezv}1utjlqjvs3@#IO&Nq z*p~g_``*2KcL@ETHbc>CQGDjrYl_Wp8QnhW_CdFlqjaLJEY7$N(av%kmVcyRfhVEf<#EeQ5=ng2KWI6m?@+azVnzkqguCWCKaS5d}JN zVHM!<(imAFlDNlFA$Jg&F;hB~z~jwCRvjV>&j6yU&wpgW1*q^8C^JBt?}gGBmB0%U zV6)jo*VorZ|NQ(M6$*twA(}Bz3?PBW0`yaTjYb2Vo}OC$d_EtB#M&LeAl!CuZx3y5 zZd&~yDnlHQ&H)A$^CpuC8jr_TKd90g12I|v!PWp>Hc%f?Abds%APxh-ZnukecXzFR zNC1kLvw!>m2&u}=&CT5RTU%R3+Cmfv&v1EpiTeHi+_`6GXP%}w1fZil&@Tnv-`}H? zlM|Fmr53s|wC(L}R4SF`et&*`HtykNisJ?#rr~)B@ZjLU_#BN!uCCwM*f8$lb(jGb zt}4=AEAZ&(2-WNLcirRo_}J6+7pu zF6?|w#7lrLFE57i+F&q1iA2Ka4~Ik4>2v}sFi;%C*F=J@NW%c4X`0m!vI<0T2v-b@ z%2bZ35k@DG26!0bP|QS#IZmV(6;=Ic;J#!o4E>;tOM$M^ z7#=Vg*N0uDF*GbYXi*2sDvn(bW*E#VP~`y>fwwB#KJ4Cu!$2$sy7}iMX+k>_FlQ1i zjSDY1hZ_TxMU;8l9As0Xt3{=?t2%RG4q@vWD+mp!ZPH6Fbgr6 zh`De)9=A$JYklgZ?Ik2C{t(Xyu9$gtj`FTm=r00RIo W**D|- zW@p~co1J-in|*2Wk_`NKlYK8Q?|t(9&F?qAnI)Wa7_<>WGJoGh{5=9&*dFz>5Ckax zX#BG>Y8|!hwZ@RMnU2xthJQo6f|F($#Z z+ihv9tE;VMv-$hN!oro=+1ab&lD4o&L(~e?@JgpnojN@>Hg=_2tsW|u%YcUP5L^%h zrdoGpLmp8SNq<9t>+9)(sZ))1n&mWPJ=us<|8G?!ekSA5>%<_V+60xnVt%1!7tk;%!80-87 z4Gh=R;~q8HTW%aURLFNA#59mxWq8bR<*1tn*bOFdSYjQ3q0_OLW=P?q7kS0gYxT zGXw>2;WRe}LygoL=~6O`P?dkGE*DNfvt77|0Mo`mVjPK~$PMaHeg#qoxHN#YzyP)C zcz=p&eE_kjDB5sOp)d^^^#qX|+b@5LS^L6=vO4nefe+yMsVxKu4v;h>z_cg~E;sh6 zFK2*P?_Pv^_ioEF+O@U!;l<-0S9AA`9@*P{3jYBi`-DzcC}@Lb#XJlq0IjDChj zH}#(ckK#za^+9xBtbpfI1t)z9BV!Bu9z(dtJ$c3oaK?snPt$Tq%6T6KgDTK>L+$|z zn|}ybyMOt=8W#F)<;7h6%A$D#a^gM~)nkQF&=;DF%q2 zFD@>^&x;?!Nw~B(0gjA}NJtoE?e%6IKvWf2_Aw%3TBFa8j*iNEY-ih6fG^e0!|lW0 zN=PO^R2t@f=(2dOUav#7T9s){vVUe7z|)Jb>|KDzj|zj=dQThx`1Ix{vHEaf`|YWB z+&5`JK>)g<70Ev7?zdrJLFJ(`=jZ1Kzkfg31J46sTDgZivh|z+q8sCQhrvWDaVr42 zM8We)V>U`Mvn0|3G;~{BhsAL&mqeOpc&|+))?r`n`v?KXx7GU>^8nZ{#DC4WaL)s8 zB=vaim2Wj>e0&^+hliyL<5(D%p0-+ro_F?bMD1A@ZnvXk>Bm*M1*^XWbKzH?ybO28 zzmqO}cqy@=etMk z$XVA3?W$f3khtm&dXJmOU4M(TGr?Qx(lTU;^M!NZOWzgLy zO|2b7)EZV(2j?9SKzz?=4*OK??9|!?%%YP3$@NlyrRRGN> zT-2QjcA7%%G)6^Xghx?%?amko8S=m`K*5xjI=hUt3MD{L5P9-;)KQ_?$q;*TT+)Fj zmC6)2VXQ4|U5GNu7KLMgrA7xJDOmuCdnqs|z(B@RN^_F~IRIz<(kr&|BLyW;#-Z3LY)Tea`+hqp))(k}M{a9#>-^RRBZl3nJEN zKntco@9ac>X{4;37~f_tKG@G)64^;2ktRxPq}PR28Z$F90}meT zZHW5IhFDI!apNX%M-U;tI#)kmT;2=K_vP&W1sDJ;`phz%at;rf00000NkvXXu0mjf DVkAy> delta 1446 zcmV;X1zGyY4%`cnNPh)>Nkl& zprCjWlvzBec<|uCg9kw`d(ngE6;B>KIVW$P_T))$5Cjh{?y$(hs*CQTv+I0xC-r<) zm87fFmFWaG$#goyo32hK>8@Y?@1rU;0QY7in7?fvzjOOGJb&g`pKYD(LAKQevL%iX*NB|PMF?PTgz0EkW!YqIuMEeYn0jl_? z6}Z5gQlJtNMutrRfCA(Yv}pxK1tj0rN=|i;nIU_jM1RAkhysa1qdv+ikXl;IWBz+V z1|E5Z73dk)RW{-f=mJRAOA8c;S#W3_l_p-w5&(??N05R{gDbf~wnl;0Yn)_A^$|-d zkP>jwa9qYDMs9#K*G`KWHR9MPQD9gii9{ivH!?09g%&_?K%C!d&+W>#8j*h(krbSS z{oEvyt$&UMX>i8C1#n(#zd|+PBtYfDsD^Z2KEP}W63T_A0cP)8+lF>|5Xp>*Wv6f% zBS^b&XxulMOc;mMS^)0+(u0q;mv#H2tpf-iKdJ?w{X12rE~dj002!K$)u$6m199*2 zPit`D`K7ph2v0utYmKpS91l@-T?i1eBtVKJ8-HhDDI4+HjlmMEEPH92>Ksv`<#GJM zC}b?8f&ldlmW-{Tp>V`EFbXkk+xM~d$SBhRSy2TVaEUbnFqCoFF>PvcPD2=or2xuA zeX^OP8-)>s;kaEpKpb})J>{0g0eYzd8+75Dw}&uT>!$5ST{vb@cqC%SKdSJHe}A4Zl{*a zHLCoM+J|Mn3k#|ezFvJ#=in@zW%E7*cV@JPrQHo zjV)E`|rJDN|hU2s_ZrA!Z?1)DT)KM)t0v?t3r2{d%JMBw_DFm!~Fdd zEXpJiy|z$fo~J`*X1{GK-7wRon16$^Qb`1v9I6^j;M4;-tVw~5W?XBZ;$TdaaAD!| z2_3VrhJ;0nTCyHymIN^+n6OZTOwDu6VlFIv1CP{1 zm;_ji{}0KD?_A2EZ>+Eji=J{}mBNLY%EmfJ!6yYC#w**Hna?WhI$apuF5Kgw>8T}M zq*rGipYGenjoNZ AbpQYW diff --git a/core/res/res/drawable/timepicker_up_selected.9.png b/core/res/res/drawable/timepicker_up_selected.9.png index 5c94d0dfe5771c56fadb89080aff119bde3e00c3..549a7e575ed112d6781d7cdb1f58b2f12a669383 100755 GIT binary patch delta 1795 zcmV+e2mJW&3%3rCNPh;|Nkl|qv_v%Gh6e3EH5YU54z<3gsjgS};HX7aR$L#KOS6Q#R zs;9c9d!}cmXEU?A1&{8TsqK&7{$IV9Qtj9kjw`W=YJzGz_!)bLJ*)hY4lkc zwYJ)JT4TsLVawG&09+HMFbD1Q>C?~FYPFZD)#_}qSe$TO7tjzirF44}V@!haeP7zf z#zuX4dHL$yyLZpe&(B{FU3_7IhNu;&;dyg&b0;S!C(oD5X$Y{R)3iQ*U&ZaWVS!$v0kd!`(di!Bq{!jVz1gZlbj_h z^OAC9Cd9-vKtv)iL0Q0iqF%4V%X@!_$;Y%Il9CzYqSB;mqF1*)M& z366zZbDtUeM>c*FE(!q=tW2X*oH>&^HZjgq7ZG6s!|2t*#= za&E*|4S!LE2>lywS65f%n23xND{3oH29fpkbqSC(;t33=>LfHABVtMUOf zO|V&+03-b{7GkH4`ql|es?BKw5QZG24GvOLWPb%t2NelX<%dar=BAy`(E-D;6zHTV zk&GBXo&Zj(jx?3W+oeG508(PXb5h`?x$v;&fi^$`R%C(ER}kWU4**?TarQWvMTNtz zKocBG$sK(o09r?lMm+< zM5qNMNntj?zQ(|;?wd2f3$?f5*201;qkVJWU3iLqke>?^Ly1XgN*(}7(g%{Dx&Z;i z%ztKP2FAw5rsK<{R!~7cNT8mycu&-+^w_~(&l!MTK5!1|*RR9$^t22bCPdHkq8YNohY!oByt1+q z0mSd`-Ma_hPkji-**o32G204&ThPYG$0a0;vi5wl4j`%uEcY=YV_KtspO~1C$ACNc z?;h?ez!M8+Vd2CV5|RlJm4>+=x_>PGR;^Z{TrSJBCRVc);2*vG9Kik^3h?NI!hU@| z@wZP(A4lrLiS5__eIxlG`{BN}pIDZQ3LjbE#GnptZCkJ%|JW+nLMBJG3CB zCfO210v3p!U4nLFLReg_D~|;cHL+faTzFT3DGH25;dB>fxN4v80&9suj3>rRJ+WQ} zYkgoiO-aIqg3_om(s^0iFe;d|d6HY^1C48`oJbYZ-0+CfE&WYX+>Nx z=p+D4T3`t<{L9-Q<%xvivVEp32;X~Pe)cFFbu0)`I-W4MsX_@*DHHvCRMeL#A0(mr z3JPrdXs6!1i2ydFarTcHg%h7d zV#S12?*S+mTm{fjp?prHsk(}!RSBb_zz8U5J}OFpP1i+utDC;~`fsqp2uaEV!)PPi zbMD)Ubyi>5PHK8xGiE2TM4BkEkyaO0Y0T{GEG#W8?da4+zif!*v@2JB*8Jk@uF~pU l-MqNGBl5tMm$UyDU;wMO7x3#^_9g%T002ovPDHLkV1lH!UU~ok delta 1465 zcmV;q1xEU}4(|()NPh*9NklKOoDZ9o6oerbUGLr7?a zvS*kafBo}Y8GnF~2k_C&?%)L6-vfvlpi!WK*Fb*uA66j55;nWR3B!i%yLkXNg81$> z>__~?*eS5dO)x+eFsN|bCsvpTP{QCYK*RtO7j8O0k}Ss1u_*vhK)lcJ2F``20;J_H zNwGjdVgMR$LOV8v6sTh$ZQM8ZF>n^RWe<)x2c)n`6o0iStUyW1fJ;oLAW;sq6#zH^ z6I17e{Xwb>K&!sU15}<ra#TW|1Z4!t&#zdCGZdKP!Yo_G7c$Pfoa?sVY8Z@RYs!Kpnsd8A)UXtd3;&?NwB56%FL=hx9yw97k>z-uQvzTb!5#*d2! zmmF74h$R%50;ub8*{vfTSZm8+pXwM1rW;qW0wqTM+5md>VF`e8Oo27s_|9JgIQC#` z*r!AFD$u_`S>A;!1o-vs5H5V*o;ZG}E1`ExTjkj}q&2*GWgULon~W#tp5BMkhoeOS zEPoLLsd|8yetrO6+zR2Lj>tV9M=l5+J%DiL$+d~|zxOp?qYbAvcB=(QMMy2sFQ6S~Ju*gj!skwtH?U~a(mn{B;nQK&ipQ$zR5(>;tz*Nv4 zzjF=VdiCYpbDw;AaqRQkZ=B6{^B*qTk$+ZY0;I8J@q$St`vxj%@vZCD^4gvLK{yb& ziuQg?(EswI+U6KiLMpf>k{)=}H1nbqyC^0jk^0u9Gjn|f6$oRiAoYzzFzMHKA2=2Q zODJ#{JFy;;TC)N*`aUflVE*h(K?Nq0vEC-;tQXKip@%D~p-8>RMMLyUB>wMva$za1auMh!gJ4BmMgHyNd98>N4x)?#MGBgPT4to5h;P9A@4aLD15>Jq z#i@=`eM~rrGP5y)YiVf=$2VpzFc8JNT;hCneMa=DKK|M0#S9D!x5cAq5|M3t!)PFa z;$qSS@l{z5o|7$n>4eF$reqK@1b@q<@a7`^Wi;di>84{D8cy5RK}){32(u7V+dB+Q z28b45tAq;&OxuhC^ax-YSQZ(=smyHokfJY-2W*+DOVj%^JP}*&+ zZZ`;ye-Bq*bz>jcg$)nOq^JwaR$%Ks;S)(S$W0;10z$4vL@Oxn!a+y!@P(sa%ovHF z$w3g&0mLxZg)vuwK{v4Q%rdS_(&;3E%~GFvbpQY548%MIV$o>uf6Hg}w*UhGg`qTP Tu~cT;00000NkvXXu0mjf2)(p} diff --git a/core/res/res/drawable/title_bar.9.png b/core/res/res/drawable/title_bar.9.png new file mode 100644 index 0000000000000000000000000000000000000000..482d82e2f81dc9b260c937177886073272bfa1e9 GIT binary patch literal 4121 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 Xiz!7xK?$qg00000NkvXXu0mjf9OntW literal 0 HcmV?d00001 diff --git a/core/res/res/drawable/title_bar.xml b/core/res/res/drawable/title_bar.xml deleted file mode 100644 index 24402dc014430..0000000000000 --- a/core/res/res/drawable/title_bar.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - diff --git a/core/res/res/drawable/zoom_ring_overview_tab.9.png b/core/res/res/drawable/zoom_ring_overview_tab.9.png index d2658d89cb286d0e5c85c325eefbf956bcece404..4056f73a8e594dba85ad935dde3ca47f17f616ff 100644 GIT binary patch delta 818 zcmV-21I_$^4$TH3iBL{Q4GJ0x0000DNk~Le0000>0000e2nGNE0Jbg%9+4py3I729 z0RN!9r<0LD7k>iaNklBZete6OF7iHG(nn1m1XS;suZ3 zeP4KBDbBFzoR+z5(7!Dc=nMq*>rDa1XGKYj2;je+!rc=3Lip0&Bo~pdzL0_5qwBzya>) zRg*f+_kZnw`0W(%K!;Nrb7uW|nKzK2Y2H5OI2_Y;Ye6tB5P)ZTJ$HqOO`3oT|LM1Z$u*Pu( z6$KVm0ILV|gb+R3whw?(O2rbAHccn$`Q}gIVon>iofx{9&!f~9@#e2oYsfC4wtC>t@Y*5{_xw*N$va<4RX=!Pz zQmO3VUnSTLEyHdYRv4JAp#|V<9fA|wVd}@sTxSCv9RZ-Wepf;I5S@GgOz`(YM(}J! woHz)O{^Xe2Jpr`fS%vc~>y#Z2s!qh=H+e?oFfj%KjsO4v07*qoM6N<$f@O_vCIA2c delta 1773 zcmVZ;bV*G`2iXD|7ZwG{8uxJk00w|bL_t(&-tC)DOcPlg$G`KhEd!-Y zwfyUWg|MMW(1iy1v#f@aY?@6pn{e^uWi=*buX;7!x$TCe(UT_+#*1b{Hc?_U8)8y- z4OH39kOR@`Qzpu&JQD2s;lsma{ql?Xg(w+0f9?4UfkY0?-cNTL87B1DQM>p@0C>`xJ;O zWx}GCuzzXycs!w@p`jbGSnL^LRtG{K1eh$#a^=9lz%OlWZC&^7-TU+Q?c3u3RsgI5 zSO>5{4_wCU|@&u|#7`X`CG63$YSFg5Sx^(HshK7a~a=uJ>YWMnwnZ5aMu8&Z2Ph9ty{N#3I>B+ zPN!3*jqB^{2LU7j#6_kM0bIS@(u zZ*R@DYuEZ(T3XI1igI!E~P@?vCUWO{mfIz`}8 z$XSb<&bO-!(C!vx*8f9yy0-TAsh~$4Fm#bBuR38%|)Cd!Rz-g z=_Hv&u+0HkA4mh_1NRAoe6sW+YOd_eBOn-4* zxpJkctE(#z2n3q_et*N4aHy}Z|CI!<*ZTsN%_J5V7Z)ZcCtp8&`0($iPoK`DQmJ(Y zE}h9`871pGxD3Mr)wGERoMqy|4sn4|ro_yYBmhpY*DIetf4=s@g$r%X&CRD2Me(r_ z{%gUC`{~G>PN!U5U0qjQU0rwX+<&}_gls%md&?ceAszbMy1_3&~`1A(2SDd;IwETq>2?U;rByz<*ZtT8Fwd z5Q$!|*VW(OU)|KyROR>keU+7!zM7hv>JukUR5=`ulEaLa`{D}rV!E#Ds;aJKGMRN% zRnu#0Yaf=Emlx;e<`$QhmR6RQme!NWlpy+wHE9B!8*I;c&>3B$XbNA`jIS>{ZdSESHy+m6Z#E0G{U|iXuc& z1jlg@1Yujvaa*p{G)E>)taV3(=-@{0bSQ&7zRx9Xi{kY$TM{Ujpz9sJi1M5 z7OGtvp67G>cWP5`V0Qz3ugCJi_~Qg~Kid=>Sn59yx=lg5f=>aktG1hG9Su1n9cHEn{E-vJZi#S8RU;3zh=nI4%dp z8i;tF&mFUCYgeozpr94Y78aywn%nYJJ9ohj|9tViVm?6KNs*>$=G=i5ESVO6>(LPvjPKv zmd$22zI1`YK?bqioO{%!X&SrwC#P5yz{bqX%v3%-c56yySAX)wlF8)1*jgl*1DgS` z7KudetE!qVj^w?Ws;cQoByt~{3k5U4=J$A7^Ai&js}mCw|C~O3y2|Bp$&w^Fi`aIy zbUMBA_U+rm_3PJvd-Ukh6o6%Ht|QLS9F{IwbYpY1vfY0Vine{)Y7n2gL6o|R&DGp# z0BIV$vdqjOLpDy5u(iSjMY!AF1z>B%PL?oBV{2{Nu3?!)p4-!@&zf4NtU=qlmzFem6RtIr7}3C{r-Hu7PImy6>0X{ z@|vzIx!bqPtV?3#%y^OQk(rgv#mUKGXlUdZ^8f$$`Hj83y)(Nfzc%mS56j5P+vOY| w96xh*_w3Gzf~y2xEt$W+&Q2;Jo|#30p?2cWeKp00i_>zopr034=9RR910 diff --git a/core/res/res/drawable/zoom_ring_thumb_minus_arrow.png b/core/res/res/drawable/zoom_ring_thumb_minus_arrow.png index abe1b8a5de5a65f6414019ddf22d5185300670b2..c7b87efe714e0dfa9a230ef8a76d9df6036e3593 100644 GIT binary patch delta 2865 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 P00000NkvXXu0mjfq+g1$ diff --git a/core/res/res/drawable/zoom_ring_thumb_plus_arrow.png b/core/res/res/drawable/zoom_ring_thumb_plus_arrow.png index d01ccb4342ab31915ada8ac91568e028b5b85071..0591d397c14368bc666acb8b2fa796cb072ec3fe 100644 GIT binary patch literal 3231 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 diff --git a/core/res/res/drawable/zoom_ring_track.png b/core/res/res/drawable/zoom_ring_track.png index 1d5a44cd8bcc6ee852c652bdb3327c5aeffc61b8..60a15b7aded0f249e00437e4371f120c9d81471c 100644 GIT binary patch literal 16980 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 SHNYc<7(8A5T-G@yGywn=GTfg4 diff --git a/core/res/res/layout/alert_dialog_simple_text.xml b/core/res/res/layout/alert_dialog_simple_text.xml deleted file mode 100644 index ab82be7f74190..0000000000000 --- a/core/res/res/layout/alert_dialog_simple_text.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - diff --git a/core/res/res/layout/global_actions_item.xml b/core/res/res/layout/global_actions_item.xml index 63bb0f457d3f1..43831276e9105 100644 --- a/core/res/res/layout/global_actions_item.xml +++ b/core/res/res/layout/global_actions_item.xml @@ -14,48 +14,38 @@ limitations under the License. --> - - - - - - - android:layout_toRightOf="@id/icon" - android:layout_alignParentRight="true" - android:layout_alignParentTop="true" - android:layout_above="@id/status" - android:layout_alignWithParentIfMissing="true" - android:gravity="center_vertical" - android:textAppearance="?android:attr/textAppearanceLargeInverse" - /> + + + - + diff --git a/core/res/res/layout/input_method_extract_view.xml b/core/res/res/layout/input_method_extract_view.xml index 13b619a6c1c94..3f68bd3d27f54 100644 --- a/core/res/res/layout/input_method_extract_view.xml +++ b/core/res/res/layout/input_method_extract_view.xml @@ -18,38 +18,13 @@ */ --> - - - - - - - -