OSDN Git Service

Merge "Don't crash legacy apps with revoked "Draw over apps access"" into nyc-dev
authorSvetoslav Ganov <svetoslavganov@google.com>
Sat, 5 Mar 2016 01:25:32 +0000 (01:25 +0000)
committerAndroid (Google) Code Review <android-gerrit@google.com>
Sat, 5 Mar 2016 01:25:33 +0000 (01:25 +0000)
892 files changed:
Android.mk
CleanSpec.mk
api/current.txt
api/removed.txt
api/system-current.txt
api/system-removed.txt
api/test-current.txt
api/test-removed.txt
cmds/am/src/com/android/commands/am/Am.java
cmds/uiautomator/library/testrunner-src/com/android/uiautomator/core/UiAutomationShellWrapper.java
core/java/android/accessibilityservice/AccessibilityService.java
core/java/android/animation/AnimatorInflater.java
core/java/android/animation/ValueAnimator.java
core/java/android/app/Activity.java
core/java/android/app/ActivityManager.java
core/java/android/app/ActivityManagerNative.java
core/java/android/app/ActivityThread.java
core/java/android/app/AlarmManager.java
core/java/android/app/AppOpsManager.java
core/java/android/app/ApplicationLoaders.java
core/java/android/app/ApplicationPackageManager.java
core/java/android/app/ApplicationThreadNative.java
core/java/android/app/AutomaticZenRule.java
core/java/android/app/BackStackRecord.java
core/java/android/app/ContextImpl.java
core/java/android/app/Fragment.java
core/java/android/app/FragmentManager.java
core/java/android/app/IActivityManager.java
core/java/android/app/IApplicationThread.java
core/java/android/app/INotificationManager.aidl
core/java/android/app/LoadedApk.java
core/java/android/app/LocalActivityManager.java
core/java/android/app/NotificationManager.java
core/java/android/app/ResourcesManager.java
core/java/android/app/SearchManager.java
core/java/android/app/StatusBarManager.java
core/java/android/app/SystemServiceRegistry.java
core/java/android/app/UiModeManager.java
core/java/android/app/WallpaperManager.java
core/java/android/app/admin/DevicePolicyManager.java
core/java/android/app/admin/DevicePolicyManagerInternal.java
core/java/android/auditing/SecurityLog.java
core/java/android/bluetooth/OobData.java
core/java/android/content/pm/ContainerEncryptionParams.java [deleted file]
core/java/android/content/pm/IPackageManager.aidl
core/java/android/content/pm/PackageInstaller.java
core/java/android/content/pm/PackageItemInfo.java
core/java/android/content/pm/PackageManager.java
core/java/android/content/pm/PackageManagerInternal.java
core/java/android/content/pm/PackageParser.java
core/java/android/content/pm/VerificationParams.aidl [deleted file]
core/java/android/content/res/ConfigurationBoundResourceCache.java
core/java/android/content/res/DrawableCache.java
core/java/android/content/res/Resources.java
core/java/android/content/res/ResourcesImpl.java [new file with mode: 0644]
core/java/android/content/res/TypedArray.java
core/java/android/hardware/ConsumerIrManager.java
core/java/android/hardware/ICameraService.aidl [deleted file]
core/java/android/hardware/SensorEventListener.java
core/java/android/hardware/SensorManager.java
core/java/android/hardware/SerialManager.java
core/java/android/hardware/camera2/CameraAccessException.java
core/java/android/hardware/camera2/CameraManager.java
core/java/android/hardware/camera2/DngCreator.java
core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl [deleted file]
core/java/android/hardware/camera2/ICameraDeviceUser.aidl [deleted file]
core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl [deleted file]
core/java/android/hardware/camera2/impl/CameraMetadataNative.java
core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl [deleted file]
core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java [new file with mode: 0644]
core/java/android/hardware/camera2/legacy/BurstHolder.java
core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java
core/java/android/hardware/camera2/legacy/LegacyExceptionUtils.java
core/java/android/hardware/camera2/legacy/RequestQueue.java
core/java/android/hardware/camera2/legacy/RequestThreadManager.java
core/java/android/hardware/camera2/legacy/SurfaceTextureRenderer.java
core/java/android/hardware/camera2/params/OutputConfiguration.java
core/java/android/hardware/camera2/params/VendorTagDescriptor.java [new file with mode: 0644]
core/java/android/hardware/camera2/utils/BinderHolder.aidl [deleted file]
core/java/android/hardware/camera2/utils/BinderHolder.java [deleted file]
core/java/android/hardware/camera2/utils/CameraBinderDecorator.java [deleted file]
core/java/android/hardware/camera2/utils/CameraRuntimeException.java [deleted file]
core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java [deleted file]
core/java/android/hardware/camera2/utils/Decorator.java [deleted file]
core/java/android/hardware/camera2/utils/LongParcelable.aidl [deleted file]
core/java/android/hardware/camera2/utils/SubmitInfo.java [new file with mode: 0644]
core/java/android/hardware/fingerprint/FingerprintManager.java
core/java/android/hardware/hdmi/HdmiControlManager.java
core/java/android/hardware/input/InputManager.java
core/java/android/hardware/soundtrigger/SoundTrigger.java
core/java/android/net/ConnectivityManager.java
core/java/android/net/ConnectivityMetricsEvent.java
core/java/android/net/DataUsageRequest.java
core/java/android/net/EthernetManager.java
core/java/android/net/NetworkAgent.java
core/java/android/net/NetworkMisc.java
core/java/android/net/NetworkPolicyManager.java
core/java/android/net/NetworkScoreManager.java
core/java/android/net/NetworkUtils.java
core/java/android/net/nsd/NsdManager.java
core/java/android/os/BatteryManager.java
core/java/android/os/Debug.java
core/java/android/os/Environment.java
core/java/android/os/HardwarePropertiesManager.java
core/java/android/os/PowerManager.java
core/java/android/os/Process.java
core/java/android/os/ServiceSpecificException.java
core/java/android/os/UserManager.java
core/java/android/os/storage/StorageVolume.java
core/java/android/os/storage/VolumeInfo.java
core/java/android/provider/BlockedNumberContract.java
core/java/android/provider/ContactsContract.java
core/java/android/provider/DocumentsContract.java
core/java/android/provider/Settings.java
core/java/android/service/carrier/CarrierMessagingService.java
core/java/android/service/carrier/ICarrierMessagingCallback.aidl
core/java/android/service/notification/NotificationAssistantService.java
core/java/android/service/notification/NotificationListenerService.java
core/java/android/service/notification/ZenModeConfig.aidl
core/java/android/service/notification/ZenModeConfig.java
core/java/android/text/method/BaseKeyListener.java
core/java/android/text/util/Linkify.java
core/java/android/util/ArrayMap.java
core/java/android/util/ArraySet.java
core/java/android/util/LocaleList.java
core/java/android/util/Patterns.java
core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java
core/java/android/view/IWindowManager.aidl
core/java/android/view/SurfaceControl.java
core/java/android/view/View.java
core/java/android/view/ViewRootImpl.java
core/java/android/view/inputmethod/InputConnectionWrapper.java
core/java/android/view/inputmethod/InputMethodManager.java
core/java/android/widget/AbsListView.java
core/java/android/widget/DatePicker.java
core/java/android/widget/DatePickerCalendarDelegate.java
core/java/android/widget/DatePickerSpinnerDelegate.java [new file with mode: 0644]
core/java/android/widget/EditText.java
core/java/android/widget/Editor.java
core/java/android/widget/PopupWindow.java
core/java/android/widget/ProgressBar.java
core/java/android/widget/TextView.java
core/java/android/widget/TimePicker.java
core/java/android/widget/TimePickerClockDelegate.java
core/java/android/widget/TimePickerSpinnerDelegate.java
core/java/com/android/internal/app/LocaleHelper.java
core/java/com/android/internal/app/LocalePickerWithRegion.java
core/java/com/android/internal/app/LocaleStore.java
core/java/com/android/internal/app/SuggestedLocaleAdapter.java
core/java/com/android/internal/inputmethod/InputMethodUtils.java
core/java/com/android/internal/os/BatteryStatsHelper.java
core/java/com/android/internal/os/ZygoteInit.java
core/java/com/android/internal/util/WakeupMessage.java
core/java/com/android/internal/widget/ImageFloatingTextView.java
core/java/com/android/internal/widget/LockPatternUtils.java
core/java/com/android/server/net/NetworkPinner.java [new file with mode: 0644]
core/jni/Android.mk
core/jni/AndroidRuntime.cpp
core/jni/android/graphics/BitmapFactory.cpp
core/jni/android/graphics/Utils.cpp
core/jni/android/graphics/Utils.h
core/jni/android_app_Activity.cpp [new file with mode: 0644]
core/jni/android_hardware_camera2_CameraMetadata.cpp
core/jni/android_hardware_camera2_DngCreator.cpp
core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
core/jni/android_media_AudioSystem.cpp
core/jni/android_net_NetUtils.cpp
core/jni/android_opengl_GLES30.cpp
core/jni/android_os_Debug.cpp
core/jni/android_view_Surface.cpp
core/jni/android_view_SurfaceControl.cpp
core/res/AndroidManifest.xml
core/res/res/drawable-nodpi/default_wallpaper.jpg [deleted file]
core/res/res/drawable-nodpi/default_wallpaper.png [new file with mode: 0644]
core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg [deleted file]
core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png [new file with mode: 0644]
core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg [deleted file]
core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png [new file with mode: 0644]
core/res/res/drawable/work_widget_mask_view_background.xml [deleted file]
core/res/res/layout/notification_template_material_big_text.xml
core/res/res/layout/notification_template_text.xml
core/res/res/layout/text_edit_suggestion_container_material.xml
core/res/res/layout/work_widget_mask_view.xml
core/res/res/values-b+sr+Latn/strings.xml
core/res/res/values-eu-rES/strings.xml
core/res/res/values-h426dp-port/integers.xml [moved from core/java/android/view/Surface.aidl with 54% similarity]
core/res/res/values-ky-rKG/strings.xml
core/res/res/values-lt/strings.xml
core/res/res/values-ms-rMY/strings.xml
core/res/res/values-sr/strings.xml
core/res/res/values-w426dp-land/integers.xml [new file with mode: 0644]
core/res/res/values-zh-rCN/strings.xml
core/res/res/values/attrs.xml
core/res/res/values/config.xml
core/res/res/values/integers.xml
core/res/res/values/strings.xml
core/res/res/values/styles_material.xml
core/res/res/values/symbols.xml
core/res/res/values/themes_device_defaults.xml
core/res/res/values/themes_micro.xml
core/tests/coretests/src/android/animation/ValueAnimatorTests.java
core/tests/coretests/src/android/content/pm/ContainerEncryptionParamsTest.java [deleted file]
core/tests/coretests/src/android/content/res/ConfigurationBoundResourceCacheTest.java
core/tests/coretests/src/android/text/method/ForwardDeleteTest.java [new file with mode: 0644]
core/tests/coretests/src/android/util/PatternsTest.java
core/tests/coretests/src/com/android/internal/inputmethod/InputMethodUtilsTest.java
data/keyboards/qwerty2.kcm
docs/html/guide/topics/sensors/sensors_overview.jd
graphics/java/android/graphics/Canvas.java
graphics/java/android/graphics/Paint.java
graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
include/androidfw/ResourceTypes.h
keystore/java/android/security/Credentials.java
keystore/java/android/security/KeyChain.java
keystore/java/android/security/KeyStore.java
keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
libs/androidfw/ResourceTypes.cpp
libs/androidfw/tests/ConfigLocale_test.cpp
libs/hwui/Android.mk
libs/hwui/AnimatorManager.cpp
libs/hwui/BakedOpDispatcher.cpp
libs/hwui/BakedOpRenderer.cpp
libs/hwui/BakedOpRenderer.h
libs/hwui/BakedOpState.cpp
libs/hwui/BakedOpState.h
libs/hwui/ClipArea.cpp
libs/hwui/FrameBuilder.cpp
libs/hwui/FrameInfoVisualizer.cpp
libs/hwui/FrameInfoVisualizer.h
libs/hwui/LayerBuilder.cpp
libs/hwui/LayerRenderer.cpp
libs/hwui/Matrix.cpp
libs/hwui/OpenGLRenderer.cpp
libs/hwui/RecordingCanvas.cpp
libs/hwui/Snapshot.cpp
libs/hwui/Snapshot.h
libs/hwui/renderthread/CanvasContext.cpp
libs/hwui/tests/unit/ClipAreaTests.cpp
libs/hwui/tests/unit/FrameBuilderTests.cpp
libs/hwui/tests/unit/MatrixTests.cpp [new file with mode: 0644]
libs/hwui/tests/unit/RecordingCanvasTests.cpp
location/java/android/location/GnssClock.java
location/java/android/location/GnssMeasurement.java
location/java/android/location/GnssMeasurementsEvent.java
location/java/android/location/GnssNavigationMessage.java
location/java/android/location/GnssNavigationMessageEvent.java
location/java/android/location/GnssStatus.java
location/java/android/location/GnssStatusCallback.java
location/java/android/location/GpsStatus.java
location/java/android/location/IGnssStatusListener.aidl
location/java/android/location/LocationManager.java
location/tests/locationtests/src/android/location/GpsStatusTest.java
media/java/android/media/AudioFormat.java
media/java/android/media/AudioManager.java
media/java/android/media/AudioRecordConfiguration.java
media/java/android/media/AudioSystem.java
media/java/android/media/AudioTrack.java
media/java/android/media/IRecordingConfigDispatcher.aidl
media/java/android/media/MediaCodec.java
media/java/android/media/MediaCodecInfo.java
media/java/android/media/MediaFormat.java
media/java/android/media/MediaMetadata.java
media/java/android/media/MediaMuxer.java
media/java/android/media/MediaPlayer.java
media/java/android/media/MediaRouter.java
media/java/android/media/Rating.java
media/java/android/media/VolumeProvider.java
media/java/android/media/browse/MediaBrowser.java
media/java/android/media/midi/MidiManager.java
media/java/android/media/session/MediaSession.java
media/java/android/media/session/PlaybackState.java
media/java/android/media/soundtrigger/SoundTriggerManager.java
media/java/android/media/tv/ITvInputClient.aidl
media/java/android/media/tv/ITvInputSessionCallback.aidl
media/java/android/media/tv/TvInputInfo.java
media/java/android/media/tv/TvInputManager.java
media/java/android/media/tv/TvInputService.java
media/java/android/media/tv/TvRecordingClient.java
media/java/android/mtp/MtpDatabase.java
media/java/android/service/media/MediaBrowserService.java
media/jni/Android.mk
media/jni/android_media_MediaCodec.cpp
media/jni/android_media_MediaDataSource.cpp
media/jni/android_media_MediaRecorder.cpp
media/jni/android_mtp_MtpDatabase.cpp
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/MediaFrameworkUnitTestRunner.java
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTest.java
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraBinderTestUtils.java
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/integration/CameraDeviceBinderTest.java
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java [deleted file]
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java [deleted file]
media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java [deleted file]
opengl/java/android/opengl/GLES30.java
packages/DocumentsUI/Android.mk
packages/DocumentsUI/perf-tests/Android.mk [new file with mode: 0644]
packages/DocumentsUI/perf-tests/AndroidManifest.xml [new file with mode: 0644]
packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java [new file with mode: 0644]
packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java [new file with mode: 0644]
packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow_down.xml [new file with mode: 0644]
packages/DocumentsUI/res/drawable/ic_sd_storage.xml
packages/DocumentsUI/res/drawable/ic_usb_storage.xml [moved from packages/SystemUI/res/drawable/ic_info.xml with 55% similarity]
packages/DocumentsUI/res/layout/dialog_delete_confirmation.xml [new file with mode: 0644]
packages/DocumentsUI/res/layout/drawer_layout.xml
packages/DocumentsUI/res/layout/fixed_layout.xml
packages/DocumentsUI/res/layout/item_doc_list.xml
packages/DocumentsUI/res/layout/item_root.xml
packages/DocumentsUI/res/layout/item_subdir.xml
packages/DocumentsUI/res/layout/item_subdir_title.xml
packages/DocumentsUI/res/layout/single_pane_layout.xml
packages/DocumentsUI/res/menu/activity.xml
packages/DocumentsUI/res/values-af/strings.xml
packages/DocumentsUI/res/values-am/strings.xml
packages/DocumentsUI/res/values-b+sr+Latn/strings.xml
packages/DocumentsUI/res/values-bg/strings.xml
packages/DocumentsUI/res/values-bs-rBA/strings.xml
packages/DocumentsUI/res/values-ca/strings.xml
packages/DocumentsUI/res/values-cs/strings.xml
packages/DocumentsUI/res/values-da/strings.xml
packages/DocumentsUI/res/values-de/strings.xml
packages/DocumentsUI/res/values-el/strings.xml
packages/DocumentsUI/res/values-es-rUS/strings.xml
packages/DocumentsUI/res/values-es/strings.xml
packages/DocumentsUI/res/values-eu-rES/strings.xml
packages/DocumentsUI/res/values-fi/strings.xml
packages/DocumentsUI/res/values-fr-rCA/strings.xml
packages/DocumentsUI/res/values-fr/strings.xml
packages/DocumentsUI/res/values-gl-rES/strings.xml
packages/DocumentsUI/res/values-hy-rAM/strings.xml
packages/DocumentsUI/res/values-in/strings.xml
packages/DocumentsUI/res/values-is-rIS/strings.xml
packages/DocumentsUI/res/values-it/strings.xml
packages/DocumentsUI/res/values-iw/strings.xml
packages/DocumentsUI/res/values-ja/strings.xml
packages/DocumentsUI/res/values-ka-rGE/strings.xml
packages/DocumentsUI/res/values-kk-rKZ/strings.xml
packages/DocumentsUI/res/values-ky-rKG/strings.xml
packages/DocumentsUI/res/values-lt/strings.xml
packages/DocumentsUI/res/values-lv/strings.xml
packages/DocumentsUI/res/values-mn-rMN/strings.xml
packages/DocumentsUI/res/values-mr-rIN/strings.xml
packages/DocumentsUI/res/values-ms-rMY/strings.xml
packages/DocumentsUI/res/values-nb/strings.xml
packages/DocumentsUI/res/values-pl/strings.xml
packages/DocumentsUI/res/values-pt-rBR/strings.xml
packages/DocumentsUI/res/values-pt-rPT/strings.xml
packages/DocumentsUI/res/values-pt/strings.xml
packages/DocumentsUI/res/values-ro/strings.xml
packages/DocumentsUI/res/values-ru/strings.xml
packages/DocumentsUI/res/values-sk/strings.xml
packages/DocumentsUI/res/values-sr/strings.xml
packages/DocumentsUI/res/values-sv/strings.xml
packages/DocumentsUI/res/values-sw720dp/dimens.xml
packages/DocumentsUI/res/values-th/strings.xml
packages/DocumentsUI/res/values-tl/strings.xml
packages/DocumentsUI/res/values-tr/strings.xml
packages/DocumentsUI/res/values-uk/strings.xml
packages/DocumentsUI/res/values-ur-rPK/strings.xml
packages/DocumentsUI/res/values-uz-rUZ/strings.xml
packages/DocumentsUI/res/values-zh-rCN/strings.xml
packages/DocumentsUI/res/values-zh-rHK/strings.xml
packages/DocumentsUI/res/values-zh-rTW/strings.xml
packages/DocumentsUI/res/values-zu/strings.xml
packages/DocumentsUI/res/values/strings.xml
packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
packages/DocumentsUI/src/com/android/documentsui/DirectoryResult.java
packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
packages/DocumentsUI/src/com/android/documentsui/DownloadsActivity.java
packages/DocumentsUI/src/com/android/documentsui/DrawerController.java
packages/DocumentsUI/src/com/android/documentsui/EventListener.java [new file with mode: 0644]
packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
packages/DocumentsUI/src/com/android/documentsui/LocalPreferences.java
packages/DocumentsUI/src/com/android/documentsui/Metrics.java
packages/DocumentsUI/src/com/android/documentsui/NavigationView.java
packages/DocumentsUI/src/com/android/documentsui/OpenExternalDirectoryActivity.java
packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
packages/DocumentsUI/src/com/android/documentsui/ProviderExecutor.java
packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
packages/DocumentsUI/src/com/android/documentsui/SearchViewManager.java
packages/DocumentsUI/src/com/android/documentsui/Shared.java
packages/DocumentsUI/src/com/android/documentsui/Snackbars.java
packages/DocumentsUI/src/com/android/documentsui/State.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentHolder.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDirectoryHolder.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/GridDocumentHolder.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/ListDocumentHolder.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/RenameDocumentFragment.java
packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
packages/DocumentsUI/src/com/android/documentsui/services/CopyJob.java
packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
packages/DocumentsUI/src/com/android/documentsui/services/Job.java
packages/DocumentsUI/src/com/android/documentsui/services/MoveJob.java
packages/DocumentsUI/tests/src/com/android/documentsui/ActivityTest.java
packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
packages/DocumentsUI/tests/src/com/android/documentsui/bots/UiBot.java
packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
packages/Keyguard/src/com/android/keyguard/KeyguardSecurityContainer.java
packages/MtpDocumentsProvider/src/com/android/mtp/MtpDocumentsProvider.java
packages/MtpDocumentsProvider/src/com/android/mtp/RootScanner.java
packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
packages/SettingsLib/res/drawable/ic_info.xml [new file with mode: 0644]
packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml [deleted file]
packages/SettingsLib/res/layout/restricted_icon.xml [new file with mode: 0644]
packages/SettingsLib/res/layout/restricted_switch_widget.xml [new file with mode: 0644]
packages/SettingsLib/res/values-es/strings.xml
packages/SettingsLib/res/values-fa/strings.xml
packages/SettingsLib/res/values-ky-rKG/strings.xml
packages/SettingsLib/res/values-ta-rIN/strings.xml
packages/SettingsLib/res/values-zh-rCN/strings.xml
packages/SettingsLib/res/values/dimens.xml
packages/SettingsLib/res/values/strings.xml
packages/SettingsLib/src/com/android/settingslib/RestrictedDropDownPreference.java
packages/SettingsLib/src/com/android/settingslib/RestrictedLockImageSpan.java
packages/SettingsLib/src/com/android/settingslib/RestrictedLockUtils.java
packages/SettingsLib/src/com/android/settingslib/RestrictedPreference.java
packages/SettingsLib/src/com/android/settingslib/RestrictedPreferenceHelper.java
packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
packages/SettingsLib/src/com/android/settingslib/SuggestionParser.java
packages/SettingsLib/src/com/android/settingslib/drawer/SettingsDrawerActivity.java
packages/SettingsLib/src/com/android/settingslib/drawer/TileUtils.java
packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
packages/Shell/res/layout/dialog_bugreport_info.xml
packages/Shell/res/values-af/strings.xml
packages/Shell/res/values-am/strings.xml
packages/Shell/res/values-ar/strings.xml
packages/Shell/res/values-az-rAZ/strings.xml
packages/Shell/res/values-b+sr+Latn/strings.xml
packages/Shell/res/values-bg/strings.xml
packages/Shell/res/values-bn-rBD/strings.xml
packages/Shell/res/values-bs-rBA/strings.xml
packages/Shell/res/values-ca/strings.xml
packages/Shell/res/values-cs/strings.xml
packages/Shell/res/values-da/strings.xml
packages/Shell/res/values-de/strings.xml
packages/Shell/res/values-el/strings.xml
packages/Shell/res/values-en-rAU/strings.xml
packages/Shell/res/values-en-rGB/strings.xml
packages/Shell/res/values-en-rIN/strings.xml
packages/Shell/res/values-es-rUS/strings.xml
packages/Shell/res/values-es/strings.xml
packages/Shell/res/values-et-rEE/strings.xml
packages/Shell/res/values-eu-rES/strings.xml
packages/Shell/res/values-fa/strings.xml
packages/Shell/res/values-fi/strings.xml
packages/Shell/res/values-fr-rCA/strings.xml
packages/Shell/res/values-fr/strings.xml
packages/Shell/res/values-gl-rES/strings.xml
packages/Shell/res/values-gu-rIN/strings.xml
packages/Shell/res/values-hi/strings.xml
packages/Shell/res/values-hr/strings.xml
packages/Shell/res/values-hu/strings.xml
packages/Shell/res/values-hy-rAM/strings.xml
packages/Shell/res/values-in/strings.xml
packages/Shell/res/values-is-rIS/strings.xml
packages/Shell/res/values-it/strings.xml
packages/Shell/res/values-iw/strings.xml
packages/Shell/res/values-ja/strings.xml
packages/Shell/res/values-ka-rGE/strings.xml
packages/Shell/res/values-kk-rKZ/strings.xml
packages/Shell/res/values-km-rKH/strings.xml
packages/Shell/res/values-kn-rIN/strings.xml
packages/Shell/res/values-ko/strings.xml
packages/Shell/res/values-ky-rKG/strings.xml
packages/Shell/res/values-lo-rLA/strings.xml
packages/Shell/res/values-lt/strings.xml
packages/Shell/res/values-lv/strings.xml
packages/Shell/res/values-mk-rMK/strings.xml
packages/Shell/res/values-ml-rIN/strings.xml
packages/Shell/res/values-mn-rMN/strings.xml
packages/Shell/res/values-mr-rIN/strings.xml
packages/Shell/res/values-ms-rMY/strings.xml
packages/Shell/res/values-my-rMM/strings.xml
packages/Shell/res/values-nb/strings.xml
packages/Shell/res/values-ne-rNP/strings.xml
packages/Shell/res/values-nl/strings.xml
packages/Shell/res/values-pa-rIN/strings.xml
packages/Shell/res/values-pl/strings.xml
packages/Shell/res/values-pt-rBR/strings.xml
packages/Shell/res/values-pt-rPT/strings.xml
packages/Shell/res/values-pt/strings.xml
packages/Shell/res/values-ro/strings.xml
packages/Shell/res/values-ru/strings.xml
packages/Shell/res/values-si-rLK/strings.xml
packages/Shell/res/values-sk/strings.xml
packages/Shell/res/values-sl/strings.xml
packages/Shell/res/values-sq-rAL/strings.xml
packages/Shell/res/values-sr/strings.xml
packages/Shell/res/values-sv/strings.xml
packages/Shell/res/values-sw/strings.xml
packages/Shell/res/values-ta-rIN/strings.xml
packages/Shell/res/values-te-rIN/strings.xml
packages/Shell/res/values-th/strings.xml
packages/Shell/res/values-tl/strings.xml
packages/Shell/res/values-tr/strings.xml
packages/Shell/res/values-uk/strings.xml
packages/Shell/res/values-ur-rPK/strings.xml
packages/Shell/res/values-uz-rUZ/strings.xml
packages/Shell/res/values-vi/strings.xml
packages/Shell/res/values-zh-rCN/strings.xml
packages/Shell/res/values-zh-rHK/strings.xml
packages/Shell/res/values-zh-rTW/strings.xml
packages/Shell/res/values-zu/strings.xml
packages/Shell/res/values/strings.xml
packages/Shell/src/com/android/shell/BugreportProgressService.java
packages/Shell/src/com/android/shell/BugreportStorageProvider.java
packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
packages/SystemUI/AndroidManifest.xml
packages/SystemUI/res/color/notification_guts_buttons.xml [new file with mode: 0644]
packages/SystemUI/res/drawable/qs_btn_borderless_rect.xml [new file with mode: 0644]
packages/SystemUI/res/drawable/qs_customizer_background.xml
packages/SystemUI/res/drawable/recents_tv_background_gradient.xml [moved from packages/SystemUI/res/drawable/qs_background_secondary.xml with 74% similarity]
packages/SystemUI/res/layout/notification_guts.xml
packages/SystemUI/res/layout/notification_settings_icon_row.xml
packages/SystemUI/res/layout/qs_tile_label.xml
packages/SystemUI/res/layout/qs_user_detail_item.xml
packages/SystemUI/res/layout/recents_on_tv.xml
packages/SystemUI/res/layout/recents_tv_task_card_view.xml [moved from packages/SystemUI/res/layout/recents_task_card_view.xml with 63% similarity]
packages/SystemUI/res/layout/remote_input.xml
packages/SystemUI/res/layout/status_bar_expanded.xml
packages/SystemUI/res/values-af/strings.xml
packages/SystemUI/res/values-am/strings.xml
packages/SystemUI/res/values-b+sr+Latn/strings.xml
packages/SystemUI/res/values-bg/strings.xml
packages/SystemUI/res/values-bn-rBD/strings.xml
packages/SystemUI/res/values-bs-rBA/strings.xml
packages/SystemUI/res/values-ca/strings.xml
packages/SystemUI/res/values-cs/strings.xml
packages/SystemUI/res/values-da/strings.xml
packages/SystemUI/res/values-de/strings.xml
packages/SystemUI/res/values-el/strings.xml
packages/SystemUI/res/values-es-rUS/strings.xml
packages/SystemUI/res/values-es/strings.xml
packages/SystemUI/res/values-eu-rES/strings.xml
packages/SystemUI/res/values-fi/strings.xml
packages/SystemUI/res/values-fr-rCA/strings.xml
packages/SystemUI/res/values-fr/strings.xml
packages/SystemUI/res/values-gl-rES/strings.xml
packages/SystemUI/res/values-hy-rAM/strings.xml
packages/SystemUI/res/values-in/strings.xml
packages/SystemUI/res/values-is-rIS/strings.xml
packages/SystemUI/res/values-it/strings.xml
packages/SystemUI/res/values-iw/strings.xml
packages/SystemUI/res/values-ja/strings.xml
packages/SystemUI/res/values-ka-rGE/strings.xml
packages/SystemUI/res/values-kk-rKZ/strings.xml
packages/SystemUI/res/values-ky-rKG/strings.xml
packages/SystemUI/res/values-lt/strings.xml
packages/SystemUI/res/values-lv/strings.xml
packages/SystemUI/res/values-mn-rMN/strings.xml
packages/SystemUI/res/values-mr-rIN/strings.xml
packages/SystemUI/res/values-ms-rMY/strings.xml
packages/SystemUI/res/values-my-rMM/strings.xml
packages/SystemUI/res/values-nb/strings.xml
packages/SystemUI/res/values-pl/strings.xml
packages/SystemUI/res/values-pt-rBR/strings.xml
packages/SystemUI/res/values-pt-rPT/strings.xml
packages/SystemUI/res/values-pt/strings.xml
packages/SystemUI/res/values-ro/strings.xml
packages/SystemUI/res/values-ru/strings.xml
packages/SystemUI/res/values-sk/strings.xml
packages/SystemUI/res/values-sr/strings.xml
packages/SystemUI/res/values-sv/strings.xml
packages/SystemUI/res/values-ta-rIN/strings.xml
packages/SystemUI/res/values-th/strings.xml
packages/SystemUI/res/values-tl/strings.xml
packages/SystemUI/res/values-tr/strings.xml
packages/SystemUI/res/values-uk/strings.xml
packages/SystemUI/res/values-ur-rPK/strings.xml
packages/SystemUI/res/values-uz-rUZ/strings.xml
packages/SystemUI/res/values-zh-rCN/strings.xml
packages/SystemUI/res/values-zh-rHK/strings.xml
packages/SystemUI/res/values-zh-rTW/strings.xml
packages/SystemUI/res/values-zu/strings.xml
packages/SystemUI/res/values/attrs.xml
packages/SystemUI/res/values/colors.xml
packages/SystemUI/res/values/colors_tv.xml
packages/SystemUI/res/values/dimens.xml
packages/SystemUI/res/values/dimens_tv.xml
packages/SystemUI/res/values/strings_tv.xml
packages/SystemUI/res/values/styles.xml
packages/SystemUI/res/values/styles_tv.xml
packages/SystemUI/src/com/android/systemui/DensityContainer.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/SwipeHelper.java
packages/SystemUI/src/com/android/systemui/keyboard/KeyboardUI.java
packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
packages/SystemUI/src/com/android/systemui/qs/QSContainer.java
packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
packages/SystemUI/src/com/android/systemui/qs/QSTile.java
packages/SystemUI/src/com/android/systemui/qs/QSTileBaseView.java
packages/SystemUI/src/com/android/systemui/qs/QuickQSPanel.java
packages/SystemUI/src/com/android/systemui/qs/customize/QSCustomizer.java
packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
packages/SystemUI/src/com/android/systemui/recents/Recents.java
packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java [moved from core/java/android/hardware/ICamera.aidl with 63% similarity]
packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskEvent.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskStartedEvent.java [moved from core/java/android/hardware/ICameraServiceProxy.aidl with 50% similarity]
packages/SystemUI/src/com/android/systemui/recents/events/activity/MultiWindowStateChangedEvent.java [moved from core/java/android/hardware/camera2/params/OutputConfiguration.aidl with 59% similarity]
packages/SystemUI/src/com/android/systemui/recents/events/component/RecentsVisibilityChangedEvent.java
packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryAdapter.java
packages/SystemUI/src/com/android/systemui/recents/misc/DozeTrigger.java
packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
packages/SystemUI/src/com/android/systemui/recents/model/Task.java
packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java [new file with mode: 0644]
packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java
packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
packages/SystemUI/src/com/android/systemui/statusbar/ExpandableView.java
packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
packages/SystemUI/src/com/android/systemui/statusbar/NotificationGuts.java
packages/SystemUI/src/com/android/systemui/statusbar/NotificationSettingsIconRow.java
packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
packages/SystemUI/src/com/android/systemui/statusbar/ViewTransformationHelper.java
packages/SystemUI/src/com/android/systemui/statusbar/notification/TextViewTransformState.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/BarTransitions.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/BaseStatusBarHeader.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/CallbackHandler.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/EthernetSignalController.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkController.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/NightModeController.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/SignalController.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
packages/SystemUI/src/com/android/systemui/statusbar/policy/WifiSignalController.java
packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationChildrenContainer.java
packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
packages/SystemUI/src/com/android/systemui/tuner/NightModeTile.java
packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
packages/SystemUI/src/com/android/systemui/volume/ZenFooter.java
packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/CallbackHandlerTest.java
packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
proto/src/metrics_constants.proto
rs/java/android/renderscript/Allocation.java
rs/jni/android_renderscript_RenderScript.cpp
services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
services/backup/java/com/android/server/backup/BackupManagerService.java
services/core/java/com/android/server/ConnectivityService.java
services/core/java/com/android/server/InputMethodManagerService.java
services/core/java/com/android/server/LockGuard.java [new file with mode: 0644]
services/core/java/com/android/server/LockSettingsService.java
services/core/java/com/android/server/MountService.java
services/core/java/com/android/server/NetworkManagementService.java
services/core/java/com/android/server/NetworkTimeUpdateService.java
services/core/java/com/android/server/NsdService.java
services/core/java/com/android/server/RecoverySystemService.java
services/core/java/com/android/server/SystemConfig.java
services/core/java/com/android/server/am/ActiveServices.java
services/core/java/com/android/server/am/ActivityManagerDebugConfig.java
services/core/java/com/android/server/am/ActivityManagerService.java
services/core/java/com/android/server/am/ActivityRecord.java
services/core/java/com/android/server/am/ActivityStack.java
services/core/java/com/android/server/am/ActivityStackSupervisor.java
services/core/java/com/android/server/am/ActivityStarter.java
services/core/java/com/android/server/am/AppErrorDialog.java
services/core/java/com/android/server/am/AppErrors.java
services/core/java/com/android/server/am/AppNotRespondingDialog.java
services/core/java/com/android/server/am/BroadcastQueue.java
services/core/java/com/android/server/am/EventLogTags.logtags
services/core/java/com/android/server/am/ProcessList.java
services/core/java/com/android/server/am/TaskRecord.java
services/core/java/com/android/server/audio/AudioService.java
services/core/java/com/android/server/audio/RecordingActivityMonitor.java
services/core/java/com/android/server/camera/CameraService.java
services/core/java/com/android/server/connectivity/ApfFilter.java [new file with mode: 0644]
services/core/java/com/android/server/connectivity/KeepaliveTracker.java
services/core/java/com/android/server/connectivity/Nat464Xlat.java
services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
services/core/java/com/android/server/connectivity/NetworkMonitor.java
services/core/java/com/android/server/connectivity/PermissionMonitor.java
services/core/java/com/android/server/connectivity/Tethering.java
services/core/java/com/android/server/fingerprint/FingerprintService.java
services/core/java/com/android/server/job/JobSchedulerService.java
services/core/java/com/android/server/job/JobStore.java
services/core/java/com/android/server/location/GnssLocationProvider.java
services/core/java/com/android/server/location/GnssMeasurementsProvider.java
services/core/java/com/android/server/location/GnssNavigationMessageProvider.java
services/core/java/com/android/server/location/GnssStatusListenerHelper.java
services/core/java/com/android/server/net/IpConfigStore.java
services/core/java/com/android/server/net/NetworkPolicyManagerService.java
services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
services/core/java/com/android/server/notification/NotificationComparator.java
services/core/java/com/android/server/notification/NotificationIntrusivenessExtractor.java
services/core/java/com/android/server/notification/NotificationManagerService.java
services/core/java/com/android/server/notification/ZenModeHelper.java
services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
services/core/java/com/android/server/pm/EphemeralApplicationRegistry.java
services/core/java/com/android/server/pm/Installer.java
services/core/java/com/android/server/pm/OtaDexoptService.java
services/core/java/com/android/server/pm/PackageDexOptimizer.java
services/core/java/com/android/server/pm/PackageManagerService.java
services/core/java/com/android/server/pm/PackageSettingBase.java
services/core/java/com/android/server/pm/Settings.java
services/core/java/com/android/server/policy/PhoneWindowManager.java
services/core/java/com/android/server/policy/ShortcutManager.java
services/core/java/com/android/server/power/PowerManagerService.java
services/core/java/com/android/server/tv/TvInputManagerService.java
services/core/java/com/android/server/vr/VrManagerService.java
services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
services/core/java/com/android/server/wm/AppWindowToken.java
services/core/java/com/android/server/wm/BoundsAnimationController.java
services/core/java/com/android/server/wm/Task.java
services/core/java/com/android/server/wm/TaskStack.java
services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
services/core/java/com/android/server/wm/WindowManagerService.java
services/core/java/com/android/server/wm/WindowState.java
services/core/java/com/android/server/wm/WindowStateAnimator.java
services/core/java/com/android/server/wm/WindowSurfaceController.java
services/core/java/com/android/server/wm/WindowSurfacePlacer.java
services/core/jni/com_android_server_location_GnssLocationProvider.cpp
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
services/devicepolicy/java/com/android/server/devicepolicy/RemoteBugreportUtils.java
services/java/com/android/server/SystemServer.java
services/net/java/android/net/dhcp/DhcpClient.java
services/net/java/android/net/ip/IpManager.java
services/net/java/android/net/ip/IpReachabilityMonitor.java
services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
services/usage/java/com/android/server/usage/UsageStatsService.java
services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java
telecomm/java/android/telecom/Call.java
telecomm/java/android/telecom/Log.java
telecomm/java/android/telecom/TelecomManager.java
telephony/java/android/telephony/CarrierConfigManager.java
telephony/java/android/telephony/ServiceState.java
telephony/java/android/telephony/TelephonyManager.java
test-runner/src/android/test/mock/MockPackageManager.java
tests/HwAccelerationTest/res/drawable/default_wallpaper.jpg [deleted file]
tests/HwAccelerationTest/res/drawable/default_wallpaper.png [new file with mode: 0644]
tests/HwAccelerationTest/res/layout/projection_clipping.xml
tests/OneMedia/src/com/android/onemedia/playback/LocalRenderer.java
tests/SoundTriggerTestApp/src/com/android/test/soundtrigger/TestSoundTriggerActivity.java
tests/SoundTriggerTests/Android.mk
tests/SoundTriggerTests/AndroidManifest.xml
tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java [new file with mode: 0644]
tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
tests/VoiceEnrollment/src/com/android/test/voiceenrollment/TestEnrollmentActivity.java
tests/permission/src/com/android/framework/permission/tests/ActivityManagerPermissionTests.java
tools/aapt/AaptAssets.cpp
tools/aapt2/Android.mk
tools/aapt2/Locale.cpp
tools/aapt2/compile/Compile.cpp
tools/aapt2/compile/Png.cpp
tools/aapt2/data/AndroidManifest.xml [deleted file]
tools/aapt2/data/Makefile [deleted file]
tools/aapt2/data/lib/AndroidManifest.xml [deleted file]
tools/aapt2/data/lib/Makefile [deleted file]
tools/aapt2/data/lib/res/layout/main.xml [deleted file]
tools/aapt2/data/lib/res/raw/hello.txt [deleted file]
tools/aapt2/data/lib/res/values/styles.xml [deleted file]
tools/aapt2/data/res/drawable/image.xml [deleted file]
tools/aapt2/data/res/layout-v21/main.xml [deleted file]
tools/aapt2/data/res/values-v4/styles.xml [deleted file]
tools/aapt2/data/res/values/colors.xml [deleted file]
tools/aapt2/data/res/values/test.xml [deleted file]
tools/aapt2/data/resources.arsc [deleted file]
tools/aapt2/data/resources_base.arsc [deleted file]
tools/aapt2/data/resources_hdpi.arsc [deleted file]
tools/aapt2/dump/Dump.cpp
tools/aapt2/flatten/XmlFlattener.cpp
tools/aapt2/flatten/XmlFlattener_test.cpp
tools/aapt2/integration-tests/Android.mk [new file with mode: 0644]
tools/aapt2/integration-tests/AppOne/Android.mk [new file with mode: 0644]
tools/aapt2/integration-tests/AppOne/AndroidManifest.xml [new file with mode: 0644]
tools/aapt2/integration-tests/AppOne/core [new file with mode: 0644]
tools/aapt2/integration-tests/AppOne/res/drawable/icon.png [moved from tools/aapt2/data/res/drawable/icon.png with 100% similarity]
tools/aapt2/integration-tests/AppOne/res/drawable/image.xml [new file with mode: 0644]
tools/aapt2/integration-tests/AppOne/res/drawable/test.9.png [moved from tools/aapt2/data/res/drawable/test.9.png with 100% similarity]
tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml [new file with mode: 0644]
tools/aapt2/integration-tests/AppOne/res/layout/main.xml [moved from tools/aapt2/data/res/layout/main.xml with 55% similarity]
tools/aapt2/integration-tests/AppOne/res/raw/test.txt [moved from tools/aapt2/data/res/raw/test.txt with 100% similarity]
tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml [new file with mode: 0644]
tools/aapt2/integration-tests/AppOne/res/values/colors.xml [new file with mode: 0644]
tools/aapt2/integration-tests/AppOne/res/values/styles.xml [moved from tools/aapt2/data/res/values/styles.xml with 59% similarity]
tools/aapt2/integration-tests/AppOne/res/values/test.xml [new file with mode: 0644]
tools/aapt2/integration-tests/AppOne/src/com/android/aapt/app/one/AppOne.java [moved from core/java/android/hardware/CameraInfo.aidl with 58% similarity]
tools/aapt2/integration-tests/StaticLibOne/Android.mk [new file with mode: 0644]
tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml [new file with mode: 0644]
tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml [new file with mode: 0644]
tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml [new file with mode: 0644]
tools/aapt2/integration-tests/StaticLibOne/src/com/android/aapt/staticlib/one/StaticLibOne.java [moved from core/java/android/hardware/ICameraClient.aidl with 64% similarity]
tools/aapt2/integration-tests/StaticLibTwo/Android.mk [new file with mode: 0644]
tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml [new file with mode: 0644]
tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml [new file with mode: 0644]
tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml [new file with mode: 0644]
tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java [new file with mode: 0644]
tools/aapt2/io/ZipArchive.cpp
tools/aapt2/java/JavaClassGenerator.cpp
tools/aapt2/link/Link.cpp
tools/aapt2/link/ManifestFixer_test.cpp
tools/aapt2/link/ReferenceLinker.cpp
tools/aapt2/link/ReferenceLinker.h
tools/aapt2/link/ReferenceLinker_test.cpp
tools/aapt2/link/TableMerger.cpp
tools/aapt2/link/TableMerger.h
tools/aapt2/link/XmlReferenceLinker.cpp
tools/aapt2/link/XmlReferenceLinker_test.cpp
tools/aapt2/process/IResourceTableConsumer.h
tools/aapt2/process/SymbolTable.cpp
tools/aapt2/process/SymbolTable.h
tools/aapt2/process/SymbolTable_test.cpp
tools/aapt2/proto/TableProtoDeserializer.cpp
tools/aapt2/proto/TableProtoSerializer.cpp
tools/aapt2/proto/TableProtoSerializer_test.cpp
tools/aapt2/test/Builders.h
tools/aapt2/test/Context.h
tools/aapt2/test/Test.h [moved from core/java/android/hardware/camera2/CaptureRequest.aidl with 64% similarity]
tools/aapt2/xml/XmlDom.h
tools/apilint/apilint.py
tools/layoutlib/.idea/libraries/junit.xml [new file with mode: 0644]
tools/layoutlib/.idea/runConfigurations/Create.xml
tools/layoutlib/Android.mk
tools/layoutlib/bridge/bridge.iml
tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java [new file with mode: 0644]
tools/layoutlib/bridge/src/android/util/PathParser_Delegate.java
tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/Main.java
tools/layoutlib/create/create.iml
tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java
tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
tools/layoutlib/create/tests/com/android/tools/layoutlib/create/StubMethodAdapterTest.java [new file with mode: 0644]
tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/StubClass.java [moved from core/java/android/hardware/ICameraServiceListener.aidl with 62% similarity]
wifi/java/android/net/wifi/RttManager.java
wifi/java/android/net/wifi/WifiConfiguration.java
wifi/java/android/net/wifi/WifiManager.java
wifi/java/android/net/wifi/WifiScanner.java
wifi/java/android/net/wifi/nan/WifiNanManager.java
wifi/java/android/net/wifi/p2p/WifiP2pManager.java

index 2ee7600..3ac5889 100644 (file)
@@ -150,14 +150,14 @@ LOCAL_SRC_FILES += \
        core/java/android/content/pm/IPackageStatsObserver.aidl \
        core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
        core/java/android/database/IContentObserver.aidl \
-       core/java/android/hardware/ICameraService.aidl \
-       core/java/android/hardware/ICameraServiceListener.aidl \
-       core/java/android/hardware/ICameraServiceProxy.aidl \
-       core/java/android/hardware/ICamera.aidl \
-       core/java/android/hardware/ICameraClient.aidl \
+       ../av/camera/aidl/android/hardware/ICameraService.aidl \
+       ../av/camera/aidl/android/hardware/ICameraServiceListener.aidl \
+       ../av/camera/aidl/android/hardware/ICameraServiceProxy.aidl \
+       ../av/camera/aidl/android/hardware/ICamera.aidl \
+       ../av/camera/aidl/android/hardware/ICameraClient.aidl \
+       ../av/camera/aidl/android/hardware/camera2/ICameraDeviceUser.aidl \
+       ../av/camera/aidl/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
        core/java/android/hardware/IConsumerIrService.aidl \
-       core/java/android/hardware/camera2/ICameraDeviceUser.aidl \
-       core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl \
        core/java/android/hardware/ISerialManager.aidl \
        core/java/android/hardware/display/IDisplayManager.aidl \
        core/java/android/hardware/display/IDisplayManagerCallback.aidl \
@@ -455,6 +455,10 @@ LOCAL_AIDL_INCLUDES += \
       $(FRAMEWORKS_BASE_JAVA_SRC_DIRS) \
       frameworks/native/aidl/binder
 
+LOCAL_AIDL_INCLUDES += \
+       frameworks/av/camera/aidl \
+       frameworks/native/aidl/gui
+
 LOCAL_INTERMEDIATE_SOURCES := \
                        $(framework_res_source_path)/android/R.java \
                        $(framework_res_source_path)/android/Manifest.java \
@@ -577,7 +581,7 @@ aidl_files := \
        frameworks/base/core/java/android/view/Display.aidl \
        frameworks/base/core/java/android/view/InputDevice.aidl \
        frameworks/base/core/java/android/view/InputEvent.aidl \
-       frameworks/base/core/java/android/view/Surface.aidl \
+       frameworks/native/aidl/gui/android/view/Surface.aidl \
        frameworks/base/core/java/android/view/WindowContentFrameStats.aidl \
        frameworks/base/core/java/android/view/inputmethod/InputMethodSubtype.aidl \
        frameworks/base/core/java/android/view/inputmethod/CursorAnchorInfo.aidl \
index 2fe5cbe..cee8fdb 100644 (file)
@@ -240,6 +240,7 @@ $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framewo
 $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/media/java/android/media/IRemoteControlDisplay.*)
 $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit1_intermediates/src/com/android/test/split/feature/R.java)
 $(call add-clean-step, rm -f $(OUT_DIR)/target/common/obj/APPS/FeatureSplit2_intermediates/src/com/android/test/split/feature/R.java)
+$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/framework_intermediates/src/core/java/android/hardware)
 
 # ******************************************************************
 # NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST ABOVE THIS BANNER
index d4f9d73..799ad0f 100644 (file)
@@ -2668,6 +2668,8 @@ package android.accessibilityservice {
     field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
     field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
+    field public static final int SHOW_MODE_AUTO = 0; // 0x0
+    field public static final int SHOW_MODE_HIDDEN = 1; // 0x1
   }
 
   public static abstract class AccessibilityService.GestureResultCallback {
@@ -4126,13 +4128,12 @@ package android.app {
     field public java.lang.String serviceDetails;
   }
 
-  public class AutomaticZenRule implements android.os.Parcelable {
+  public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
     method public int describeContents();
     method public android.net.Uri getConditionId();
     method public long getCreationTime();
-    method public java.lang.String getId();
     method public int getInterruptionFilter();
     method public java.lang.String getName();
     method public android.content.ComponentName getOwner();
@@ -5228,14 +5229,14 @@ package android.app {
   }
 
   public class NotificationManager {
-    method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+    method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
     method public boolean areNotificationsEnabled();
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
-    method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
+    method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
@@ -5245,7 +5246,7 @@ package android.app {
     method public boolean removeAutomaticZenRule(java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
-    method public boolean updateAutomaticZenRule(android.app.AutomaticZenRule);
+    method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
@@ -5257,7 +5258,7 @@ package android.app {
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
-    ctor public deprecated NotificationManager.Policy(int, int, int);
+    ctor public NotificationManager.Policy(int, int, int);
     ctor public NotificationManager.Policy(int, int, int, int);
     method public int describeContents();
     method public static java.lang.String priorityCategoriesToString(int);
@@ -5609,8 +5610,6 @@ package android.app {
     method public void enableCarMode(int);
     method public int getCurrentModeType();
     method public int getNightMode();
-    method public boolean isNightModeLocked();
-    method public boolean isUiModeLocked();
     method public void setNightMode(int);
     field public static java.lang.String ACTION_ENTER_CAR_MODE;
     field public static java.lang.String ACTION_ENTER_DESK_MODE;
@@ -5712,6 +5711,7 @@ package android.app {
 
   public class WallpaperManager {
     method public void clear() throws java.io.IOException;
+    method public void clear(int) throws java.io.IOException;
     method public void clearWallpaperOffsets(android.os.IBinder);
     method public void forgetLoadedWallpaper();
     method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -6591,7 +6591,7 @@ package android.auditing {
     field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
   }
 
-  public static class SecurityLog.SecurityEvent implements android.os.Parcelable {
+  public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
     method public int describeContents();
     method public java.lang.Object getData();
     method public int getTag();
@@ -7335,15 +7335,6 @@ package android.bluetooth {
     field public static final int TYPE_SCO = 2; // 0x2
   }
 
-  public class OobData implements android.os.Parcelable {
-    ctor public OobData();
-    method public int describeContents();
-    method public byte[] getSecurityManagerTk();
-    method public void setSecurityManagerTk(byte[]);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.OobData> CREATOR;
-  }
-
 }
 
 package android.bluetooth.le {
@@ -10475,7 +10466,6 @@ package android.database {
     method public boolean hasNext();
     method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
     method public android.database.CursorJoiner.Result next();
-    method public void remove();
   }
 
   public static final class CursorJoiner.Result extends java.lang.Enum {
@@ -19165,168 +19155,110 @@ package android.location {
 
   public final class GnssClock implements android.os.Parcelable {
     method public int describeContents();
-    method public double getBiasInNs();
-    method public double getBiasUncertaintyInNs();
-    method public double getDriftInNsPerSec();
-    method public double getDriftUncertaintyInNsPerSec();
-    method public long getFullBiasInNs();
+    method public double getBiasNanos();
+    method public double getBiasUncertaintyNanos();
+    method public double getDriftNanosPerSecond();
+    method public double getDriftUncertaintyNanosPerSecond();
+    method public long getFullBiasNanos();
     method public int getHardwareClockDiscontinuityCount();
-    method public short getLeapSecond();
-    method public long getTimeInNs();
-    method public double getTimeUncertaintyInNs();
-    method public boolean hasBiasInNs();
-    method public boolean hasBiasUncertaintyInNs();
-    method public boolean hasDriftInNsPerSec();
-    method public boolean hasDriftUncertaintyInNsPerSec();
-    method public boolean hasFullBiasInNs();
+    method public int getLeapSecond();
+    method public long getTimeNanos();
+    method public double getTimeUncertaintyNanos();
+    method public boolean hasBiasNanos();
+    method public boolean hasBiasUncertaintyNanos();
+    method public boolean hasDriftNanosPerSecond();
+    method public boolean hasDriftUncertaintyNanosPerSecond();
+    method public boolean hasFullBiasNanos();
     method public boolean hasLeapSecond();
-    method public boolean hasTimeUncertaintyInNs();
+    method public boolean hasTimeUncertaintyNanos();
     method public void reset();
-    method public void resetBiasInNs();
-    method public void resetBiasUncertaintyInNs();
-    method public void resetDriftInNsPerSec();
-    method public void resetDriftUncertaintyInNsPerSec();
-    method public void resetFullBiasInNs();
+    method public void resetBiasNanos();
+    method public void resetBiasUncertaintyNanos();
+    method public void resetDriftNanosPerSecond();
+    method public void resetDriftUncertaintyNanosPerSecond();
+    method public void resetFullBiasNanos();
     method public void resetLeapSecond();
-    method public void resetTimeUncertaintyInNs();
+    method public void resetTimeUncertaintyNanos();
     method public void set(android.location.GnssClock);
-    method public void setBiasInNs(double);
-    method public void setBiasUncertaintyInNs(double);
-    method public void setDriftInNsPerSec(double);
-    method public void setDriftUncertaintyInNsPerSec(double);
-    method public void setFullBiasInNs(long);
+    method public void setBiasNanos(double);
+    method public void setBiasUncertaintyNanos(double);
+    method public void setDriftNanosPerSecond(double);
+    method public void setDriftUncertaintyNanosPerSecond(double);
+    method public void setFullBiasNanos(long);
     method public void setHardwareClockDiscontinuityCount(int);
-    method public void setLeapSecond(short);
-    method public void setTimeInNs(long);
-    method public void setTimeUncertaintyInNs(double);
+    method public void setLeapSecond(int);
+    method public void setTimeNanos(long);
+    method public void setTimeUncertaintyNanos(double);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
   }
 
   public final class GnssMeasurement implements android.os.Parcelable {
     method public int describeContents();
-    method public double getAccumulatedDeltaRangeInMeters();
-    method public short getAccumulatedDeltaRangeState();
-    method public double getAccumulatedDeltaRangeUncertaintyInMeters();
-    method public double getAzimuthInDeg();
-    method public double getAzimuthUncertaintyInDeg();
-    method public int getBitNumber();
+    method public double getAccumulatedDeltaRangeMeters();
+    method public int getAccumulatedDeltaRangeState();
+    method public double getAccumulatedDeltaRangeUncertaintyMeters();
     method public long getCarrierCycles();
-    method public float getCarrierFrequencyInHz();
+    method public float getCarrierFrequencyHz();
     method public double getCarrierPhase();
     method public double getCarrierPhaseUncertainty();
-    method public double getCn0InDbHz();
-    method public double getCodePhaseInChips();
-    method public double getCodePhaseUncertaintyInChips();
-    method public byte getConstellationType();
-    method public double getDopplerShiftInHz();
-    method public double getDopplerShiftUncertaintyInHz();
-    method public double getElevationInDeg();
-    method public double getElevationUncertaintyInDeg();
-    method public byte getLossOfLock();
-    method public byte getMultipathIndicator();
-    method public double getPseudorangeInMeters();
-    method public double getPseudorangeRateInMetersPerSec();
-    method public double getPseudorangeRateUncertaintyInMetersPerSec();
-    method public double getPseudorangeUncertaintyInMeters();
-    method public long getReceivedSvTimeInNs();
-    method public long getReceivedSvTimeUncertaintyInNs();
+    method public double getCn0DbHz();
+    method public int getConstellationType();
+    method public int getMultipathIndicator();
+    method public double getPseudorangeRateMetersPerSecond();
+    method public double getPseudorangeRateUncertaintyMetersPerSecond();
+    method public long getReceivedSvTimeNanos();
+    method public long getReceivedSvTimeUncertaintyNanos();
     method public double getSnrInDb();
-    method public short getState();
-    method public short getSvid();
-    method public short getTimeFromLastBitInMs();
-    method public double getTimeOffsetInNs();
-    method public boolean hasAzimuthInDeg();
-    method public boolean hasAzimuthUncertaintyInDeg();
-    method public boolean hasBitNumber();
+    method public int getState();
+    method public int getSvid();
+    method public double getTimeOffsetNanos();
     method public boolean hasCarrierCycles();
-    method public boolean hasCarrierFrequencyInHz();
+    method public boolean hasCarrierFrequencyHz();
     method public boolean hasCarrierPhase();
     method public boolean hasCarrierPhaseUncertainty();
-    method public boolean hasCodePhaseInChips();
-    method public boolean hasCodePhaseUncertaintyInChips();
-    method public boolean hasDopplerShiftInHz();
-    method public boolean hasDopplerShiftUncertaintyInHz();
-    method public boolean hasElevationInDeg();
-    method public boolean hasElevationUncertaintyInDeg();
-    method public boolean hasPseudorangeInMeters();
-    method public boolean hasPseudorangeUncertaintyInMeters();
     method public boolean hasSnrInDb();
-    method public boolean hasTimeFromLastBitInMs();
     method public boolean isPseudorangeRateCorrected();
-    method public boolean isUsedInFix();
     method public void reset();
-    method public void resetAzimuthInDeg();
-    method public void resetAzimuthUncertaintyInDeg();
-    method public void resetBitNumber();
     method public void resetCarrierCycles();
-    method public void resetCarrierFrequencyInHz();
+    method public void resetCarrierFrequencyHz();
     method public void resetCarrierPhase();
     method public void resetCarrierPhaseUncertainty();
-    method public void resetCodePhaseInChips();
-    method public void resetCodePhaseUncertaintyInChips();
-    method public void resetDopplerShiftInHz();
-    method public void resetDopplerShiftUncertaintyInHz();
-    method public void resetElevationInDeg();
-    method public void resetElevationUncertaintyInDeg();
-    method public void resetPseudorangeInMeters();
-    method public void resetPseudorangeUncertaintyInMeters();
     method public void resetSnrInDb();
-    method public void resetTimeFromLastBitInMs();
     method public void set(android.location.GnssMeasurement);
-    method public void setAccumulatedDeltaRangeInMeters(double);
-    method public void setAccumulatedDeltaRangeState(short);
-    method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
-    method public void setAzimuthInDeg(double);
-    method public void setAzimuthUncertaintyInDeg(double);
-    method public void setBitNumber(int);
+    method public void setAccumulatedDeltaRangeMeters(double);
+    method public void setAccumulatedDeltaRangeState(int);
+    method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
     method public void setCarrierCycles(long);
-    method public void setCarrierFrequencyInHz(float);
+    method public void setCarrierFrequencyHz(float);
     method public void setCarrierPhase(double);
     method public void setCarrierPhaseUncertainty(double);
-    method public void setCn0InDbHz(double);
-    method public void setCodePhaseInChips(double);
-    method public void setCodePhaseUncertaintyInChips(double);
-    method public void setConstellationType(byte);
-    method public void setDopplerShiftInHz(double);
-    method public void setDopplerShiftUncertaintyInHz(double);
-    method public void setElevationInDeg(double);
-    method public void setElevationUncertaintyInDeg(double);
-    method public void setLossOfLock(byte);
-    method public void setMultipathIndicator(byte);
-    method public void setPseudorangeInMeters(double);
-    method public void setPseudorangeRateInMetersPerSec(double);
-    method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
-    method public void setPseudorangeUncertaintyInMeters(double);
-    method public void setReceivedSvTimeInNs(long);
-    method public void setReceivedSvTimeUncertaintyInNs(long);
+    method public void setCn0DbHz(double);
+    method public void setConstellationType(int);
+    method public void setMultipathIndicator(int);
+    method public void setPseudorangeRateMetersPerSecond(double);
+    method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
+    method public void setReceivedSvTimeNanos(long);
+    method public void setReceivedSvTimeUncertaintyNanos(long);
     method public void setSnrInDb(double);
-    method public void setState(short);
-    method public void setSvid(short);
-    method public void setTimeFromLastBitInMs(short);
-    method public void setTimeOffsetInNs(double);
-    method public void setUsedInFix(boolean);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
-    field public static final short ADR_STATE_RESET = 2; // 0x2
-    field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
-    field public static final short ADR_STATE_VALID = 1; // 0x1
+    method public void setState(int);
+    method public void setSvid(int);
+    method public void setTimeOffsetNanos(double);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final int ADR_STATE_RESET = 2; // 0x2
+    field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+    field public static final int ADR_STATE_VALID = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
-    field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
-    field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
-    field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
-    field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
-    field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
-    field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
-    field public static final short STATE_BIT_SYNC = 2; // 0x2
-    field public static final short STATE_CODE_LOCK = 1; // 0x1
-    field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
-    field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
-    field public static final short STATE_TOW_DECODED = 8; // 0x8
-    field public static final short STATE_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+    field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+    field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final int STATE_BIT_SYNC = 2; // 0x2
+    field public static final int STATE_CODE_LOCK = 1; // 0x1
+    field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+    field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
   public static abstract class GnssMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
@@ -19339,7 +19271,7 @@ package android.location {
     method public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -19356,34 +19288,34 @@ package android.location {
   public final class GnssNavigationMessage implements android.os.Parcelable {
     method public int describeContents();
     method public byte[] getData();
-    method public short getMessageId();
-    method public short getStatus();
-    method public short getSubmessageId();
-    method public short getSvid();
-    method public short getType();
+    method public int getMessageId();
+    method public int getStatus();
+    method public int getSubmessageId();
+    method public int getSvid();
+    method public int getType();
     method public void reset();
     method public void set(android.location.GnssNavigationMessage);
     method public void setData(byte[]);
-    method public void setMessageId(short);
-    method public void setStatus(short);
-    method public void setSubmessageId(short);
-    method public void setSvid(short);
-    method public void setType(short);
+    method public void setMessageId(int);
+    method public void setStatus(int);
+    method public void setSubmessageId(int);
+    method public void setSvid(int);
+    method public void setType(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
-    field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
-    field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
-    field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
-    field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
-    field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
-    field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
-    field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
-    field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
-    field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
-    field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
-    field public static final short STATUS_PARITY_PASSED = 1; // 0x1
-    field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
-    field public static final short STATUS_UNKNOWN = 0; // 0x0
+    field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_BDS_D1 = 1281; // 0x501
+    field public static final int TYPE_BDS_D2 = 1282; // 0x502
+    field public static final int TYPE_GAL_F = 1538; // 0x602
+    field public static final int TYPE_GAL_I = 1537; // 0x601
+    field public static final int TYPE_GLO_L1CA = 769; // 0x301
+    field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+    field public static final int TYPE_GPS_L1CA = 257; // 0x101
+    field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+    field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+    field public static final int TYPE_UNKNOWN = 0; // 0x0
   }
 
   public static abstract class GnssNavigationMessage.GnssNavigationMessageType implements java.lang.annotation.Annotation {
@@ -19395,7 +19327,7 @@ package android.location {
     method public android.location.GnssNavigationMessage getNavigationMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessageEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -19414,22 +19346,22 @@ package android.location {
   }
 
   public final class GnssStatus {
-    method public float getAzimuth(int);
-    method public byte getConstellationType(int);
-    method public float getElevation(int);
+    method public float getAzimuthDegrees(int);
+    method public float getCn0DbHz(int);
+    method public int getConstellationType(int);
+    method public float getElevationDegrees(int);
     method public int getNumSatellites();
-    method public float getSnr(int);
     method public int getSvid(int);
     method public boolean hasAlmanac(int);
     method public boolean hasEphemeris(int);
     method public boolean usedInFix(int);
-    field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
-    field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
-    field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
-    field public static final byte CONSTELLATION_GPS = 1; // 0x1
-    field public static final byte CONSTELLATION_QZSS = 4; // 0x4
-    field public static final byte CONSTELLATION_SBAS = 2; // 0x2
-    field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
   }
 
   public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
@@ -19544,8 +19476,8 @@ package android.location {
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isProviderEnabled(java.lang.String);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback, android.os.Handler);
     method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
@@ -19570,7 +19502,7 @@ package android.location {
     method public void setTestProviderEnabled(java.lang.String, boolean);
     method public void setTestProviderLocation(java.lang.String, android.location.Location);
     method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
-    method public void unregisterGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
@@ -19708,7 +19640,7 @@ package android.media {
     field public static final int TYPE_WIRED_HEADSET = 3; // 0x3
   }
 
-  public class AudioFormat implements android.os.Parcelable {
+  public final class AudioFormat implements android.os.Parcelable {
     method public int describeContents();
     method public int getChannelCount();
     method public int getChannelIndexMask();
@@ -19934,7 +19866,7 @@ package android.media {
 
   public static abstract class AudioManager.AudioRecordingCallback {
     ctor public AudioManager.AudioRecordingCallback();
-    method public void onRecordConfigChanged();
+    method public void onRecordConfigChanged(android.media.AudioRecordConfiguration[]);
   }
 
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20008,7 +19940,7 @@ package android.media {
     method public abstract void onRoutingChanged(android.media.AudioRecord);
   }
 
-  public class AudioRecordConfiguration implements android.os.Parcelable {
+  public final class AudioRecordConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.AudioDeviceInfo getAudioDevice();
     method public int getClientAudioSessionId();
@@ -20660,6 +20592,7 @@ package android.media {
     field public static final int HEVCMainTierLevel62 = 16777216; // 0x1000000
     field public static final int HEVCProfileMain = 1; // 0x1
     field public static final int HEVCProfileMain10 = 2; // 0x2
+    field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
     field public static final int MPEG2LevelH14 = 2; // 0x2
     field public static final int MPEG2LevelHL = 3; // 0x3
     field public static final int MPEG2LevelLL = 0; // 0x0
@@ -21001,6 +20934,7 @@ package android.media {
     field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height";
     field public static final java.lang.String KEY_STRIDE = "stride";
     field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema";
+    field public static final java.lang.String KEY_TRACK_ID = "track-id";
     field public static final java.lang.String KEY_WIDTH = "width";
     field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
     field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -22976,7 +22910,7 @@ package android.media.tv {
   }
 
   public static final class TvInputInfo.Builder {
-    ctor public TvInputInfo.Builder(android.content.Context, java.lang.Class<?>);
+    ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
     method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
     method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -23044,7 +22978,7 @@ package android.media.tv {
     ctor public TvInputService.RecordingSession(android.content.Context);
     method public void notifyError(int);
     method public void notifyRecordingStopped(android.net.Uri);
-    method public void notifyTuned();
+    method public void notifyTuned(android.net.Uri);
     method public abstract void onRelease();
     method public abstract void onStartRecording(android.net.Uri);
     method public abstract void onStopRecording();
@@ -23103,7 +23037,7 @@ package android.media.tv {
     method public void onDisconnected(java.lang.String);
     method public void onError(int);
     method public void onRecordingStopped(android.net.Uri);
-    method public void onTuned();
+    method public void onTuned(android.net.Uri);
   }
 
   public final class TvTrackInfo implements android.os.Parcelable {
@@ -23523,17 +23457,6 @@ package android.net {
     method public abstract void onNetworkActive();
   }
 
-  public class ConnectivityMetricsEvent implements android.os.Parcelable {
-    ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
-    field public final int componentTag;
-    field public final android.os.Parcelable data;
-    field public final int eventTag;
-    field public final long timestamp;
-  }
-
   public class Credentials {
     ctor public Credentials(int, int, int);
     method public int getGid();
@@ -23541,7 +23464,7 @@ package android.net {
     method public int getUid();
   }
 
-  public class DataUsageRequest implements android.os.Parcelable {
+  public final class DataUsageRequest implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.DataUsageRequest> CREATOR;
@@ -26859,7 +26782,8 @@ package android.opengl {
     method public static void glGetSynciv(long, int, int, int[], int, int[], int);
     method public static void glGetSynciv(long, int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetTransformFeedbackVarying(int, int, int, int[], int, int[], int, int[], int, byte[], int);
-    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static deprecated void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, int[], int, int[], int);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static int glGetUniformBlockIndex(int, java.lang.String);
@@ -29123,6 +29047,8 @@ package android.os {
     ctor public Process();
     method public static final long getElapsedCpuTime();
     method public static final int getGidForName(java.lang.String);
+    method public static final long getStartElapsedRealtime();
+    method public static final long getStartUptimeMillis();
     method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
     method public static final int getUidForName(java.lang.String);
     method public static final boolean is64Bit();
@@ -29428,7 +29354,7 @@ package android.os.storage {
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
   }
 
-  public class StorageVolume implements android.os.Parcelable {
+  public final class StorageVolume implements android.os.Parcelable {
     method public android.content.Intent createAccessIntent(java.lang.String);
     method public int describeContents();
     method public java.lang.String getDescription(android.content.Context);
@@ -30261,7 +30187,7 @@ package android.provider {
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_ORIGINAL_NUMBER = "original_number";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number";
     field public static final android.net.Uri CONTENT_URI;
   }
 
@@ -31788,6 +31714,7 @@ package android.provider {
 
   public static final class DocumentsContract.Root {
     field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
+    field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
     field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
     field public static final java.lang.String COLUMN_FLAGS = "flags";
     field public static final java.lang.String COLUMN_ICON = "icon";
@@ -34310,7 +34237,8 @@ package android.service.carrier {
     ctor public CarrierMessagingService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
-    method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public deprecated void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public void onReceiveTextSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
     method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
@@ -34321,6 +34249,9 @@ package android.service.carrier {
     field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
     field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
     field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
+    field public static final int RECEIVE_OPTIONS_DROP = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 2; // 0x2
     field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
     field public static final int SEND_STATUS_ERROR = 2; // 0x2
     field public static final int SEND_STATUS_OK = 0; // 0x0
@@ -34552,7 +34483,7 @@ package android.service.notification {
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
-    method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
+    method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
     method public final void requestUnbind() throws android.os.RemoteException;
     method public final void setNotificationsShown(java.lang.String[]);
     field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
@@ -36432,7 +36363,7 @@ package android.telecom {
     method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
     method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
-    method public void launchManageBlockedNumbersActivity();
+    method public deprecated void launchManageBlockedNumbersActivity();
     method public void placeCall(android.net.Uri, android.os.Bundle);
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
     method public void showInCallScreen(boolean);
@@ -38547,7 +38478,6 @@ package android.text {
     method public boolean hasNext();
     method public java.util.Iterator<java.lang.String> iterator();
     method public java.lang.String next();
-    method public void remove();
     method public void setString(java.lang.String);
   }
 
@@ -40159,6 +40089,7 @@ package android.util {
     method public int describeContents();
     method public static android.util.LocaleList forLanguageTags(java.lang.String);
     method public java.util.Locale get(int);
+    method public static android.util.LocaleList getAdjustedDefault();
     method public static android.util.LocaleList getDefault();
     method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getFirstMatch(java.lang.String[]);
@@ -50470,6 +50401,7 @@ package java.lang {
     method public static long doubleToRawLongBits(double);
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(double);
     method public int intValue();
     method public static boolean isInfinite(double);
     method public boolean isInfinite();
@@ -50477,11 +50409,15 @@ package java.lang {
     method public boolean isNaN();
     method public static double longBitsToDouble(long);
     method public long longValue();
+    method public static double max(double, double);
+    method public static double min(double, double);
     method public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+    method public static double sum(double, double);
     method public static java.lang.String toHexString(double);
     method public static java.lang.String toString(double);
     method public static java.lang.Double valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Double valueOf(double);
+    field public static final int BYTES = 8; // 0x8
     field public static final int MAX_EXPONENT = 1023; // 0x3ff
     field public static final double MAX_VALUE = 1.7976931348623157E308;
     field public static final int MIN_EXPONENT = -1022; // 0xfffffc02
@@ -50644,10 +50580,13 @@ package java.lang {
     method public static java.lang.Integer getInteger(java.lang.String);
     method public static java.lang.Integer getInteger(java.lang.String, int);
     method public static java.lang.Integer getInteger(java.lang.String, java.lang.Integer);
+    method public static int hashCode(int);
     method public static int highestOneBit(int);
     method public int intValue();
     method public long longValue();
     method public static int lowestOneBit(int);
+    method public static int max(int, int);
+    method public static int min(int, int);
     method public static int numberOfLeadingZeros(int);
     method public static int numberOfTrailingZeros(int);
     method public static int parseInt(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50657,6 +50596,7 @@ package java.lang {
     method public static int rotateLeft(int, int);
     method public static int rotateRight(int, int);
     method public static int signum(int);
+    method public static int sum(int, int);
     method public static java.lang.String toBinaryString(int);
     method public static java.lang.String toHexString(int);
     method public static java.lang.String toOctalString(int);
@@ -50665,6 +50605,7 @@ package java.lang {
     method public static java.lang.Integer valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(int);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_VALUE = 2147483647; // 0x7fffffff
     field public static final int MIN_VALUE = -2147483648; // 0x80000000
     field public static final int SIZE = 32; // 0x20
@@ -50684,6 +50625,7 @@ package java.lang {
   }
 
   public abstract interface Iterable {
+    method public default void forEach(java.util.function.Consumer<? super T>);
     method public abstract java.util.Iterator<T> iterator();
   }
 
@@ -50705,10 +50647,13 @@ package java.lang {
     method public static java.lang.Long getLong(java.lang.String);
     method public static java.lang.Long getLong(java.lang.String, long);
     method public static java.lang.Long getLong(java.lang.String, java.lang.Long);
+    method public static int hashCode(long);
     method public static long highestOneBit(long);
     method public int intValue();
     method public long longValue();
     method public static long lowestOneBit(long);
+    method public static long max(long, long);
+    method public static long min(long, long);
     method public static int numberOfLeadingZeros(long);
     method public static int numberOfTrailingZeros(long);
     method public static long parseLong(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50718,6 +50663,7 @@ package java.lang {
     method public static long rotateLeft(long, int);
     method public static long rotateRight(long, int);
     method public static int signum(long);
+    method public static long sum(long, long);
     method public static java.lang.String toBinaryString(long);
     method public static java.lang.String toHexString(long);
     method public static java.lang.String toOctalString(long);
@@ -54159,6 +54105,7 @@ package java.security {
 
   public abstract class Provider extends java.util.Properties {
     ctor protected Provider(java.lang.String, double, java.lang.String);
+    method public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object, ? super java.lang.Object>);
     method public java.lang.String getInfo();
     method public java.lang.String getName();
     method public synchronized java.security.Provider.Service getService(java.lang.String, java.lang.String);
@@ -57108,6 +57055,7 @@ package java.util {
     ctor public ArrayList(java.util.Collection<? extends E>);
     method public java.lang.Object clone();
     method public void ensureCapacity(int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
     method public int size();
     method public void trimToSize();
@@ -57671,6 +57619,7 @@ package java.util {
     ctor public HashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
   public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
@@ -57695,6 +57644,7 @@ package java.util {
     method public boolean containsValue(java.lang.Object);
     method public synchronized java.util.Enumeration<V> elements();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public synchronized void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public synchronized V get(java.lang.Object);
     method public synchronized boolean isEmpty();
     method public java.util.Set<K> keySet();
@@ -57713,6 +57663,7 @@ package java.util {
     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -57762,9 +57713,10 @@ package java.util {
   }
 
   public abstract interface Iterator {
+    method public default void forEachRemaining(java.util.function.Consumer<? super E>);
     method public abstract boolean hasNext();
     method public abstract E next();
-    method public abstract void remove();
+    method public default void remove();
   }
 
   public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
@@ -57952,6 +57904,7 @@ package java.util {
     method public abstract boolean containsValue(java.lang.Object);
     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public abstract boolean equals(java.lang.Object);
+    method public default void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public abstract V get(java.lang.Object);
     method public abstract int hashCode();
     method public abstract boolean isEmpty();
@@ -58066,6 +58019,79 @@ package java.util {
     method public abstract void update(java.util.Observable, java.lang.Object);
   }
 
+  public final class Optional {
+    method public static java.util.Optional<T> empty();
+    method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
+    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+    method public T get();
+    method public void ifPresent(java.util.function.Consumer<? super T>);
+    method public boolean isPresent();
+    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.Optional<T> of(T);
+    method public static java.util.Optional<T> ofNullable(T);
+    method public T orElse(T);
+    method public T orElseGet(java.util.function.Supplier<? extends T>);
+    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalDouble {
+    method public static java.util.OptionalDouble empty();
+    method public double getAsDouble();
+    method public void ifPresent(java.util.function.DoubleConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalDouble of(double);
+    method public double orElse(double);
+    method public double orElseGet(java.util.function.DoubleSupplier);
+    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalInt {
+    method public static java.util.OptionalInt empty();
+    method public int getAsInt();
+    method public void ifPresent(java.util.function.IntConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalInt of(int);
+    method public int orElse(int);
+    method public int orElseGet(java.util.function.IntSupplier);
+    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalLong {
+    method public static java.util.OptionalLong empty();
+    method public long getAsLong();
+    method public void ifPresent(java.util.function.LongConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalLong of(long);
+    method public long orElse(long);
+    method public long orElseGet(java.util.function.LongSupplier);
+    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public abstract interface PrimitiveIterator implements java.util.Iterator {
+    method public abstract void forEachRemaining(T_CONS);
+  }
+
+  public static abstract interface PrimitiveIterator.OfDouble implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.DoubleConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+    method public default java.lang.Double next();
+    method public abstract double nextDouble();
+  }
+
+  public static abstract interface PrimitiveIterator.OfInt implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.IntConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+    method public default java.lang.Integer next();
+    method public abstract int nextInt();
+  }
+
+  public static abstract interface PrimitiveIterator.OfLong implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.LongConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+    method public default java.lang.Long next();
+    method public abstract long nextLong();
+  }
+
   public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
     ctor public PriorityQueue();
     ctor public PriorityQueue(int);
@@ -58237,7 +58263,6 @@ package java.util {
     method public short nextShort();
     method public short nextShort(int);
     method public int radix();
-    method public void remove();
     method public java.util.Scanner reset();
     method public java.util.Scanner skip(java.util.regex.Pattern);
     method public java.util.Scanner skip(java.lang.String);
@@ -58413,6 +58438,7 @@ package java.util {
     method public K firstKey();
     method public java.util.Map.Entry<K, V> floorEntry(K);
     method public K floorKey(K);
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public java.util.NavigableMap<K, V> headMap(K, boolean);
     method public java.util.SortedMap<K, V> headMap(K);
     method public java.util.Map.Entry<K, V> higherEntry(K);
@@ -58495,6 +58521,7 @@ package java.util {
     method public java.util.Enumeration<E> elements();
     method public synchronized void ensureCapacity(int);
     method public synchronized E firstElement();
+    method public synchronized void forEach(java.util.function.Consumer<? super E>);
     method public synchronized E get(int);
     method public synchronized int indexOf(java.lang.Object, int);
     method public synchronized void insertElementAt(E, int);
@@ -58518,6 +58545,7 @@ package java.util {
     ctor public WeakHashMap();
     ctor public WeakHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
 }
index 50a24f6..115224c 100644 (file)
@@ -37,7 +37,7 @@ package android.database {
 
 package android.media {
 
-  public class AudioFormat implements android.os.Parcelable {
+  public final class AudioFormat implements android.os.Parcelable {
     ctor public AudioFormat();
   }
 
index db90b89..9a84d1a 100644 (file)
@@ -2770,6 +2770,8 @@ package android.accessibilityservice {
     field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
     field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
+    field public static final int SHOW_MODE_AUTO = 0; // 0x0
+    field public static final int SHOW_MODE_HIDDEN = 1; // 0x1
   }
 
   public static abstract class AccessibilityService.GestureResultCallback {
@@ -4252,13 +4254,12 @@ package android.app {
     field public java.lang.String serviceDetails;
   }
 
-  public class AutomaticZenRule implements android.os.Parcelable {
+  public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
     method public int describeContents();
     method public android.net.Uri getConditionId();
     method public long getCreationTime();
-    method public java.lang.String getId();
     method public int getInterruptionFilter();
     method public java.lang.String getName();
     method public android.content.ComponentName getOwner();
@@ -5360,14 +5361,14 @@ package android.app {
   }
 
   public class NotificationManager {
-    method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+    method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
     method public boolean areNotificationsEnabled();
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
-    method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
+    method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
@@ -5377,7 +5378,7 @@ package android.app {
     method public boolean removeAutomaticZenRule(java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
-    method public boolean updateAutomaticZenRule(android.app.AutomaticZenRule);
+    method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
@@ -5389,7 +5390,7 @@ package android.app {
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
-    ctor public deprecated NotificationManager.Policy(int, int, int);
+    ctor public NotificationManager.Policy(int, int, int);
     ctor public NotificationManager.Policy(int, int, int, int);
     method public int describeContents();
     method public static java.lang.String priorityCategoriesToString(int);
@@ -5741,8 +5742,6 @@ package android.app {
     method public void enableCarMode(int);
     method public int getCurrentModeType();
     method public int getNightMode();
-    method public boolean isNightModeLocked();
-    method public boolean isUiModeLocked();
     method public void setNightMode(int);
     field public static java.lang.String ACTION_ENTER_CAR_MODE;
     field public static java.lang.String ACTION_ENTER_DESK_MODE;
@@ -5844,6 +5843,7 @@ package android.app {
 
   public class WallpaperManager {
     method public void clear() throws java.io.IOException;
+    method public void clear(int) throws java.io.IOException;
     method public void clearWallpaper();
     method public void clearWallpaper(int, int);
     method public void clearWallpaperOffsets(android.os.IBinder);
@@ -6858,7 +6858,7 @@ package android.auditing {
     field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
   }
 
-  public static class SecurityLog.SecurityEvent implements android.os.Parcelable {
+  public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
     method public int describeContents();
     method public java.lang.Object getData();
     method public int getTag();
@@ -7610,15 +7610,6 @@ package android.bluetooth {
     field public static final int TYPE_SCO = 2; // 0x2
   }
 
-  public class OobData implements android.os.Parcelable {
-    ctor public OobData();
-    method public int describeContents();
-    method public byte[] getSecurityManagerTk();
-    method public void setSecurityManagerTk(byte[]);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.OobData> CREATOR;
-  }
-
 }
 
 package android.bluetooth.le {
@@ -9707,25 +9698,6 @@ package android.content.pm {
     field public int reqTouchScreen;
   }
 
-  public deprecated class ContainerEncryptionParams implements android.os.Parcelable {
-    ctor public ContainerEncryptionParams(java.lang.String, java.security.spec.AlgorithmParameterSpec, javax.crypto.SecretKey) throws java.security.InvalidAlgorithmParameterException;
-    ctor public ContainerEncryptionParams(java.lang.String, java.security.spec.AlgorithmParameterSpec, javax.crypto.SecretKey, java.lang.String, java.security.spec.AlgorithmParameterSpec, javax.crypto.SecretKey, byte[], long, long, long) throws java.security.InvalidAlgorithmParameterException;
-    method public int describeContents();
-    method public long getAuthenticatedDataStart();
-    method public long getDataEnd();
-    method public long getEncryptedDataStart();
-    method public java.lang.String getEncryptionAlgorithm();
-    method public javax.crypto.SecretKey getEncryptionKey();
-    method public java.security.spec.AlgorithmParameterSpec getEncryptionSpec();
-    method public java.lang.String getMacAlgorithm();
-    method public javax.crypto.SecretKey getMacKey();
-    method public java.security.spec.AlgorithmParameterSpec getMacSpec();
-    method public byte[] getMacTag();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.content.pm.ContainerEncryptionParams> CREATOR;
-    field protected static final java.lang.String TAG = "ContainerEncryptionParams";
-  }
-
   public final class EphemeralResolveInfo implements android.os.Parcelable {
     ctor public EphemeralResolveInfo(android.net.Uri, java.lang.String, java.util.List<android.content.IntentFilter>);
     method public int describeContents();
@@ -9955,6 +9927,7 @@ package android.content.pm {
     method public android.graphics.drawable.Drawable loadIcon(android.content.pm.PackageManager);
     method public java.lang.CharSequence loadLabel(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadLogo(android.content.pm.PackageManager);
+    method public java.lang.CharSequence loadSafeLabel(android.content.pm.PackageManager);
     method public android.graphics.drawable.Drawable loadUnbadgedIcon(android.content.pm.PackageManager);
     method public android.content.res.XmlResourceParser loadXmlMetaData(android.content.pm.PackageManager, java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
@@ -10213,6 +10186,8 @@ package android.content.pm {
     field public static final int INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103; // 0xffffff99
     field public static final int INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102; // 0xffffff9a
     field public static final int INSTALL_SUCCEEDED = 1; // 0x1
+    field public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1; // 0xffffffff
+    field public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1; // 0x1
     field public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
@@ -10885,7 +10860,6 @@ package android.database {
     method public boolean hasNext();
     method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
     method public android.database.CursorJoiner.Result next();
-    method public void remove();
   }
 
   public static final class CursorJoiner.Result extends java.lang.Enum {
@@ -20354,168 +20328,110 @@ package android.location {
 
   public final class GnssClock implements android.os.Parcelable {
     method public int describeContents();
-    method public double getBiasInNs();
-    method public double getBiasUncertaintyInNs();
-    method public double getDriftInNsPerSec();
-    method public double getDriftUncertaintyInNsPerSec();
-    method public long getFullBiasInNs();
+    method public double getBiasNanos();
+    method public double getBiasUncertaintyNanos();
+    method public double getDriftNanosPerSecond();
+    method public double getDriftUncertaintyNanosPerSecond();
+    method public long getFullBiasNanos();
     method public int getHardwareClockDiscontinuityCount();
-    method public short getLeapSecond();
-    method public long getTimeInNs();
-    method public double getTimeUncertaintyInNs();
-    method public boolean hasBiasInNs();
-    method public boolean hasBiasUncertaintyInNs();
-    method public boolean hasDriftInNsPerSec();
-    method public boolean hasDriftUncertaintyInNsPerSec();
-    method public boolean hasFullBiasInNs();
+    method public int getLeapSecond();
+    method public long getTimeNanos();
+    method public double getTimeUncertaintyNanos();
+    method public boolean hasBiasNanos();
+    method public boolean hasBiasUncertaintyNanos();
+    method public boolean hasDriftNanosPerSecond();
+    method public boolean hasDriftUncertaintyNanosPerSecond();
+    method public boolean hasFullBiasNanos();
     method public boolean hasLeapSecond();
-    method public boolean hasTimeUncertaintyInNs();
+    method public boolean hasTimeUncertaintyNanos();
     method public void reset();
-    method public void resetBiasInNs();
-    method public void resetBiasUncertaintyInNs();
-    method public void resetDriftInNsPerSec();
-    method public void resetDriftUncertaintyInNsPerSec();
-    method public void resetFullBiasInNs();
+    method public void resetBiasNanos();
+    method public void resetBiasUncertaintyNanos();
+    method public void resetDriftNanosPerSecond();
+    method public void resetDriftUncertaintyNanosPerSecond();
+    method public void resetFullBiasNanos();
     method public void resetLeapSecond();
-    method public void resetTimeUncertaintyInNs();
+    method public void resetTimeUncertaintyNanos();
     method public void set(android.location.GnssClock);
-    method public void setBiasInNs(double);
-    method public void setBiasUncertaintyInNs(double);
-    method public void setDriftInNsPerSec(double);
-    method public void setDriftUncertaintyInNsPerSec(double);
-    method public void setFullBiasInNs(long);
+    method public void setBiasNanos(double);
+    method public void setBiasUncertaintyNanos(double);
+    method public void setDriftNanosPerSecond(double);
+    method public void setDriftUncertaintyNanosPerSecond(double);
+    method public void setFullBiasNanos(long);
     method public void setHardwareClockDiscontinuityCount(int);
-    method public void setLeapSecond(short);
-    method public void setTimeInNs(long);
-    method public void setTimeUncertaintyInNs(double);
+    method public void setLeapSecond(int);
+    method public void setTimeNanos(long);
+    method public void setTimeUncertaintyNanos(double);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
   }
 
   public final class GnssMeasurement implements android.os.Parcelable {
     method public int describeContents();
-    method public double getAccumulatedDeltaRangeInMeters();
-    method public short getAccumulatedDeltaRangeState();
-    method public double getAccumulatedDeltaRangeUncertaintyInMeters();
-    method public double getAzimuthInDeg();
-    method public double getAzimuthUncertaintyInDeg();
-    method public int getBitNumber();
+    method public double getAccumulatedDeltaRangeMeters();
+    method public int getAccumulatedDeltaRangeState();
+    method public double getAccumulatedDeltaRangeUncertaintyMeters();
     method public long getCarrierCycles();
-    method public float getCarrierFrequencyInHz();
+    method public float getCarrierFrequencyHz();
     method public double getCarrierPhase();
     method public double getCarrierPhaseUncertainty();
-    method public double getCn0InDbHz();
-    method public double getCodePhaseInChips();
-    method public double getCodePhaseUncertaintyInChips();
-    method public byte getConstellationType();
-    method public double getDopplerShiftInHz();
-    method public double getDopplerShiftUncertaintyInHz();
-    method public double getElevationInDeg();
-    method public double getElevationUncertaintyInDeg();
-    method public byte getLossOfLock();
-    method public byte getMultipathIndicator();
-    method public double getPseudorangeInMeters();
-    method public double getPseudorangeRateInMetersPerSec();
-    method public double getPseudorangeRateUncertaintyInMetersPerSec();
-    method public double getPseudorangeUncertaintyInMeters();
-    method public long getReceivedSvTimeInNs();
-    method public long getReceivedSvTimeUncertaintyInNs();
+    method public double getCn0DbHz();
+    method public int getConstellationType();
+    method public int getMultipathIndicator();
+    method public double getPseudorangeRateMetersPerSecond();
+    method public double getPseudorangeRateUncertaintyMetersPerSecond();
+    method public long getReceivedSvTimeNanos();
+    method public long getReceivedSvTimeUncertaintyNanos();
     method public double getSnrInDb();
-    method public short getState();
-    method public short getSvid();
-    method public short getTimeFromLastBitInMs();
-    method public double getTimeOffsetInNs();
-    method public boolean hasAzimuthInDeg();
-    method public boolean hasAzimuthUncertaintyInDeg();
-    method public boolean hasBitNumber();
+    method public int getState();
+    method public int getSvid();
+    method public double getTimeOffsetNanos();
     method public boolean hasCarrierCycles();
-    method public boolean hasCarrierFrequencyInHz();
+    method public boolean hasCarrierFrequencyHz();
     method public boolean hasCarrierPhase();
     method public boolean hasCarrierPhaseUncertainty();
-    method public boolean hasCodePhaseInChips();
-    method public boolean hasCodePhaseUncertaintyInChips();
-    method public boolean hasDopplerShiftInHz();
-    method public boolean hasDopplerShiftUncertaintyInHz();
-    method public boolean hasElevationInDeg();
-    method public boolean hasElevationUncertaintyInDeg();
-    method public boolean hasPseudorangeInMeters();
-    method public boolean hasPseudorangeUncertaintyInMeters();
     method public boolean hasSnrInDb();
-    method public boolean hasTimeFromLastBitInMs();
     method public boolean isPseudorangeRateCorrected();
-    method public boolean isUsedInFix();
     method public void reset();
-    method public void resetAzimuthInDeg();
-    method public void resetAzimuthUncertaintyInDeg();
-    method public void resetBitNumber();
     method public void resetCarrierCycles();
-    method public void resetCarrierFrequencyInHz();
+    method public void resetCarrierFrequencyHz();
     method public void resetCarrierPhase();
     method public void resetCarrierPhaseUncertainty();
-    method public void resetCodePhaseInChips();
-    method public void resetCodePhaseUncertaintyInChips();
-    method public void resetDopplerShiftInHz();
-    method public void resetDopplerShiftUncertaintyInHz();
-    method public void resetElevationInDeg();
-    method public void resetElevationUncertaintyInDeg();
-    method public void resetPseudorangeInMeters();
-    method public void resetPseudorangeUncertaintyInMeters();
     method public void resetSnrInDb();
-    method public void resetTimeFromLastBitInMs();
     method public void set(android.location.GnssMeasurement);
-    method public void setAccumulatedDeltaRangeInMeters(double);
-    method public void setAccumulatedDeltaRangeState(short);
-    method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
-    method public void setAzimuthInDeg(double);
-    method public void setAzimuthUncertaintyInDeg(double);
-    method public void setBitNumber(int);
+    method public void setAccumulatedDeltaRangeMeters(double);
+    method public void setAccumulatedDeltaRangeState(int);
+    method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
     method public void setCarrierCycles(long);
-    method public void setCarrierFrequencyInHz(float);
+    method public void setCarrierFrequencyHz(float);
     method public void setCarrierPhase(double);
     method public void setCarrierPhaseUncertainty(double);
-    method public void setCn0InDbHz(double);
-    method public void setCodePhaseInChips(double);
-    method public void setCodePhaseUncertaintyInChips(double);
-    method public void setConstellationType(byte);
-    method public void setDopplerShiftInHz(double);
-    method public void setDopplerShiftUncertaintyInHz(double);
-    method public void setElevationInDeg(double);
-    method public void setElevationUncertaintyInDeg(double);
-    method public void setLossOfLock(byte);
-    method public void setMultipathIndicator(byte);
-    method public void setPseudorangeInMeters(double);
-    method public void setPseudorangeRateInMetersPerSec(double);
-    method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
-    method public void setPseudorangeUncertaintyInMeters(double);
-    method public void setReceivedSvTimeInNs(long);
-    method public void setReceivedSvTimeUncertaintyInNs(long);
+    method public void setCn0DbHz(double);
+    method public void setConstellationType(int);
+    method public void setMultipathIndicator(int);
+    method public void setPseudorangeRateMetersPerSecond(double);
+    method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
+    method public void setReceivedSvTimeNanos(long);
+    method public void setReceivedSvTimeUncertaintyNanos(long);
     method public void setSnrInDb(double);
-    method public void setState(short);
-    method public void setSvid(short);
-    method public void setTimeFromLastBitInMs(short);
-    method public void setTimeOffsetInNs(double);
-    method public void setUsedInFix(boolean);
+    method public void setState(int);
+    method public void setSvid(int);
+    method public void setTimeOffsetNanos(double);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
-    field public static final short ADR_STATE_RESET = 2; // 0x2
-    field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
-    field public static final short ADR_STATE_VALID = 1; // 0x1
+    field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final int ADR_STATE_RESET = 2; // 0x2
+    field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+    field public static final int ADR_STATE_VALID = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
-    field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
-    field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
-    field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
-    field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
-    field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
-    field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
-    field public static final short STATE_BIT_SYNC = 2; // 0x2
-    field public static final short STATE_CODE_LOCK = 1; // 0x1
-    field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
-    field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
-    field public static final short STATE_TOW_DECODED = 8; // 0x8
-    field public static final short STATE_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+    field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+    field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final int STATE_BIT_SYNC = 2; // 0x2
+    field public static final int STATE_CODE_LOCK = 1; // 0x1
+    field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+    field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
   public static abstract class GnssMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
@@ -20528,7 +20444,7 @@ package android.location {
     method public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -20545,34 +20461,34 @@ package android.location {
   public final class GnssNavigationMessage implements android.os.Parcelable {
     method public int describeContents();
     method public byte[] getData();
-    method public short getMessageId();
-    method public short getStatus();
-    method public short getSubmessageId();
-    method public short getSvid();
-    method public short getType();
+    method public int getMessageId();
+    method public int getStatus();
+    method public int getSubmessageId();
+    method public int getSvid();
+    method public int getType();
     method public void reset();
     method public void set(android.location.GnssNavigationMessage);
     method public void setData(byte[]);
-    method public void setMessageId(short);
-    method public void setStatus(short);
-    method public void setSubmessageId(short);
-    method public void setSvid(short);
-    method public void setType(short);
+    method public void setMessageId(int);
+    method public void setStatus(int);
+    method public void setSubmessageId(int);
+    method public void setSvid(int);
+    method public void setType(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
-    field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
-    field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
-    field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
-    field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
-    field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
-    field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
-    field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
-    field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
-    field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
-    field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
-    field public static final short STATUS_PARITY_PASSED = 1; // 0x1
-    field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
-    field public static final short STATUS_UNKNOWN = 0; // 0x0
+    field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_BDS_D1 = 1281; // 0x501
+    field public static final int TYPE_BDS_D2 = 1282; // 0x502
+    field public static final int TYPE_GAL_F = 1538; // 0x602
+    field public static final int TYPE_GAL_I = 1537; // 0x601
+    field public static final int TYPE_GLO_L1CA = 769; // 0x301
+    field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+    field public static final int TYPE_GPS_L1CA = 257; // 0x101
+    field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+    field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+    field public static final int TYPE_UNKNOWN = 0; // 0x0
   }
 
   public static abstract class GnssNavigationMessage.GnssNavigationMessageType implements java.lang.annotation.Annotation {
@@ -20584,7 +20500,7 @@ package android.location {
     method public android.location.GnssNavigationMessage getNavigationMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessageEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -20603,22 +20519,22 @@ package android.location {
   }
 
   public final class GnssStatus {
-    method public float getAzimuth(int);
-    method public byte getConstellationType(int);
-    method public float getElevation(int);
+    method public float getAzimuthDegrees(int);
+    method public float getCn0DbHz(int);
+    method public int getConstellationType(int);
+    method public float getElevationDegrees(int);
     method public int getNumSatellites();
-    method public float getSnr(int);
     method public int getSvid(int);
     method public boolean hasAlmanac(int);
     method public boolean hasEphemeris(int);
     method public boolean usedInFix(int);
-    field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
-    field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
-    field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
-    field public static final byte CONSTELLATION_GPS = 1; // 0x1
-    field public static final byte CONSTELLATION_QZSS = 4; // 0x4
-    field public static final byte CONSTELLATION_SBAS = 2; // 0x2
-    field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
   }
 
   public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
@@ -20980,8 +20896,8 @@ package android.location {
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isProviderEnabled(java.lang.String);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback, android.os.Handler);
     method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
@@ -21010,7 +20926,7 @@ package android.location {
     method public void setTestProviderEnabled(java.lang.String, boolean);
     method public void setTestProviderLocation(java.lang.String, android.location.Location);
     method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
-    method public void unregisterGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
@@ -21204,7 +21120,7 @@ package android.media {
     field public static final android.os.Parcelable.Creator<android.media.AudioFocusInfo> CREATOR;
   }
 
-  public class AudioFormat implements android.os.Parcelable {
+  public final class AudioFormat implements android.os.Parcelable {
     method public int describeContents();
     method public int getChannelCount();
     method public int getChannelIndexMask();
@@ -21439,7 +21355,7 @@ package android.media {
 
   public static abstract class AudioManager.AudioRecordingCallback {
     ctor public AudioManager.AudioRecordingCallback();
-    method public void onRecordConfigChanged();
+    method public void onRecordConfigChanged(android.media.AudioRecordConfiguration[]);
   }
 
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -21516,7 +21432,7 @@ package android.media {
     method public abstract void onRoutingChanged(android.media.AudioRecord);
   }
 
-  public class AudioRecordConfiguration implements android.os.Parcelable {
+  public final class AudioRecordConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.AudioDeviceInfo getAudioDevice();
     method public int getClientAudioSessionId();
@@ -22168,6 +22084,7 @@ package android.media {
     field public static final int HEVCMainTierLevel62 = 16777216; // 0x1000000
     field public static final int HEVCProfileMain = 1; // 0x1
     field public static final int HEVCProfileMain10 = 2; // 0x2
+    field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
     field public static final int MPEG2LevelH14 = 2; // 0x2
     field public static final int MPEG2LevelHL = 3; // 0x3
     field public static final int MPEG2LevelLL = 0; // 0x0
@@ -22509,6 +22426,7 @@ package android.media {
     field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height";
     field public static final java.lang.String KEY_STRIDE = "stride";
     field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema";
+    field public static final java.lang.String KEY_TRACK_ID = "track-id";
     field public static final java.lang.String KEY_WIDTH = "width";
     field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
     field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -24663,7 +24581,7 @@ package android.media.tv {
   }
 
   public static final class TvInputInfo.Builder {
-    ctor public TvInputInfo.Builder(android.content.Context, java.lang.Class<?>);
+    ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
     method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
     method public android.media.tv.TvInputInfo.Builder setHdmiDeviceInfo(android.hardware.hdmi.HdmiDeviceInfo);
@@ -24808,7 +24726,7 @@ package android.media.tv {
     method public void notifyError(int);
     method public void notifyRecordingStopped(android.net.Uri);
     method public void notifySessionEvent(java.lang.String, android.os.Bundle);
-    method public void notifyTuned();
+    method public void notifyTuned(android.net.Uri);
     method public void onAppPrivateCommand(java.lang.String, android.os.Bundle);
     method public abstract void onRelease();
     method public abstract void onStartRecording(android.net.Uri);
@@ -24876,7 +24794,7 @@ package android.media.tv {
     method public void onError(int);
     method public void onEvent(java.lang.String, java.lang.String, android.os.Bundle);
     method public void onRecordingStopped(android.net.Uri);
-    method public void onTuned();
+    method public void onTuned(android.net.Uri);
   }
 
   public class TvStreamConfig implements android.os.Parcelable {
@@ -25344,17 +25262,6 @@ package android.net {
     method public void onTetheringStarted();
   }
 
-  public class ConnectivityMetricsEvent implements android.os.Parcelable {
-    ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
-    field public final int componentTag;
-    field public final android.os.Parcelable data;
-    field public final int eventTag;
-    field public final long timestamp;
-  }
-
   public class Credentials {
     ctor public Credentials(int, int, int);
     method public int getGid();
@@ -25362,7 +25269,7 @@ package android.net {
     method public int getUid();
   }
 
-  public class DataUsageRequest implements android.os.Parcelable {
+  public final class DataUsageRequest implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.DataUsageRequest> CREATOR;
@@ -26757,7 +26664,6 @@ package android.net.wifi {
     method public boolean reconnect();
     method public boolean removeNetwork(int);
     method public boolean saveConfiguration();
-    method public boolean setMetered(int, boolean);
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiApConfiguration(android.net.wifi.WifiConfiguration);
@@ -29161,7 +29067,8 @@ package android.opengl {
     method public static void glGetSynciv(long, int, int, int[], int, int[], int);
     method public static void glGetSynciv(long, int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetTransformFeedbackVarying(int, int, int, int[], int, int[], int, int[], int, byte[], int);
-    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static deprecated void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, int[], int, int[], int);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static int glGetUniformBlockIndex(int, java.lang.String);
@@ -31433,6 +31340,8 @@ package android.os {
     ctor public Process();
     method public static final long getElapsedCpuTime();
     method public static final int getGidForName(java.lang.String);
+    method public static final long getStartElapsedRealtime();
+    method public static final long getStartUptimeMillis();
     method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
     method public static final int getUidForName(java.lang.String);
     method public static final boolean is64Bit();
@@ -31799,7 +31708,7 @@ package android.os.storage {
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
   }
 
-  public class StorageVolume implements android.os.Parcelable {
+  public final class StorageVolume implements android.os.Parcelable {
     method public android.content.Intent createAccessIntent(java.lang.String);
     method public int describeContents();
     method public java.lang.String getDescription(android.content.Context);
@@ -32633,7 +32542,7 @@ package android.provider {
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_ORIGINAL_NUMBER = "original_number";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number";
     field public static final android.net.Uri CONTENT_URI;
   }
 
@@ -34190,6 +34099,7 @@ package android.provider {
 
   public static final class DocumentsContract.Root {
     field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
+    field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
     field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
     field public static final java.lang.String COLUMN_FLAGS = "flags";
     field public static final java.lang.String COLUMN_ICON = "icon";
@@ -36817,7 +36727,8 @@ package android.service.carrier {
     ctor public CarrierMessagingService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
-    method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public deprecated void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public void onReceiveTextSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
     method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
@@ -36828,6 +36739,9 @@ package android.service.carrier {
     field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
     field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
     field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
+    field public static final int RECEIVE_OPTIONS_DROP = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 2; // 0x2
     field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
     field public static final int SEND_STATUS_ERROR = 2; // 0x2
     field public static final int SEND_STATUS_OK = 0; // 0x0
@@ -37041,6 +36955,7 @@ package android.service.notification {
   public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
     ctor public NotificationAssistantService();
     method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
+    method public final android.os.IBinder onBind(android.content.Intent);
     method public void onNotificationActionClick(java.lang.String, long, int);
     method public void onNotificationClick(java.lang.String, long);
     method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
@@ -37093,7 +37008,7 @@ package android.service.notification {
     method public void registerAsSystemService(android.content.Context, android.content.ComponentName, int) throws android.os.RemoteException;
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
-    method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
+    method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
     method public final void requestUnbind() throws android.os.RemoteException;
     method public final void setNotificationsShown(java.lang.String[]);
     method public final void setOnNotificationPostedTrim(int);
@@ -39144,7 +39059,7 @@ package android.telecom {
     method public boolean isRinging();
     method public boolean isTtySupported();
     method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
-    method public void launchManageBlockedNumbersActivity();
+    method public deprecated void launchManageBlockedNumbersActivity();
     method public void placeCall(android.net.Uri, android.os.Bundle);
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
     method public void showInCallScreen(boolean);
@@ -41330,7 +41245,6 @@ package android.text {
     method public boolean hasNext();
     method public java.util.Iterator<java.lang.String> iterator();
     method public java.lang.String next();
-    method public void remove();
     method public void setString(java.lang.String);
   }
 
@@ -42942,6 +42856,7 @@ package android.util {
     method public int describeContents();
     method public static android.util.LocaleList forLanguageTags(java.lang.String);
     method public java.util.Locale get(int);
+    method public static android.util.LocaleList getAdjustedDefault();
     method public static android.util.LocaleList getDefault();
     method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getFirstMatch(java.lang.String[]);
@@ -53590,6 +53505,7 @@ package java.lang {
     method public static long doubleToRawLongBits(double);
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(double);
     method public int intValue();
     method public static boolean isInfinite(double);
     method public boolean isInfinite();
@@ -53597,11 +53513,15 @@ package java.lang {
     method public boolean isNaN();
     method public static double longBitsToDouble(long);
     method public long longValue();
+    method public static double max(double, double);
+    method public static double min(double, double);
     method public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+    method public static double sum(double, double);
     method public static java.lang.String toHexString(double);
     method public static java.lang.String toString(double);
     method public static java.lang.Double valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Double valueOf(double);
+    field public static final int BYTES = 8; // 0x8
     field public static final int MAX_EXPONENT = 1023; // 0x3ff
     field public static final double MAX_VALUE = 1.7976931348623157E308;
     field public static final int MIN_EXPONENT = -1022; // 0xfffffc02
@@ -53764,10 +53684,13 @@ package java.lang {
     method public static java.lang.Integer getInteger(java.lang.String);
     method public static java.lang.Integer getInteger(java.lang.String, int);
     method public static java.lang.Integer getInteger(java.lang.String, java.lang.Integer);
+    method public static int hashCode(int);
     method public static int highestOneBit(int);
     method public int intValue();
     method public long longValue();
     method public static int lowestOneBit(int);
+    method public static int max(int, int);
+    method public static int min(int, int);
     method public static int numberOfLeadingZeros(int);
     method public static int numberOfTrailingZeros(int);
     method public static int parseInt(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -53777,6 +53700,7 @@ package java.lang {
     method public static int rotateLeft(int, int);
     method public static int rotateRight(int, int);
     method public static int signum(int);
+    method public static int sum(int, int);
     method public static java.lang.String toBinaryString(int);
     method public static java.lang.String toHexString(int);
     method public static java.lang.String toOctalString(int);
@@ -53785,6 +53709,7 @@ package java.lang {
     method public static java.lang.Integer valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(int);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_VALUE = 2147483647; // 0x7fffffff
     field public static final int MIN_VALUE = -2147483648; // 0x80000000
     field public static final int SIZE = 32; // 0x20
@@ -53804,6 +53729,7 @@ package java.lang {
   }
 
   public abstract interface Iterable {
+    method public default void forEach(java.util.function.Consumer<? super T>);
     method public abstract java.util.Iterator<T> iterator();
   }
 
@@ -53825,10 +53751,13 @@ package java.lang {
     method public static java.lang.Long getLong(java.lang.String);
     method public static java.lang.Long getLong(java.lang.String, long);
     method public static java.lang.Long getLong(java.lang.String, java.lang.Long);
+    method public static int hashCode(long);
     method public static long highestOneBit(long);
     method public int intValue();
     method public long longValue();
     method public static long lowestOneBit(long);
+    method public static long max(long, long);
+    method public static long min(long, long);
     method public static int numberOfLeadingZeros(long);
     method public static int numberOfTrailingZeros(long);
     method public static long parseLong(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -53838,6 +53767,7 @@ package java.lang {
     method public static long rotateLeft(long, int);
     method public static long rotateRight(long, int);
     method public static int signum(long);
+    method public static long sum(long, long);
     method public static java.lang.String toBinaryString(long);
     method public static java.lang.String toHexString(long);
     method public static java.lang.String toOctalString(long);
@@ -57279,6 +57209,7 @@ package java.security {
 
   public abstract class Provider extends java.util.Properties {
     ctor protected Provider(java.lang.String, double, java.lang.String);
+    method public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object, ? super java.lang.Object>);
     method public java.lang.String getInfo();
     method public java.lang.String getName();
     method public synchronized java.security.Provider.Service getService(java.lang.String, java.lang.String);
@@ -60228,6 +60159,7 @@ package java.util {
     ctor public ArrayList(java.util.Collection<? extends E>);
     method public java.lang.Object clone();
     method public void ensureCapacity(int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
     method public int size();
     method public void trimToSize();
@@ -60791,6 +60723,7 @@ package java.util {
     ctor public HashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
   public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
@@ -60815,6 +60748,7 @@ package java.util {
     method public boolean containsValue(java.lang.Object);
     method public synchronized java.util.Enumeration<V> elements();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public synchronized void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public synchronized V get(java.lang.Object);
     method public synchronized boolean isEmpty();
     method public java.util.Set<K> keySet();
@@ -60833,6 +60767,7 @@ package java.util {
     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -60882,9 +60817,10 @@ package java.util {
   }
 
   public abstract interface Iterator {
+    method public default void forEachRemaining(java.util.function.Consumer<? super E>);
     method public abstract boolean hasNext();
     method public abstract E next();
-    method public abstract void remove();
+    method public default void remove();
   }
 
   public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
@@ -61072,6 +61008,7 @@ package java.util {
     method public abstract boolean containsValue(java.lang.Object);
     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public abstract boolean equals(java.lang.Object);
+    method public default void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public abstract V get(java.lang.Object);
     method public abstract int hashCode();
     method public abstract boolean isEmpty();
@@ -61186,6 +61123,79 @@ package java.util {
     method public abstract void update(java.util.Observable, java.lang.Object);
   }
 
+  public final class Optional {
+    method public static java.util.Optional<T> empty();
+    method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
+    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+    method public T get();
+    method public void ifPresent(java.util.function.Consumer<? super T>);
+    method public boolean isPresent();
+    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.Optional<T> of(T);
+    method public static java.util.Optional<T> ofNullable(T);
+    method public T orElse(T);
+    method public T orElseGet(java.util.function.Supplier<? extends T>);
+    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalDouble {
+    method public static java.util.OptionalDouble empty();
+    method public double getAsDouble();
+    method public void ifPresent(java.util.function.DoubleConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalDouble of(double);
+    method public double orElse(double);
+    method public double orElseGet(java.util.function.DoubleSupplier);
+    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalInt {
+    method public static java.util.OptionalInt empty();
+    method public int getAsInt();
+    method public void ifPresent(java.util.function.IntConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalInt of(int);
+    method public int orElse(int);
+    method public int orElseGet(java.util.function.IntSupplier);
+    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalLong {
+    method public static java.util.OptionalLong empty();
+    method public long getAsLong();
+    method public void ifPresent(java.util.function.LongConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalLong of(long);
+    method public long orElse(long);
+    method public long orElseGet(java.util.function.LongSupplier);
+    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public abstract interface PrimitiveIterator implements java.util.Iterator {
+    method public abstract void forEachRemaining(T_CONS);
+  }
+
+  public static abstract interface PrimitiveIterator.OfDouble implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.DoubleConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+    method public default java.lang.Double next();
+    method public abstract double nextDouble();
+  }
+
+  public static abstract interface PrimitiveIterator.OfInt implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.IntConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+    method public default java.lang.Integer next();
+    method public abstract int nextInt();
+  }
+
+  public static abstract interface PrimitiveIterator.OfLong implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.LongConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+    method public default java.lang.Long next();
+    method public abstract long nextLong();
+  }
+
   public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
     ctor public PriorityQueue();
     ctor public PriorityQueue(int);
@@ -61357,7 +61367,6 @@ package java.util {
     method public short nextShort();
     method public short nextShort(int);
     method public int radix();
-    method public void remove();
     method public java.util.Scanner reset();
     method public java.util.Scanner skip(java.util.regex.Pattern);
     method public java.util.Scanner skip(java.lang.String);
@@ -61533,6 +61542,7 @@ package java.util {
     method public K firstKey();
     method public java.util.Map.Entry<K, V> floorEntry(K);
     method public K floorKey(K);
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public java.util.NavigableMap<K, V> headMap(K, boolean);
     method public java.util.SortedMap<K, V> headMap(K);
     method public java.util.Map.Entry<K, V> higherEntry(K);
@@ -61615,6 +61625,7 @@ package java.util {
     method public java.util.Enumeration<E> elements();
     method public synchronized void ensureCapacity(int);
     method public synchronized E firstElement();
+    method public synchronized void forEach(java.util.function.Consumer<? super E>);
     method public synchronized E get(int);
     method public synchronized int indexOf(java.lang.Object, int);
     method public synchronized void insertElementAt(E, int);
@@ -61638,6 +61649,7 @@ package java.util {
     ctor public WeakHashMap();
     ctor public WeakHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
 }
index 7347aa3..9ebc484 100644 (file)
@@ -35,7 +35,7 @@ package android.database {
 
 package android.media {
 
-  public class AudioFormat implements android.os.Parcelable {
+  public final class AudioFormat implements android.os.Parcelable {
     ctor public AudioFormat();
   }
 
index ad3a5e6..f18f4e1 100644 (file)
@@ -2668,6 +2668,8 @@ package android.accessibilityservice {
     field public static final int GLOBAL_ACTION_TOGGLE_SPLIT_SCREEN = 7; // 0x7
     field public static final java.lang.String SERVICE_INTERFACE = "android.accessibilityservice.AccessibilityService";
     field public static final java.lang.String SERVICE_META_DATA = "android.accessibilityservice";
+    field public static final int SHOW_MODE_AUTO = 0; // 0x0
+    field public static final int SHOW_MODE_HIDDEN = 1; // 0x1
   }
 
   public static abstract class AccessibilityService.GestureResultCallback {
@@ -4126,13 +4128,12 @@ package android.app {
     field public java.lang.String serviceDetails;
   }
 
-  public class AutomaticZenRule implements android.os.Parcelable {
+  public final class AutomaticZenRule implements android.os.Parcelable {
     ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
     ctor public AutomaticZenRule(android.os.Parcel);
     method public int describeContents();
     method public android.net.Uri getConditionId();
     method public long getCreationTime();
-    method public java.lang.String getId();
     method public int getInterruptionFilter();
     method public java.lang.String getName();
     method public android.content.ComponentName getOwner();
@@ -5228,14 +5229,14 @@ package android.app {
   }
 
   public class NotificationManager {
-    method public android.app.AutomaticZenRule addAutomaticZenRule(android.app.AutomaticZenRule);
+    method public java.lang.String addAutomaticZenRule(android.app.AutomaticZenRule);
     method public boolean areNotificationsEnabled();
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
     method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
-    method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
+    method public java.util.Map<java.lang.String, android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public int getImportance();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
@@ -5245,7 +5246,7 @@ package android.app {
     method public boolean removeAutomaticZenRule(java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
-    method public boolean updateAutomaticZenRule(android.app.AutomaticZenRule);
+    method public boolean updateAutomaticZenRule(java.lang.String, android.app.AutomaticZenRule);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED = "android.app.action.NOTIFICATION_POLICY_ACCESS_GRANTED_CHANGED";
     field public static final java.lang.String ACTION_NOTIFICATION_POLICY_CHANGED = "android.app.action.NOTIFICATION_POLICY_CHANGED";
@@ -5257,7 +5258,7 @@ package android.app {
   }
 
   public static class NotificationManager.Policy implements android.os.Parcelable {
-    ctor public deprecated NotificationManager.Policy(int, int, int);
+    ctor public NotificationManager.Policy(int, int, int);
     ctor public NotificationManager.Policy(int, int, int, int);
     method public int describeContents();
     method public static java.lang.String priorityCategoriesToString(int);
@@ -5714,6 +5715,7 @@ package android.app {
 
   public class WallpaperManager {
     method public void clear() throws java.io.IOException;
+    method public void clear(int) throws java.io.IOException;
     method public void clearWallpaperOffsets(android.os.IBinder);
     method public void forgetLoadedWallpaper();
     method public android.graphics.drawable.Drawable getBuiltInDrawable();
@@ -6593,7 +6595,7 @@ package android.auditing {
     field public static final int TAG_SYNC_SEND_FILE = 210004; // 0x33454
   }
 
-  public static class SecurityLog.SecurityEvent implements android.os.Parcelable {
+  public static final class SecurityLog.SecurityEvent implements android.os.Parcelable {
     method public int describeContents();
     method public java.lang.Object getData();
     method public int getTag();
@@ -7337,15 +7339,6 @@ package android.bluetooth {
     field public static final int TYPE_SCO = 2; // 0x2
   }
 
-  public class OobData implements android.os.Parcelable {
-    ctor public OobData();
-    method public int describeContents();
-    method public byte[] getSecurityManagerTk();
-    method public void setSecurityManagerTk(byte[]);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.bluetooth.OobData> CREATOR;
-  }
-
 }
 
 package android.bluetooth.le {
@@ -10483,7 +10476,6 @@ package android.database {
     method public boolean hasNext();
     method public java.util.Iterator<android.database.CursorJoiner.Result> iterator();
     method public android.database.CursorJoiner.Result next();
-    method public void remove();
   }
 
   public static final class CursorJoiner.Result extends java.lang.Enum {
@@ -19173,168 +19165,110 @@ package android.location {
 
   public final class GnssClock implements android.os.Parcelable {
     method public int describeContents();
-    method public double getBiasInNs();
-    method public double getBiasUncertaintyInNs();
-    method public double getDriftInNsPerSec();
-    method public double getDriftUncertaintyInNsPerSec();
-    method public long getFullBiasInNs();
+    method public double getBiasNanos();
+    method public double getBiasUncertaintyNanos();
+    method public double getDriftNanosPerSecond();
+    method public double getDriftUncertaintyNanosPerSecond();
+    method public long getFullBiasNanos();
     method public int getHardwareClockDiscontinuityCount();
-    method public short getLeapSecond();
-    method public long getTimeInNs();
-    method public double getTimeUncertaintyInNs();
-    method public boolean hasBiasInNs();
-    method public boolean hasBiasUncertaintyInNs();
-    method public boolean hasDriftInNsPerSec();
-    method public boolean hasDriftUncertaintyInNsPerSec();
-    method public boolean hasFullBiasInNs();
+    method public int getLeapSecond();
+    method public long getTimeNanos();
+    method public double getTimeUncertaintyNanos();
+    method public boolean hasBiasNanos();
+    method public boolean hasBiasUncertaintyNanos();
+    method public boolean hasDriftNanosPerSecond();
+    method public boolean hasDriftUncertaintyNanosPerSecond();
+    method public boolean hasFullBiasNanos();
     method public boolean hasLeapSecond();
-    method public boolean hasTimeUncertaintyInNs();
+    method public boolean hasTimeUncertaintyNanos();
     method public void reset();
-    method public void resetBiasInNs();
-    method public void resetBiasUncertaintyInNs();
-    method public void resetDriftInNsPerSec();
-    method public void resetDriftUncertaintyInNsPerSec();
-    method public void resetFullBiasInNs();
+    method public void resetBiasNanos();
+    method public void resetBiasUncertaintyNanos();
+    method public void resetDriftNanosPerSecond();
+    method public void resetDriftUncertaintyNanosPerSecond();
+    method public void resetFullBiasNanos();
     method public void resetLeapSecond();
-    method public void resetTimeUncertaintyInNs();
+    method public void resetTimeUncertaintyNanos();
     method public void set(android.location.GnssClock);
-    method public void setBiasInNs(double);
-    method public void setBiasUncertaintyInNs(double);
-    method public void setDriftInNsPerSec(double);
-    method public void setDriftUncertaintyInNsPerSec(double);
-    method public void setFullBiasInNs(long);
+    method public void setBiasNanos(double);
+    method public void setBiasUncertaintyNanos(double);
+    method public void setDriftNanosPerSecond(double);
+    method public void setDriftUncertaintyNanosPerSecond(double);
+    method public void setFullBiasNanos(long);
     method public void setHardwareClockDiscontinuityCount(int);
-    method public void setLeapSecond(short);
-    method public void setTimeInNs(long);
-    method public void setTimeUncertaintyInNs(double);
+    method public void setLeapSecond(int);
+    method public void setTimeNanos(long);
+    method public void setTimeUncertaintyNanos(double);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssClock> CREATOR;
   }
 
   public final class GnssMeasurement implements android.os.Parcelable {
     method public int describeContents();
-    method public double getAccumulatedDeltaRangeInMeters();
-    method public short getAccumulatedDeltaRangeState();
-    method public double getAccumulatedDeltaRangeUncertaintyInMeters();
-    method public double getAzimuthInDeg();
-    method public double getAzimuthUncertaintyInDeg();
-    method public int getBitNumber();
+    method public double getAccumulatedDeltaRangeMeters();
+    method public int getAccumulatedDeltaRangeState();
+    method public double getAccumulatedDeltaRangeUncertaintyMeters();
     method public long getCarrierCycles();
-    method public float getCarrierFrequencyInHz();
+    method public float getCarrierFrequencyHz();
     method public double getCarrierPhase();
     method public double getCarrierPhaseUncertainty();
-    method public double getCn0InDbHz();
-    method public double getCodePhaseInChips();
-    method public double getCodePhaseUncertaintyInChips();
-    method public byte getConstellationType();
-    method public double getDopplerShiftInHz();
-    method public double getDopplerShiftUncertaintyInHz();
-    method public double getElevationInDeg();
-    method public double getElevationUncertaintyInDeg();
-    method public byte getLossOfLock();
-    method public byte getMultipathIndicator();
-    method public double getPseudorangeInMeters();
-    method public double getPseudorangeRateInMetersPerSec();
-    method public double getPseudorangeRateUncertaintyInMetersPerSec();
-    method public double getPseudorangeUncertaintyInMeters();
-    method public long getReceivedSvTimeInNs();
-    method public long getReceivedSvTimeUncertaintyInNs();
+    method public double getCn0DbHz();
+    method public int getConstellationType();
+    method public int getMultipathIndicator();
+    method public double getPseudorangeRateMetersPerSecond();
+    method public double getPseudorangeRateUncertaintyMetersPerSecond();
+    method public long getReceivedSvTimeNanos();
+    method public long getReceivedSvTimeUncertaintyNanos();
     method public double getSnrInDb();
-    method public short getState();
-    method public short getSvid();
-    method public short getTimeFromLastBitInMs();
-    method public double getTimeOffsetInNs();
-    method public boolean hasAzimuthInDeg();
-    method public boolean hasAzimuthUncertaintyInDeg();
-    method public boolean hasBitNumber();
+    method public int getState();
+    method public int getSvid();
+    method public double getTimeOffsetNanos();
     method public boolean hasCarrierCycles();
-    method public boolean hasCarrierFrequencyInHz();
+    method public boolean hasCarrierFrequencyHz();
     method public boolean hasCarrierPhase();
     method public boolean hasCarrierPhaseUncertainty();
-    method public boolean hasCodePhaseInChips();
-    method public boolean hasCodePhaseUncertaintyInChips();
-    method public boolean hasDopplerShiftInHz();
-    method public boolean hasDopplerShiftUncertaintyInHz();
-    method public boolean hasElevationInDeg();
-    method public boolean hasElevationUncertaintyInDeg();
-    method public boolean hasPseudorangeInMeters();
-    method public boolean hasPseudorangeUncertaintyInMeters();
     method public boolean hasSnrInDb();
-    method public boolean hasTimeFromLastBitInMs();
     method public boolean isPseudorangeRateCorrected();
-    method public boolean isUsedInFix();
     method public void reset();
-    method public void resetAzimuthInDeg();
-    method public void resetAzimuthUncertaintyInDeg();
-    method public void resetBitNumber();
     method public void resetCarrierCycles();
-    method public void resetCarrierFrequencyInHz();
+    method public void resetCarrierFrequencyHz();
     method public void resetCarrierPhase();
     method public void resetCarrierPhaseUncertainty();
-    method public void resetCodePhaseInChips();
-    method public void resetCodePhaseUncertaintyInChips();
-    method public void resetDopplerShiftInHz();
-    method public void resetDopplerShiftUncertaintyInHz();
-    method public void resetElevationInDeg();
-    method public void resetElevationUncertaintyInDeg();
-    method public void resetPseudorangeInMeters();
-    method public void resetPseudorangeUncertaintyInMeters();
     method public void resetSnrInDb();
-    method public void resetTimeFromLastBitInMs();
     method public void set(android.location.GnssMeasurement);
-    method public void setAccumulatedDeltaRangeInMeters(double);
-    method public void setAccumulatedDeltaRangeState(short);
-    method public void setAccumulatedDeltaRangeUncertaintyInMeters(double);
-    method public void setAzimuthInDeg(double);
-    method public void setAzimuthUncertaintyInDeg(double);
-    method public void setBitNumber(int);
+    method public void setAccumulatedDeltaRangeMeters(double);
+    method public void setAccumulatedDeltaRangeState(int);
+    method public void setAccumulatedDeltaRangeUncertaintyMeters(double);
     method public void setCarrierCycles(long);
-    method public void setCarrierFrequencyInHz(float);
+    method public void setCarrierFrequencyHz(float);
     method public void setCarrierPhase(double);
     method public void setCarrierPhaseUncertainty(double);
-    method public void setCn0InDbHz(double);
-    method public void setCodePhaseInChips(double);
-    method public void setCodePhaseUncertaintyInChips(double);
-    method public void setConstellationType(byte);
-    method public void setDopplerShiftInHz(double);
-    method public void setDopplerShiftUncertaintyInHz(double);
-    method public void setElevationInDeg(double);
-    method public void setElevationUncertaintyInDeg(double);
-    method public void setLossOfLock(byte);
-    method public void setMultipathIndicator(byte);
-    method public void setPseudorangeInMeters(double);
-    method public void setPseudorangeRateInMetersPerSec(double);
-    method public void setPseudorangeRateUncertaintyInMetersPerSec(double);
-    method public void setPseudorangeUncertaintyInMeters(double);
-    method public void setReceivedSvTimeInNs(long);
-    method public void setReceivedSvTimeUncertaintyInNs(long);
+    method public void setCn0DbHz(double);
+    method public void setConstellationType(int);
+    method public void setMultipathIndicator(int);
+    method public void setPseudorangeRateMetersPerSecond(double);
+    method public void setPseudorangeRateUncertaintyMetersPerSecond(double);
+    method public void setReceivedSvTimeNanos(long);
+    method public void setReceivedSvTimeUncertaintyNanos(long);
     method public void setSnrInDb(double);
-    method public void setState(short);
-    method public void setSvid(short);
-    method public void setTimeFromLastBitInMs(short);
-    method public void setTimeOffsetInNs(double);
-    method public void setUsedInFix(boolean);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final short ADR_STATE_CYCLE_SLIP = 4; // 0x4
-    field public static final short ADR_STATE_RESET = 2; // 0x2
-    field public static final short ADR_STATE_UNKNOWN = 0; // 0x0
-    field public static final short ADR_STATE_VALID = 1; // 0x1
+    method public void setState(int);
+    method public void setSvid(int);
+    method public void setTimeOffsetNanos(double);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final int ADR_STATE_CYCLE_SLIP = 4; // 0x4
+    field public static final int ADR_STATE_RESET = 2; // 0x2
+    field public static final int ADR_STATE_UNKNOWN = 0; // 0x0
+    field public static final int ADR_STATE_VALID = 1; // 0x1
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurement> CREATOR;
-    field public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2; // 0x2
-    field public static final byte LOSS_OF_LOCK_OK = 1; // 0x1
-    field public static final byte LOSS_OF_LOCK_UNKNOWN = 0; // 0x0
-    field public static final byte MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
-    field public static final byte MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
-    field public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
-    field public static final short STATE_BIT_SYNC = 2; // 0x2
-    field public static final short STATE_CODE_LOCK = 1; // 0x1
-    field public static final short STATE_MSEC_AMBIGUOUS = 16; // 0x10
-    field public static final short STATE_SUBFRAME_SYNC = 4; // 0x4
-    field public static final short STATE_TOW_DECODED = 8; // 0x8
-    field public static final short STATE_UNKNOWN = 0; // 0x0
-  }
-
-  public static abstract class GnssMeasurement.LossOfLockStatus implements java.lang.annotation.Annotation {
+    field public static final int MULTIPATH_INDICATOR_DETECTED = 1; // 0x1
+    field public static final int MULTIPATH_INDICATOR_NOT_USED = 2; // 0x2
+    field public static final int MULTIPATH_INDICATOR_UNKNOWN = 0; // 0x0
+    field public static final int STATE_BIT_SYNC = 2; // 0x2
+    field public static final int STATE_CODE_LOCK = 1; // 0x1
+    field public static final int STATE_MSEC_AMBIGUOUS = 16; // 0x10
+    field public static final int STATE_SUBFRAME_SYNC = 4; // 0x4
+    field public static final int STATE_TOW_DECODED = 8; // 0x8
+    field public static final int STATE_UNKNOWN = 0; // 0x0
   }
 
   public static abstract class GnssMeasurement.MultipathIndicator implements java.lang.annotation.Annotation {
@@ -19347,7 +19281,7 @@ package android.location {
     method public java.util.Collection<android.location.GnssMeasurement> getMeasurements();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssMeasurementsEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -19364,34 +19298,34 @@ package android.location {
   public final class GnssNavigationMessage implements android.os.Parcelable {
     method public int describeContents();
     method public byte[] getData();
-    method public short getMessageId();
-    method public short getStatus();
-    method public short getSubmessageId();
-    method public short getSvid();
-    method public short getType();
+    method public int getMessageId();
+    method public int getStatus();
+    method public int getSubmessageId();
+    method public int getSvid();
+    method public int getType();
     method public void reset();
     method public void set(android.location.GnssNavigationMessage);
     method public void setData(byte[]);
-    method public void setMessageId(short);
-    method public void setStatus(short);
-    method public void setSubmessageId(short);
-    method public void setSvid(short);
-    method public void setType(short);
+    method public void setMessageId(int);
+    method public void setStatus(int);
+    method public void setSubmessageId(int);
+    method public void setSvid(int);
+    method public void setType(int);
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessage> CREATOR;
-    field public static final short MESSAGE_TYPE_BDS_D1 = 1281; // 0x501
-    field public static final short MESSAGE_TYPE_BDS_D2 = 1282; // 0x502
-    field public static final short MESSAGE_TYPE_GAL_F = 1538; // 0x602
-    field public static final short MESSAGE_TYPE_GAL_I = 1537; // 0x601
-    field public static final short MESSAGE_TYPE_GLO_L1CA = 769; // 0x301
-    field public static final short MESSAGE_TYPE_GPS_CNAV2 = 260; // 0x104
-    field public static final short MESSAGE_TYPE_GPS_L1CA = 257; // 0x101
-    field public static final short MESSAGE_TYPE_GPS_L2CNAV = 258; // 0x102
-    field public static final short MESSAGE_TYPE_GPS_L5CNAV = 259; // 0x103
-    field public static final short MESSAGE_TYPE_UNKNOWN = 0; // 0x0
-    field public static final short STATUS_PARITY_PASSED = 1; // 0x1
-    field public static final short STATUS_PARITY_REBUILT = 2; // 0x2
-    field public static final short STATUS_UNKNOWN = 0; // 0x0
+    field public static final int STATUS_PARITY_PASSED = 1; // 0x1
+    field public static final int STATUS_PARITY_REBUILT = 2; // 0x2
+    field public static final int STATUS_UNKNOWN = 0; // 0x0
+    field public static final int TYPE_BDS_D1 = 1281; // 0x501
+    field public static final int TYPE_BDS_D2 = 1282; // 0x502
+    field public static final int TYPE_GAL_F = 1538; // 0x602
+    field public static final int TYPE_GAL_I = 1537; // 0x601
+    field public static final int TYPE_GLO_L1CA = 769; // 0x301
+    field public static final int TYPE_GPS_CNAV2 = 260; // 0x104
+    field public static final int TYPE_GPS_L1CA = 257; // 0x101
+    field public static final int TYPE_GPS_L2CNAV = 258; // 0x102
+    field public static final int TYPE_GPS_L5CNAV = 259; // 0x103
+    field public static final int TYPE_UNKNOWN = 0; // 0x0
   }
 
   public static abstract class GnssNavigationMessage.GnssNavigationMessageType implements java.lang.annotation.Annotation {
@@ -19403,7 +19337,7 @@ package android.location {
     method public android.location.GnssNavigationMessage getNavigationMessage();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.location.GnssNavigationMessageEvent> CREATOR;
-    field public static final int STATUS_GPS_LOCATION_DISABLED = 2; // 0x2
+    field public static final int STATUS_GNSS_LOCATION_DISABLED = 2; // 0x2
     field public static final int STATUS_NOT_SUPPORTED = 0; // 0x0
     field public static final int STATUS_READY = 1; // 0x1
   }
@@ -19422,22 +19356,22 @@ package android.location {
   }
 
   public final class GnssStatus {
-    method public float getAzimuth(int);
-    method public byte getConstellationType(int);
-    method public float getElevation(int);
+    method public float getAzimuthDegrees(int);
+    method public float getCn0DbHz(int);
+    method public int getConstellationType(int);
+    method public float getElevationDegrees(int);
     method public int getNumSatellites();
-    method public float getSnr(int);
     method public int getSvid(int);
     method public boolean hasAlmanac(int);
     method public boolean hasEphemeris(int);
     method public boolean usedInFix(int);
-    field public static final byte CONSTELLATION_BEIDOU = 5; // 0x5
-    field public static final byte CONSTELLATION_GALILEO = 6; // 0x6
-    field public static final byte CONSTELLATION_GLONASS = 3; // 0x3
-    field public static final byte CONSTELLATION_GPS = 1; // 0x1
-    field public static final byte CONSTELLATION_QZSS = 4; // 0x4
-    field public static final byte CONSTELLATION_SBAS = 2; // 0x2
-    field public static final byte CONSTELLATION_UNKNOWN = 0; // 0x0
+    field public static final int CONSTELLATION_BEIDOU = 5; // 0x5
+    field public static final int CONSTELLATION_GALILEO = 6; // 0x6
+    field public static final int CONSTELLATION_GLONASS = 3; // 0x3
+    field public static final int CONSTELLATION_GPS = 1; // 0x1
+    field public static final int CONSTELLATION_QZSS = 4; // 0x4
+    field public static final int CONSTELLATION_SBAS = 2; // 0x2
+    field public static final int CONSTELLATION_UNKNOWN = 0; // 0x0
   }
 
   public static abstract class GnssStatus.ConstellationType implements java.lang.annotation.Annotation {
@@ -19553,8 +19487,8 @@ package android.location {
     method public java.util.List<java.lang.String> getProviders(boolean);
     method public java.util.List<java.lang.String> getProviders(android.location.Criteria, boolean);
     method public boolean isProviderEnabled(java.lang.String);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
-    method public boolean registerGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public boolean registerGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback, android.os.Handler);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public boolean registerGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback, android.os.Handler);
     method public boolean registerGnssStatusCallback(android.location.GnssStatusCallback);
@@ -19579,7 +19513,7 @@ package android.location {
     method public void setTestProviderEnabled(java.lang.String, boolean);
     method public void setTestProviderLocation(java.lang.String, android.location.Location);
     method public void setTestProviderStatus(java.lang.String, int, android.os.Bundle, long);
-    method public void unregisterGnssMeasurementCallback(android.location.GnssMeasurementsEvent.Callback);
+    method public void unregisterGnssMeasurementsCallback(android.location.GnssMeasurementsEvent.Callback);
     method public void unregisterGnssNavigationMessageCallback(android.location.GnssNavigationMessageEvent.Callback);
     method public void unregisterGnssStatusCallback(android.location.GnssStatusCallback);
     field public static final java.lang.String GPS_PROVIDER = "gps";
@@ -19717,7 +19651,7 @@ package android.media {
     field public static final int TYPE_WIRED_HEADSET = 3; // 0x3
   }
 
-  public class AudioFormat implements android.os.Parcelable {
+  public final class AudioFormat implements android.os.Parcelable {
     method public int describeContents();
     method public int getChannelCount();
     method public int getChannelIndexMask();
@@ -19943,7 +19877,7 @@ package android.media {
 
   public static abstract class AudioManager.AudioRecordingCallback {
     ctor public AudioManager.AudioRecordingCallback();
-    method public void onRecordConfigChanged();
+    method public void onRecordConfigChanged(android.media.AudioRecordConfiguration[]);
   }
 
   public static abstract interface AudioManager.OnAudioFocusChangeListener {
@@ -20017,7 +19951,7 @@ package android.media {
     method public abstract void onRoutingChanged(android.media.AudioRecord);
   }
 
-  public class AudioRecordConfiguration implements android.os.Parcelable {
+  public final class AudioRecordConfiguration implements android.os.Parcelable {
     method public int describeContents();
     method public android.media.AudioDeviceInfo getAudioDevice();
     method public int getClientAudioSessionId();
@@ -20669,6 +20603,7 @@ package android.media {
     field public static final int HEVCMainTierLevel62 = 16777216; // 0x1000000
     field public static final int HEVCProfileMain = 1; // 0x1
     field public static final int HEVCProfileMain10 = 2; // 0x2
+    field public static final int HEVCProfileMain10HDR10 = 4096; // 0x1000
     field public static final int MPEG2LevelH14 = 2; // 0x2
     field public static final int MPEG2LevelHL = 3; // 0x3
     field public static final int MPEG2LevelLL = 0; // 0x0
@@ -21010,6 +20945,7 @@ package android.media {
     field public static final java.lang.String KEY_SLICE_HEIGHT = "slice-height";
     field public static final java.lang.String KEY_STRIDE = "stride";
     field public static final java.lang.String KEY_TEMPORAL_LAYERING = "ts-schema";
+    field public static final java.lang.String KEY_TRACK_ID = "track-id";
     field public static final java.lang.String KEY_WIDTH = "width";
     field public static final java.lang.String MIMETYPE_AUDIO_AAC = "audio/mp4a-latm";
     field public static final java.lang.String MIMETYPE_AUDIO_AC3 = "audio/ac3";
@@ -22985,7 +22921,7 @@ package android.media.tv {
   }
 
   public static final class TvInputInfo.Builder {
-    ctor public TvInputInfo.Builder(android.content.Context, java.lang.Class<?>);
+    ctor public TvInputInfo.Builder(android.content.Context, android.content.ComponentName);
     method public android.media.tv.TvInputInfo build() throws java.io.IOException, org.xmlpull.v1.XmlPullParserException;
     method public android.media.tv.TvInputInfo.Builder setCanRecord(boolean);
     method public android.media.tv.TvInputInfo.Builder setTunerCount(int);
@@ -23053,7 +22989,7 @@ package android.media.tv {
     ctor public TvInputService.RecordingSession(android.content.Context);
     method public void notifyError(int);
     method public void notifyRecordingStopped(android.net.Uri);
-    method public void notifyTuned();
+    method public void notifyTuned(android.net.Uri);
     method public abstract void onRelease();
     method public abstract void onStartRecording(android.net.Uri);
     method public abstract void onStopRecording();
@@ -23112,7 +23048,7 @@ package android.media.tv {
     method public void onDisconnected(java.lang.String);
     method public void onError(int);
     method public void onRecordingStopped(android.net.Uri);
-    method public void onTuned();
+    method public void onTuned(android.net.Uri);
   }
 
   public final class TvTrackInfo implements android.os.Parcelable {
@@ -23532,17 +23468,6 @@ package android.net {
     method public abstract void onNetworkActive();
   }
 
-  public class ConnectivityMetricsEvent implements android.os.Parcelable {
-    ctor public ConnectivityMetricsEvent(long, int, int, android.os.Parcelable);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.ConnectivityMetricsEvent> CREATOR;
-    field public final int componentTag;
-    field public final android.os.Parcelable data;
-    field public final int eventTag;
-    field public final long timestamp;
-  }
-
   public class Credentials {
     ctor public Credentials(int, int, int);
     method public int getGid();
@@ -23550,7 +23475,7 @@ package android.net {
     method public int getUid();
   }
 
-  public class DataUsageRequest implements android.os.Parcelable {
+  public final class DataUsageRequest implements android.os.Parcelable {
     method public int describeContents();
     method public void writeToParcel(android.os.Parcel, int);
     field public static final android.os.Parcelable.Creator<android.net.DataUsageRequest> CREATOR;
@@ -26868,7 +26793,8 @@ package android.opengl {
     method public static void glGetSynciv(long, int, int, int[], int, int[], int);
     method public static void glGetSynciv(long, int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static void glGetTransformFeedbackVarying(int, int, int, int[], int, int[], int, int[], int, byte[], int);
-    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static deprecated void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, byte);
+    method public static void glGetTransformFeedbackVarying(int, int, int, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.IntBuffer, java.nio.ByteBuffer);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, int[], int, int[], int);
     method public static java.lang.String glGetTransformFeedbackVarying(int, int, java.nio.IntBuffer, java.nio.IntBuffer);
     method public static int glGetUniformBlockIndex(int, java.lang.String);
@@ -29132,6 +29058,8 @@ package android.os {
     ctor public Process();
     method public static final long getElapsedCpuTime();
     method public static final int getGidForName(java.lang.String);
+    method public static final long getStartElapsedRealtime();
+    method public static final long getStartUptimeMillis();
     method public static final int getThreadPriority(int) throws java.lang.IllegalArgumentException;
     method public static final int getUidForName(java.lang.String);
     method public static final boolean is64Bit();
@@ -29438,7 +29366,7 @@ package android.os.storage {
     method public boolean unmountObb(java.lang.String, boolean, android.os.storage.OnObbStateChangeListener);
   }
 
-  public class StorageVolume implements android.os.Parcelable {
+  public final class StorageVolume implements android.os.Parcelable {
     method public android.content.Intent createAccessIntent(java.lang.String);
     method public int describeContents();
     method public java.lang.String getDescription(android.content.Context);
@@ -30274,7 +30202,7 @@ package android.provider {
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_ORIGINAL_NUMBER = "original_number";
     field public static final java.lang.String CONTENT_ITEM_TYPE = "vnd.android.cursor.item/blocked_number";
-    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+    field public static final java.lang.String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number";
     field public static final android.net.Uri CONTENT_URI;
   }
 
@@ -31801,6 +31729,7 @@ package android.provider {
 
   public static final class DocumentsContract.Root {
     field public static final java.lang.String COLUMN_AVAILABLE_BYTES = "available_bytes";
+    field public static final java.lang.String COLUMN_CAPACITY_BYTES = "capacity_bytes";
     field public static final java.lang.String COLUMN_DOCUMENT_ID = "document_id";
     field public static final java.lang.String COLUMN_FLAGS = "flags";
     field public static final java.lang.String COLUMN_ICON = "icon";
@@ -34325,7 +34254,8 @@ package android.service.carrier {
     ctor public CarrierMessagingService();
     method public android.os.IBinder onBind(android.content.Intent);
     method public void onDownloadMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
-    method public void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public deprecated void onFilterSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Boolean>);
+    method public void onReceiveTextSms(android.service.carrier.MessagePdu, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<java.lang.Integer>);
     method public deprecated void onSendDataSms(byte[], int, java.lang.String, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendDataSms(byte[], int, java.lang.String, int, int, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendSmsResult>);
     method public void onSendMms(android.net.Uri, int, android.net.Uri, android.service.carrier.CarrierMessagingService.ResultCallback<android.service.carrier.CarrierMessagingService.SendMmsResult>);
@@ -34336,6 +34266,9 @@ package android.service.carrier {
     field public static final int DOWNLOAD_STATUS_ERROR = 2; // 0x2
     field public static final int DOWNLOAD_STATUS_OK = 0; // 0x0
     field public static final int DOWNLOAD_STATUS_RETRY_ON_CARRIER_NETWORK = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_DEFAULT = 0; // 0x0
+    field public static final int RECEIVE_OPTIONS_DROP = 1; // 0x1
+    field public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 2; // 0x2
     field public static final int SEND_FLAG_REQUEST_DELIVERY_STATUS = 1; // 0x1
     field public static final int SEND_STATUS_ERROR = 2; // 0x2
     field public static final int SEND_STATUS_OK = 0; // 0x0
@@ -34567,7 +34500,7 @@ package android.service.notification {
     method public void onNotificationRemoved(android.service.notification.StatusBarNotification, android.service.notification.NotificationListenerService.RankingMap);
     method public final void requestInterruptionFilter(int);
     method public final void requestListenerHints(int);
-    method public static final void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
+    method public static void requestRebind(android.content.ComponentName) throws android.os.RemoteException;
     method public final void requestUnbind() throws android.os.RemoteException;
     method public final void setNotificationsShown(java.lang.String[]);
     field public static final java.lang.String CATEGORY_VR_NOTIFICATIONS = "android.intent.category.vr.notifications";
@@ -36447,7 +36380,7 @@ package android.telecom {
     method public boolean handleMmi(java.lang.String, android.telecom.PhoneAccountHandle);
     method public boolean isInCall();
     method public boolean isVoiceMailNumber(android.telecom.PhoneAccountHandle, java.lang.String);
-    method public void launchManageBlockedNumbersActivity();
+    method public deprecated void launchManageBlockedNumbersActivity();
     method public void placeCall(android.net.Uri, android.os.Bundle);
     method public void registerPhoneAccount(android.telecom.PhoneAccount);
     method public void showInCallScreen(boolean);
@@ -38564,7 +38497,6 @@ package android.text {
     method public boolean hasNext();
     method public java.util.Iterator<java.lang.String> iterator();
     method public java.lang.String next();
-    method public void remove();
     method public void setString(java.lang.String);
   }
 
@@ -40176,6 +40108,7 @@ package android.util {
     method public int describeContents();
     method public static android.util.LocaleList forLanguageTags(java.lang.String);
     method public java.util.Locale get(int);
+    method public static android.util.LocaleList getAdjustedDefault();
     method public static android.util.LocaleList getDefault();
     method public static android.util.LocaleList getEmptyLocaleList();
     method public java.util.Locale getFirstMatch(java.lang.String[]);
@@ -50487,6 +50420,7 @@ package java.lang {
     method public static long doubleToRawLongBits(double);
     method public double doubleValue();
     method public float floatValue();
+    method public static int hashCode(double);
     method public int intValue();
     method public static boolean isInfinite(double);
     method public boolean isInfinite();
@@ -50494,11 +50428,15 @@ package java.lang {
     method public boolean isNaN();
     method public static double longBitsToDouble(long);
     method public long longValue();
+    method public static double max(double, double);
+    method public static double min(double, double);
     method public static double parseDouble(java.lang.String) throws java.lang.NumberFormatException;
+    method public static double sum(double, double);
     method public static java.lang.String toHexString(double);
     method public static java.lang.String toString(double);
     method public static java.lang.Double valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Double valueOf(double);
+    field public static final int BYTES = 8; // 0x8
     field public static final int MAX_EXPONENT = 1023; // 0x3ff
     field public static final double MAX_VALUE = 1.7976931348623157E308;
     field public static final int MIN_EXPONENT = -1022; // 0xfffffc02
@@ -50661,10 +50599,13 @@ package java.lang {
     method public static java.lang.Integer getInteger(java.lang.String);
     method public static java.lang.Integer getInteger(java.lang.String, int);
     method public static java.lang.Integer getInteger(java.lang.String, java.lang.Integer);
+    method public static int hashCode(int);
     method public static int highestOneBit(int);
     method public int intValue();
     method public long longValue();
     method public static int lowestOneBit(int);
+    method public static int max(int, int);
+    method public static int min(int, int);
     method public static int numberOfLeadingZeros(int);
     method public static int numberOfTrailingZeros(int);
     method public static int parseInt(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50674,6 +50615,7 @@ package java.lang {
     method public static int rotateLeft(int, int);
     method public static int rotateRight(int, int);
     method public static int signum(int);
+    method public static int sum(int, int);
     method public static java.lang.String toBinaryString(int);
     method public static java.lang.String toHexString(int);
     method public static java.lang.String toOctalString(int);
@@ -50682,6 +50624,7 @@ package java.lang {
     method public static java.lang.Integer valueOf(java.lang.String, int) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(java.lang.String) throws java.lang.NumberFormatException;
     method public static java.lang.Integer valueOf(int);
+    field public static final int BYTES = 4; // 0x4
     field public static final int MAX_VALUE = 2147483647; // 0x7fffffff
     field public static final int MIN_VALUE = -2147483648; // 0x80000000
     field public static final int SIZE = 32; // 0x20
@@ -50701,6 +50644,7 @@ package java.lang {
   }
 
   public abstract interface Iterable {
+    method public default void forEach(java.util.function.Consumer<? super T>);
     method public abstract java.util.Iterator<T> iterator();
   }
 
@@ -50722,10 +50666,13 @@ package java.lang {
     method public static java.lang.Long getLong(java.lang.String);
     method public static java.lang.Long getLong(java.lang.String, long);
     method public static java.lang.Long getLong(java.lang.String, java.lang.Long);
+    method public static int hashCode(long);
     method public static long highestOneBit(long);
     method public int intValue();
     method public long longValue();
     method public static long lowestOneBit(long);
+    method public static long max(long, long);
+    method public static long min(long, long);
     method public static int numberOfLeadingZeros(long);
     method public static int numberOfTrailingZeros(long);
     method public static long parseLong(java.lang.String, int) throws java.lang.NumberFormatException;
@@ -50735,6 +50682,7 @@ package java.lang {
     method public static long rotateLeft(long, int);
     method public static long rotateRight(long, int);
     method public static int signum(long);
+    method public static long sum(long, long);
     method public static java.lang.String toBinaryString(long);
     method public static java.lang.String toHexString(long);
     method public static java.lang.String toOctalString(long);
@@ -54176,6 +54124,7 @@ package java.security {
 
   public abstract class Provider extends java.util.Properties {
     ctor protected Provider(java.lang.String, double, java.lang.String);
+    method public synchronized void forEach(java.util.function.BiConsumer<? super java.lang.Object, ? super java.lang.Object>);
     method public java.lang.String getInfo();
     method public java.lang.String getName();
     method public synchronized java.security.Provider.Service getService(java.lang.String, java.lang.String);
@@ -57125,6 +57074,7 @@ package java.util {
     ctor public ArrayList(java.util.Collection<? extends E>);
     method public java.lang.Object clone();
     method public void ensureCapacity(int);
+    method public void forEach(java.util.function.Consumer<? super E>);
     method public E get(int);
     method public int size();
     method public void trimToSize();
@@ -57688,6 +57638,7 @@ package java.util {
     ctor public HashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
   public class HashSet extends java.util.AbstractSet implements java.lang.Cloneable java.io.Serializable java.util.Set {
@@ -57712,6 +57663,7 @@ package java.util {
     method public boolean containsValue(java.lang.Object);
     method public synchronized java.util.Enumeration<V> elements();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public synchronized void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public synchronized V get(java.lang.Object);
     method public synchronized boolean isEmpty();
     method public java.util.Set<K> keySet();
@@ -57730,6 +57682,7 @@ package java.util {
     ctor public IdentityHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -57779,9 +57732,10 @@ package java.util {
   }
 
   public abstract interface Iterator {
+    method public default void forEachRemaining(java.util.function.Consumer<? super E>);
     method public abstract boolean hasNext();
     method public abstract E next();
-    method public abstract void remove();
+    method public default void remove();
   }
 
   public class LinkedHashMap extends java.util.HashMap implements java.util.Map {
@@ -57969,6 +57923,7 @@ package java.util {
     method public abstract boolean containsValue(java.lang.Object);
     method public abstract java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public abstract boolean equals(java.lang.Object);
+    method public default void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public abstract V get(java.lang.Object);
     method public abstract int hashCode();
     method public abstract boolean isEmpty();
@@ -58083,6 +58038,79 @@ package java.util {
     method public abstract void update(java.util.Observable, java.lang.Object);
   }
 
+  public final class Optional {
+    method public static java.util.Optional<T> empty();
+    method public java.util.Optional<T> filter(java.util.function.Predicate<? super T>);
+    method public java.util.Optional<U> flatMap(java.util.function.Function<? super T, java.util.Optional<U>>);
+    method public T get();
+    method public void ifPresent(java.util.function.Consumer<? super T>);
+    method public boolean isPresent();
+    method public java.util.Optional<U> map(java.util.function.Function<? super T, ? extends U>);
+    method public static java.util.Optional<T> of(T);
+    method public static java.util.Optional<T> ofNullable(T);
+    method public T orElse(T);
+    method public T orElseGet(java.util.function.Supplier<? extends T>);
+    method public T orElseThrow(java.util.function.Supplier<? extends X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalDouble {
+    method public static java.util.OptionalDouble empty();
+    method public double getAsDouble();
+    method public void ifPresent(java.util.function.DoubleConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalDouble of(double);
+    method public double orElse(double);
+    method public double orElseGet(java.util.function.DoubleSupplier);
+    method public double orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalInt {
+    method public static java.util.OptionalInt empty();
+    method public int getAsInt();
+    method public void ifPresent(java.util.function.IntConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalInt of(int);
+    method public int orElse(int);
+    method public int orElseGet(java.util.function.IntSupplier);
+    method public int orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public final class OptionalLong {
+    method public static java.util.OptionalLong empty();
+    method public long getAsLong();
+    method public void ifPresent(java.util.function.LongConsumer);
+    method public boolean isPresent();
+    method public static java.util.OptionalLong of(long);
+    method public long orElse(long);
+    method public long orElseGet(java.util.function.LongSupplier);
+    method public long orElseThrow(java.util.function.Supplier<X>) throws java.lang.Throwable;
+  }
+
+  public abstract interface PrimitiveIterator implements java.util.Iterator {
+    method public abstract void forEachRemaining(T_CONS);
+  }
+
+  public static abstract interface PrimitiveIterator.OfDouble implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.DoubleConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Double>);
+    method public default java.lang.Double next();
+    method public abstract double nextDouble();
+  }
+
+  public static abstract interface PrimitiveIterator.OfInt implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.IntConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Integer>);
+    method public default java.lang.Integer next();
+    method public abstract int nextInt();
+  }
+
+  public static abstract interface PrimitiveIterator.OfLong implements java.util.PrimitiveIterator {
+    method public default void forEachRemaining(java.util.function.LongConsumer);
+    method public default void forEachRemaining(java.util.function.Consumer<? super java.lang.Long>);
+    method public default java.lang.Long next();
+    method public abstract long nextLong();
+  }
+
   public class PriorityQueue extends java.util.AbstractQueue implements java.io.Serializable {
     ctor public PriorityQueue();
     ctor public PriorityQueue(int);
@@ -58254,7 +58282,6 @@ package java.util {
     method public short nextShort();
     method public short nextShort(int);
     method public int radix();
-    method public void remove();
     method public java.util.Scanner reset();
     method public java.util.Scanner skip(java.util.regex.Pattern);
     method public java.util.Scanner skip(java.lang.String);
@@ -58430,6 +58457,7 @@ package java.util {
     method public K firstKey();
     method public java.util.Map.Entry<K, V> floorEntry(K);
     method public K floorKey(K);
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
     method public java.util.NavigableMap<K, V> headMap(K, boolean);
     method public java.util.SortedMap<K, V> headMap(K);
     method public java.util.Map.Entry<K, V> higherEntry(K);
@@ -58512,6 +58540,7 @@ package java.util {
     method public java.util.Enumeration<E> elements();
     method public synchronized void ensureCapacity(int);
     method public synchronized E firstElement();
+    method public synchronized void forEach(java.util.function.Consumer<? super E>);
     method public synchronized E get(int);
     method public synchronized int indexOf(java.lang.Object, int);
     method public synchronized void insertElementAt(E, int);
@@ -58535,6 +58564,7 @@ package java.util {
     ctor public WeakHashMap();
     ctor public WeakHashMap(java.util.Map<? extends K, ? extends V>);
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
+    method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
   }
 
 }
index 50a24f6..115224c 100644 (file)
@@ -37,7 +37,7 @@ package android.database {
 
 package android.media {
 
-  public class AudioFormat implements android.os.Parcelable {
+  public final class AudioFormat implements android.os.Parcelable {
     ctor public AudioFormat();
   }
 
index eedb82b..fea6f0e 100644 (file)
@@ -606,7 +606,7 @@ public class Am extends BaseCommand {
                             new File(mProfileFile),
                             ParcelFileDescriptor.MODE_CREATE |
                             ParcelFileDescriptor.MODE_TRUNCATE |
-                            ParcelFileDescriptor.MODE_READ_WRITE);
+                            ParcelFileDescriptor.MODE_WRITE_ONLY);
                 } catch (FileNotFoundException e) {
                     System.err.println("Error: Unable to open file: " + mProfileFile);
                     System.err.println("Consider using a file under /data/local/tmp/");
@@ -903,7 +903,7 @@ public class Am extends BaseCommand {
             fd = openForSystemServer(file,
                     ParcelFileDescriptor.MODE_CREATE |
                             ParcelFileDescriptor.MODE_TRUNCATE |
-                            ParcelFileDescriptor.MODE_READ_WRITE);
+                            ParcelFileDescriptor.MODE_WRITE_ONLY);
         } catch (FileNotFoundException e) {
             System.err.println("Error: Unable to open file: " + filename);
             System.err.println("Consider using a file under /data/local/tmp/");
@@ -992,7 +992,7 @@ public class Am extends BaseCommand {
                         new File(profileFile),
                         ParcelFileDescriptor.MODE_CREATE |
                         ParcelFileDescriptor.MODE_TRUNCATE |
-                        ParcelFileDescriptor.MODE_READ_WRITE);
+                        ParcelFileDescriptor.MODE_WRITE_ONLY);
             } catch (FileNotFoundException e) {
                 System.err.println("Error: Unable to open file: " + profileFile);
                 System.err.println("Consider using a file under /data/local/tmp/");
@@ -1052,7 +1052,7 @@ public class Am extends BaseCommand {
             fd = openForSystemServer(file,
                     ParcelFileDescriptor.MODE_CREATE |
                     ParcelFileDescriptor.MODE_TRUNCATE |
-                    ParcelFileDescriptor.MODE_READ_WRITE);
+                    ParcelFileDescriptor.MODE_WRITE_ONLY);
         } catch (FileNotFoundException e) {
             System.err.println("Error: Unable to open file: " + heapFile);
             System.err.println("Consider using a file under /data/local/tmp/");
@@ -1216,6 +1216,7 @@ public class Am extends BaseCommand {
 
     class MyActivityController extends IActivityController.Stub {
         final String mGdbPort;
+        final boolean mMonkey;
 
         static final int STATE_NORMAL = 0;
         static final int STATE_CRASHED = 1;
@@ -1242,8 +1243,9 @@ public class Am extends BaseCommand {
         Thread mGdbThread;
         boolean mGotGdbPrint;
 
-        MyActivityController(String gdbPort) {
+        MyActivityController(String gdbPort, boolean monkey) {
             mGdbPort = gdbPort;
+            mMonkey = monkey;
         }
 
         @Override
@@ -1443,7 +1445,7 @@ public class Am extends BaseCommand {
             try {
                 printMessageForState();
 
-                mAm.setActivityController(this);
+                mAm.setActivityController(this, mMonkey);
                 mState = STATE_NORMAL;
 
                 InputStreamReader converter = new InputStreamReader(System.in);
@@ -1498,7 +1500,7 @@ public class Am extends BaseCommand {
             } catch (IOException e) {
                 e.printStackTrace();
             } finally {
-                mAm.setActivityController(null);
+                mAm.setActivityController(null, mMonkey);
             }
         }
     }
@@ -1506,16 +1508,19 @@ public class Am extends BaseCommand {
     private void runMonitor() throws Exception {
         String opt;
         String gdbPort = null;
+        boolean monkey = false;
         while ((opt=nextOption()) != null) {
             if (opt.equals("--gdb")) {
                 gdbPort = nextArgRequired();
+            } else if (opt.equals("-m")) {
+                monkey = true;
             } else {
                 System.err.println("Error: Unknown option: " + opt);
                 return;
             }
         }
 
-        MyActivityController controller = new MyActivityController(gdbPort);
+        MyActivityController controller = new MyActivityController(gdbPort, monkey);
         controller.run();
     }
 
index 1fa9bac..ddeb8e7 100644 (file)
@@ -50,9 +50,9 @@ public class UiAutomationShellWrapper {
         }
         try {
             if (isSet) {
-                am.setActivityController(new DummyActivityController());
+                am.setActivityController(new DummyActivityController(), true);
             } else {
-                am.setActivityController(null);
+                am.setActivityController(null, true);
             }
         } catch (RemoteException e) {
             throw new RuntimeException(e);
index fb5f5b9..ac3b8e3 100644 (file)
@@ -383,13 +383,7 @@ public abstract class AccessibilityService extends Service {
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({SHOW_MODE_AUTO, SHOW_MODE_HIDDEN})
     public @interface SoftKeyboardShowMode {};
-    /**
-     * @hide
-     */
     public static final int SHOW_MODE_AUTO = 0;
-    /**
-     * @hide
-     */
     public static final int SHOW_MODE_HIDDEN = 1;
 
     private int mConnectionId;
@@ -1137,7 +1131,7 @@ public abstract class AccessibilityService extends Service {
         }
 
         /**
-         * Removes all instances of the specified change listener from teh list of magnification
+         * Removes all instances of the specified change listener from the list of magnification
          * change listeners.
          *
          * @param listener the listener to remove, must be non-null
@@ -1216,14 +1210,11 @@ public abstract class AccessibilityService extends Service {
 
         /**
          * Returns the show mode of the soft keyboard. The default show mode is
-         * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
-         * input field is focused. An AccessibilityService can also request the show mode
-         * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+         * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
+         * focused. An AccessibilityService can also request the show mode
+         * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
          *
          * @return the current soft keyboard show mode
-         *
-         * @see Settings#Secure#SHOW_MODE_AUTO
-         * @see Settings#Secure#SHOW_MODE_HIDDEN
          */
         @SoftKeyboardShowMode
         public int getShowMode() {
@@ -1239,9 +1230,9 @@ public abstract class AccessibilityService extends Service {
 
         /**
          * Sets the soft keyboard show mode. The default show mode is
-         * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
-         * input field is focused. An AccessibilityService can also request the show mode
-         * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
+         * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
+         * focused. An AccessibilityService can also request the show mode
+         * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
          * The lastto this method will be honored, regardless of any previous calls (including those
          * made by other AccessibilityServices).
          * <p>
@@ -1251,9 +1242,6 @@ public abstract class AccessibilityService extends Service {
          *
          * @param showMode the new show mode for the soft keyboard
          * @return {@code true} on success
-         *
-         * @see Settings#Secure#SHOW_MODE_AUTO
-         * @see Settings#Secure#SHOW_MODE_HIDDEN
          */
         public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
            final IAccessibilityServiceConnection connection =
@@ -1263,9 +1251,13 @@ public abstract class AccessibilityService extends Service {
                try {
                    return connection.setSoftKeyboardShowMode(showMode);
                } catch (RemoteException re) {
-                   Log.w(LOG_TAG, "Falied to set soft keyboard behavior", re);
+                   Log.w(LOG_TAG, "Failed to set soft keyboard behavior", re);
+                   re.rethrowFromSystemServer();
                }
+           } else {
+               throw new RuntimeException("AccessibilityServiceConnection is null");
            }
+
            return false;
         }
 
@@ -1275,9 +1267,9 @@ public abstract class AccessibilityService extends Service {
         public interface OnShowModeChangedListener {
            /**
             * Called when the soft keyboard behavior changes. The default show mode is
-            * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
-            * input field is focused. An AccessibilityService can also request the show mode
-            * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+            * {@code SHOW_MODE_AUTO}, where the soft keyboard is shown when a text input field is
+            * focused. An AccessibilityService can also request the show mode
+            * {@code SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
             *
             * @param controller the soft keyboard controller
             * @param showMode the current soft keyboard show mode
index 20d71a6..8d03b55 100644 (file)
@@ -108,7 +108,7 @@ public class AnimatorInflater {
             float pathErrorScale) throws NotFoundException {
         final ConfigurationBoundResourceCache<Animator> animatorCache = resources
                 .getAnimatorCache();
-        Animator animator = animatorCache.getInstance(id, theme);
+        Animator animator = animatorCache.getInstance(id, resources, theme);
         if (animator != null) {
             if (DBG_ANIMATOR_INFLATER) {
                 Log.d(TAG, "loaded animator from cache, " + resources.getResourceName(id));
@@ -157,7 +157,7 @@ public class AnimatorInflater {
         final ConfigurationBoundResourceCache<StateListAnimator> cache = resources
                 .getStateListAnimatorCache();
         final Theme theme = context.getTheme();
-        StateListAnimator animator = cache.getInstance(id, theme);
+        StateListAnimator animator = cache.getInstance(id, resources, theme);
         if (animator != null) {
             return animator;
         }
index e721de9..5ab2c1d 100644 (file)
@@ -1029,8 +1029,16 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
 
     @Override
     public void resume() {
-        if (mPaused) {
+        if (Looper.myLooper() == null) {
+            throw new AndroidRuntimeException("Animators may only be resumed from the same " +
+                    "thread that the animator was started on");
+        }
+        if (mPaused && !mResumed) {
             mResumed = true;
+            if (mPauseTime > 0) {
+                AnimationHandler handler = AnimationHandler.getInstance();
+                handler.addAnimationFrameCallback(this, 0);
+            }
         }
         super.resume();
     }
@@ -1235,9 +1243,8 @@ public class ValueAnimator extends Animator implements AnimationHandler.Animatio
         }
         mLastFrameTime = frameTime;
         if (mPaused) {
-            if (mPauseTime < 0) {
-                mPauseTime = frameTime;
-            }
+            mPauseTime = frameTime;
+            handler.removeCallback(this);
             return;
         } else if (mResumed) {
             mResumed = false;
index 32751b2..b87e9fa 100644 (file)
@@ -41,6 +41,7 @@ import android.content.Intent;
 import android.content.IntentSender;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Configuration;
@@ -68,6 +69,7 @@ import android.os.Parcelable;
 import android.os.PersistableBundle;
 import android.os.RemoteException;
 import android.os.StrictMode;
+import android.os.SystemProperties;
 import android.os.UserHandle;
 import android.text.Selection;
 import android.text.SpannableStringBuilder;
@@ -110,6 +112,7 @@ import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView;
+import android.widget.Toast;
 import android.widget.Toolbar;
 
 import com.android.internal.app.IVoiceInteractor;
@@ -832,6 +835,8 @@ public class Activity extends ContextThemeWrapper
     private boolean mHasCurrentPermissionsRequest;
     private boolean mEatKeyUpEvent;
 
+    private static native String getDlWarning();
+
     /** Return the intent that started this activity. */
     public Intent getIntent() {
         return mIntent;
@@ -1119,34 +1124,6 @@ public class Activity extends ContextThemeWrapper
     }
 
     /**
-     * Attempts to extract the color from a given drawable.
-     *
-     * @return the extracted color or 0 if no color could be extracted.
-     */
-    private int tryExtractColorFromDrawable(Drawable drawable) {
-        if (drawable instanceof ColorDrawable) {
-            return ((ColorDrawable) drawable).getColor();
-        } else if (drawable instanceof InsetDrawable) {
-            return tryExtractColorFromDrawable(((InsetDrawable) drawable).getDrawable());
-        } else if (drawable instanceof ShapeDrawable) {
-            Paint p = ((ShapeDrawable) drawable).getPaint();
-            if (p != null) {
-                return p.getColor();
-            }
-        } else if (drawable instanceof LayerDrawable) {
-            LayerDrawable ld = (LayerDrawable) drawable;
-            int numLayers = ld.getNumberOfLayers();
-            for (int i = 0; i < numLayers; i++) {
-                int color = tryExtractColorFromDrawable(ld.getDrawable(i));
-                if (color != 0) {
-                    return color;
-                }
-            }
-        }
-        return 0;
-    }
-
-    /**
      * Called when activity start-up is complete (after {@link #onStart}
      * and {@link #onRestoreInstanceState} have been called).  Applications will
      * generally not implement this method; it is intended for system
@@ -1168,35 +1145,6 @@ public class Activity extends ContextThemeWrapper
             onTitleChanged(getTitle(), getTitleColor());
         }
 
-        Resources.Theme theme = getTheme();
-        if (theme != null) {
-            // Get the primary color and update the TaskDescription for this activity
-            TypedArray a = theme.obtainStyledAttributes(
-                    com.android.internal.R.styleable.ActivityTaskDescription);
-            if (mTaskDescription.getPrimaryColor() == 0) {
-                int colorPrimary = a.getColor(
-                        com.android.internal.R.styleable.ActivityTaskDescription_colorPrimary, 0);
-                if (colorPrimary != 0 && Color.alpha(colorPrimary) == 0xFF) {
-                    mTaskDescription.setPrimaryColor(colorPrimary);
-                }
-            }
-            if (mTaskDescription.getBackgroundColor() == 0) {
-                int windowBgResourceId = a.getResourceId(
-                        com.android.internal.R.styleable.ActivityTaskDescription_windowBackground,
-                        0);
-                int windowBgFallbackResourceId = a.getResourceId(
-                        com.android.internal.R.styleable.ActivityTaskDescription_windowBackgroundFallback,
-                        0);
-                int colorBg = tryExtractColorFromDrawable(DecorView.getResizingBackgroundDrawable(
-                        this, windowBgResourceId, windowBgFallbackResourceId));
-                if (colorBg != 0 && Color.alpha(colorBg) == 0xFF) {
-                    mTaskDescription.setBackgroundColor(colorBg);
-                }
-            }
-            a.recycle();
-            setTaskDescription(mTaskDescription);
-        }
-
         mCalled = true;
     }
 
@@ -4036,6 +3984,27 @@ public class Activity extends ContextThemeWrapper
             }
             theme.applyStyle(resid, false);
         }
+
+        // Get the primary color and update the TaskDescription for this activity
+        TypedArray a = theme.obtainStyledAttributes(
+                com.android.internal.R.styleable.ActivityTaskDescription);
+        if (mTaskDescription.getPrimaryColor() == 0) {
+            int colorPrimary = a.getColor(
+                    com.android.internal.R.styleable.ActivityTaskDescription_colorPrimary, 0);
+            if (colorPrimary != 0 && Color.alpha(colorPrimary) == 0xFF) {
+                mTaskDescription.setPrimaryColor(colorPrimary);
+            }
+        }
+        // For dev-preview only.
+        if (mTaskDescription.getBackgroundColor() == 0) {
+            int colorBackground = a.getColor(
+                    com.android.internal.R.styleable.ActivityTaskDescription_colorBackground, 0);
+            if (colorBackground != 0 && Color.alpha(colorBackground) == 0xFF) {
+                mTaskDescription.setBackgroundColor(colorBackground);
+            }
+        }
+        a.recycle();
+        setTaskDescription(mTaskDescription);
     }
 
     /**
@@ -6621,6 +6590,32 @@ public class Activity extends ContextThemeWrapper
         }
         mFragments.dispatchStart();
         mFragments.reportLoaderStart();
+
+        // This property is set for all builds except final release
+        boolean isDlwarningEnabled = SystemProperties.getInt("ro.bionic.ld.warning", 0) == 1;
+        boolean isAppDebuggable =
+                (mApplication.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
+
+        if (isAppDebuggable || isDlwarningEnabled) {
+            String dlwarning = getDlWarning();
+            if (dlwarning != null) {
+                String appName = getApplicationInfo().loadLabel(getPackageManager())
+                        .toString();
+                String warning = "Detected problems with app native libraries\n" +
+                                 "(please consult log for detail):\n" + dlwarning;
+                if (isAppDebuggable) {
+                      new AlertDialog.Builder(this).
+                          setTitle(appName).
+                          setMessage(warning).
+                          setPositiveButton(android.R.string.ok, null).
+                          setCancelable(false).
+                          show();
+                } else {
+                    Toast.makeText(this, appName + "\n" + warning, Toast.LENGTH_LONG).show();
+                }
+            }
+        }
+
         mActivityTransitionState.enterReady(this);
     }
 
index 4aab163..a4e5b90 100644 (file)
@@ -577,6 +577,16 @@ public class ActivityManager {
         }
 
         /**
+         * Return whether a stackId is a stack containing floating windows. Floating windows
+         * are laid out differently as they are allowed to extend past the display bounds
+         * without overscan insets.
+         */
+        public static boolean tasksAreFloating(int stackId) {
+            return stackId == FREEFORM_WORKSPACE_STACK_ID
+                || stackId == PINNED_STACK_ID;
+        }
+
+        /**
          * Returns true if animation specs should be constructed for app transition that moves
          * the task to the specified stack.
          */
@@ -647,6 +657,16 @@ public class ActivityManager {
             return stackId != PINNED_STACK_ID && stackId != FREEFORM_WORKSPACE_STACK_ID
                     && stackId != DOCKED_STACK_ID;
         }
+
+        /**
+         * Returns true if the input stack id should only be present on a device that supports
+         * multi-window mode.
+         * @see android.app.ActivityManager#supportsMultiWindow
+         */
+        public static boolean isMultiWindowStack(int stackId) {
+            return isStaticStack(stackId) || stackId == PINNED_STACK_ID
+                    || stackId == FREEFORM_WORKSPACE_STACK_ID || stackId == DOCKED_STACK_ID;
+        }
     }
 
     /**
@@ -868,6 +888,17 @@ public class ActivityManager {
     }
 
     /**
+     * Returns true if the system supports at least one form of multi-window.
+     * E.g. freeform, split-screen, picture-in-picture.
+     * @hide
+     */
+    static public boolean supportsMultiWindow() {
+        return !isLowRamDeviceStatic()
+                && Resources.getSystem().getBoolean(
+                    com.android.internal.R.bool.config_supportsMultiWindow);
+    }
+
+    /**
      * Information you can set and retrieve about the current activity within the recent task list.
      */
     public static class TaskDescription implements Parcelable {
index a1f82de..ff7f70d 100644 (file)
@@ -792,8 +792,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
             if (hasBounds) {
                 bounds = Rect.CREATOR.createFromParcel(data);
             }
-            moveTaskToDockedStack(taskId, createMode, toTop, animate, bounds);
+            boolean res = moveTaskToDockedStack(taskId, createMode, toTop, animate, bounds);
             reply.writeNoException();
+            reply.writeInt(res ? 1 : 0);
             return true;
         }
 
@@ -822,7 +823,21 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
             reply.writeNoException();
             return true;
         }
-
+        case RESIZE_PINNED_STACK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final boolean hasBounds = data.readInt() != 0;
+            Rect bounds = null;
+            if (hasBounds) {
+                bounds = Rect.CREATOR.createFromParcel(data);
+            }
+            final boolean hasTempPinnedTaskBounds = data.readInt() != 0;
+            Rect tempPinnedTaskBounds = null;
+            if (hasTempPinnedTaskBounds) {
+                tempPinnedTaskBounds = Rect.CREATOR.createFromParcel(data);
+            }
+            resizePinnedStack(bounds, tempPinnedTaskBounds);
+            return true;
+        }
         case RESIZE_DOCKED_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             final boolean hasBounds = data.readInt() != 0;
@@ -1527,7 +1542,8 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
             data.enforceInterface(IActivityManager.descriptor);
             IActivityController watcher = IActivityController.Stub.asInterface(
                     data.readStrongBinder());
-            setActivityController(watcher);
+            boolean imAMonkey = data.readInt() != 0;
+            setActivityController(watcher, imAMonkey);
             reply.writeNoException();
             return true;
         }
@@ -3808,7 +3824,7 @@ class ActivityManagerProxy implements IActivityManager
         reply.recycle();
     }
     @Override
-    public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
+    public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -3826,8 +3842,10 @@ class ActivityManagerProxy implements IActivityManager
         }
         mRemote.transact(MOVE_TASK_TO_DOCKED_STACK_TRANSACTION, data, reply, 0);
         reply.readException();
+        boolean res = reply.readInt() > 0;
         data.recycle();
         reply.recycle();
+        return res;
     }
     @Override
     public boolean moveTopActivityToPinnedStack(int stackId, Rect r)
@@ -3910,6 +3928,31 @@ class ActivityManagerProxy implements IActivityManager
         data.recycle();
         reply.recycle();
     }
+
+    @Override
+    public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        if (pinnedBounds != null) {
+            data.writeInt(1);
+            pinnedBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        if (tempPinnedTaskBounds != null) {
+            data.writeInt(1);
+            tempPinnedTaskBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        mRemote.transact(RESIZE_PINNED_STACK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     @Override
     public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException
     {
@@ -4860,12 +4903,14 @@ class ActivityManagerProxy implements IActivityManager
         data.recycle();
         reply.recycle();
     }
-    public void setActivityController(IActivityController watcher) throws RemoteException
+    public void setActivityController(IActivityController watcher, boolean imAMonkey)
+            throws RemoteException
     {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeStrongBinder(watcher != null ? watcher.asBinder() : null);
+        data.writeInt(imAMonkey ? 1 : 0);
         mRemote.transact(SET_ACTIVITY_CONTROLLER_TRANSACTION, data, reply, 0);
         reply.readException();
         data.recycle();
index 0d852e5..1bc33b8 100644 (file)
@@ -175,6 +175,7 @@ public final class ActivityThread {
     private static final int SQLITE_MEM_RELEASED_EVENT_LOG_TAG = 75003;
     private static final int LOG_AM_ON_PAUSE_CALLED = 30021;
     private static final int LOG_AM_ON_RESUME_CALLED = 30022;
+    private static final int LOG_AM_ON_STOP_CALLED = 30049;
 
     /** Type for IActivityManager.serviceDoneExecuting: anonymous operation */
     public static final int SERVICE_DONE_EXECUTING_ANON = 0;
@@ -978,18 +979,19 @@ public final class ActivityThread {
 
         @Override
         public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
-                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) {
+                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
+                boolean dumpUnreachable, String[] args) {
             FileOutputStream fout = new FileOutputStream(fd);
             PrintWriter pw = new FastPrintWriter(fout);
             try {
-                dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly);
+                dumpMemInfo(pw, mem, checkin, dumpFullInfo, dumpDalvik, dumpSummaryOnly, dumpUnreachable);
             } finally {
                 pw.flush();
             }
         }
 
         private void dumpMemInfo(PrintWriter pw, Debug.MemoryInfo memInfo, boolean checkin,
-                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly) {
+                boolean dumpFullInfo, boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable) {
             long nativeMax = Debug.getNativeHeapSize() / 1024;
             long nativeAllocated = Debug.getNativeHeapAllocatedSize() / 1024;
             long nativeFree = Debug.getNativeHeapFreeSize() / 1024;
@@ -1103,6 +1105,16 @@ public final class ActivityThread {
                 pw.println(" Asset Allocations");
                 pw.print(assetAlloc);
             }
+
+            // Unreachable native memory
+            if (dumpUnreachable) {
+                boolean showContents = ((mBoundApplication != null)
+                    && ((mBoundApplication.appInfo.flags&ApplicationInfo.FLAG_DEBUGGABLE) != 0))
+                    || android.os.Build.IS_DEBUGGABLE;
+                pw.println(" ");
+                pw.println(" Unreachable memory");
+                pw.print(Debug.getUnreachableMemory(100, showContents));
+            }
         }
 
         @Override
@@ -1396,7 +1408,7 @@ public final class ActivityThread {
 
                     r.packageInfo = getPackageInfoNoCheck(
                             r.activityInfo.applicationInfo, r.compatInfo);
-                    handleLaunchActivity(r, null);
+                    handleLaunchActivity(r, null, "LAUNCH_ACTIVITY");
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                 } break;
                 case RELAUNCH_ACTIVITY: {
@@ -1447,7 +1459,7 @@ public final class ActivityThread {
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "activityResume");
                     SomeArgs args = (SomeArgs) msg.obj;
                     handleResumeActivity((IBinder) args.arg1, true, args.argi1 != 0, true,
-                            args.argi3);
+                            args.argi3, "RESUME_ACTIVITY");
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 case SEND_RESULT:
@@ -1776,7 +1788,8 @@ public final class ActivityThread {
     }
 
     /**
-     * Creates the top level resources for the given package.
+     * Creates the top level resources for the given package. Will return an existing
+     * Resources if one has already been created.
      */
     Resources getTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
             String[] libDirs, int displayId, Configuration overrideConfiguration,
@@ -1786,6 +1799,19 @@ public final class ActivityThread {
                 pkgInfo.getClassLoader());
     }
 
+    /**
+     * Creates a new top level resources for the given package. Will always create a new
+     * Resources, regardless if one has already been created.
+     */
+    Resources getNewTopLevelResources(String resDir, String[] splitResDirs, String[] overlayDirs,
+            String[] libDirs, int displayId, Configuration overrideConfiguration,
+            LoadedApk pkgInfo) {
+        mResourcesManager.removeTopLevelResources(
+                resDir, displayId, overrideConfiguration, pkgInfo.getCompatibilityInfo());
+        return getTopLevelResources(resDir, splitResDirs, overlayDirs, libDirs,
+                displayId, overrideConfiguration, pkgInfo);
+    }
+
     final Handler getHandler() {
         return mH;
     }
@@ -2620,7 +2646,7 @@ public final class ActivityThread {
         return baseContext;
     }
 
-    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent) {
+    private void handleLaunchActivity(ActivityClientRecord r, Intent customIntent, String reason) {
         // If we are getting ready to gc after going to the background, well
         // we are back active so skip it.
         unscheduleGcIdler();
@@ -2647,7 +2673,7 @@ public final class ActivityThread {
             reportSizeConfigurations(r);
             Bundle oldState = r.state;
             handleResumeActivity(r.token, false, r.isForward,
-                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq);
+                    !r.activity.mFinished && !r.startsNotResumed, r.lastProcessedSeq, reason);
 
             if (!r.activity.mFinished && r.startsNotResumed) {
                 // The activity manager actually wants this one to start out
@@ -2662,6 +2688,8 @@ public final class ActivityThread {
                 try {
                     r.activity.mCalled = false;
                     mInstrumentation.callActivityOnPause(r.activity);
+                    EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
+                            r.activity.getComponentName().getClassName(), reason);
                     // We need to keep around the original state, in case
                     // we need to be created again.  But we only do this
                     // for pre-Honeycomb apps, which always save their state
@@ -3309,7 +3337,7 @@ public final class ActivityThread {
     }
 
     public final ActivityClientRecord performResumeActivity(IBinder token,
-            boolean clearHide) {
+            boolean clearHide, String reason) {
         ActivityClientRecord r = mActivities.get(token);
         if (localLOGV) Slog.v(TAG, "Performing resume of " + r
                 + " finished=" + r.activity.mFinished);
@@ -3331,8 +3359,20 @@ public final class ActivityThread {
                 }
                 r.activity.performResume();
 
-                EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED,
-                        UserHandle.myUserId(), r.activity.getComponentName().getClassName());
+                // If there is a pending local relaunch that was requested when the activity was
+                // paused, it will put the activity into paused state when it finally happens.
+                // Since the activity resumed before being relaunched, we don't want that to happen,
+                // so we need to clear the request to relaunch paused.
+                for (int i = mRelaunchingActivities.size() - 1; i >= 0; i--) {
+                    final ActivityClientRecord relaunching = mRelaunchingActivities.get(i);
+                    if (relaunching.token == r.token
+                            && relaunching.onlyLocalRequest && relaunching.startsNotResumed) {
+                        relaunching.startsNotResumed = false;
+                    }
+                }
+
+                EventLog.writeEvent(LOG_AM_ON_RESUME_CALLED, UserHandle.myUserId(),
+                        r.activity.getComponentName().getClassName(), reason);
 
                 r.paused = false;
                 r.stopped = false;
@@ -3368,7 +3408,7 @@ public final class ActivityThread {
     }
 
     final void handleResumeActivity(IBinder token,
-            boolean clearHide, boolean isForward, boolean reallyResume, int seq) {
+            boolean clearHide, boolean isForward, boolean reallyResume, int seq, String reason) {
         ActivityClientRecord r = mActivities.get(token);
         if (!checkAndUpdateLifecycleSeq(seq, r, "resumeActivity")) {
             return;
@@ -3380,7 +3420,7 @@ public final class ActivityThread {
         mSomeActivitiesChanged = true;
 
         // TODO Push resumeArgs into the activity for consideration
-        r = performResumeActivity(token, clearHide);
+        r = performResumeActivity(token, clearHide, reason);
 
         if (r != null) {
             final Activity a = r.activity;
@@ -3562,6 +3602,7 @@ public final class ActivityThread {
     private void handlePauseActivity(IBinder token, boolean finished,
             boolean userLeaving, int configChanges, boolean dontReport, int seq) {
         ActivityClientRecord r = mActivities.get(token);
+        if (DEBUG_ORDER) Slog.d(TAG, "handlePauseActivity " + r + ", seq: " + seq);
         if (!checkAndUpdateLifecycleSeq(seq, r, "pauseActivity")) {
             return;
         }
@@ -3572,7 +3613,7 @@ public final class ActivityThread {
             }
 
             r.activity.mConfigChangeFlags |= configChanges;
-            performPauseActivity(token, finished, r.isPreHoneycomb());
+            performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
 
             // Make sure any pending writes are now committed.
             if (r.isPreHoneycomb()) {
@@ -3596,13 +3637,13 @@ public final class ActivityThread {
     }
 
     final Bundle performPauseActivity(IBinder token, boolean finished,
-            boolean saveState) {
+            boolean saveState, String reason) {
         ActivityClientRecord r = mActivities.get(token);
-        return r != null ? performPauseActivity(r, finished, saveState) : null;
+        return r != null ? performPauseActivity(r, finished, saveState, reason) : null;
     }
 
     final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,
-            boolean saveState) {
+            boolean saveState, String reason) {
         if (r.paused) {
             if (r.activity.mFinished) {
                 // If we are finishing, we won't call onResume() in certain cases.
@@ -3627,7 +3668,7 @@ public final class ActivityThread {
             r.activity.mCalled = false;
             mInstrumentation.callActivityOnPause(r.activity);
             EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
-                    r.activity.getComponentName().getClassName());
+                    r.activity.getComponentName().getClassName(), reason);
             if (!r.activity.mCalled) {
                 throw new SuperNotCalledException(
                     "Activity " + r.intent.getComponent().toShortString() +
@@ -3660,9 +3701,9 @@ public final class ActivityThread {
         return !r.activity.mFinished && saveState ? r.state : null;
     }
 
-    final void performStopActivity(IBinder token, boolean saveState) {
+    final void performStopActivity(IBinder token, boolean saveState, String reason) {
         ActivityClientRecord r = mActivities.get(token);
-        performStopActivityInner(r, null, false, saveState);
+        performStopActivityInner(r, null, false, saveState, reason);
     }
 
     private static class StopInfo implements Runnable {
@@ -3679,8 +3720,8 @@ public final class ActivityThread {
                     activity.token, state, persistentState, description);
             } catch (RemoteException ex) {
                 if (ex instanceof TransactionTooLargeException
-                        && "com.google.android.gms".equals(activity.packageInfo.getPackageName())) {
-                    Log.d(TAG, "STAHP SENDING SO MUCH DATA KTHX: " + ex);
+                        && activity.packageInfo.getTargetSdkVersion() < Build.VERSION_CODES.N) {
+                    Log.e(TAG, "App tried sending too much data in instance state", ex);
                     return;
                 }
 
@@ -3720,7 +3761,7 @@ public final class ActivityThread {
      * the activity's UI visibillity changes.
      */
     private void performStopActivityInner(ActivityClientRecord r,
-            StopInfo info, boolean keepShown, boolean saveState) {
+            StopInfo info, boolean keepShown, boolean saveState, String reason) {
         if (localLOGV) Slog.v(TAG, "Performing stop of " + r);
         if (r != null) {
             if (!keepShown && r.stopped) {
@@ -3772,6 +3813,8 @@ public final class ActivityThread {
                     }
                 }
                 r.stopped = true;
+                EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),
+                        r.activity.getComponentName().getClassName(), reason);
             }
 
             r.paused = true;
@@ -3818,7 +3861,7 @@ public final class ActivityThread {
         r.activity.mConfigChangeFlags |= configChanges;
 
         StopInfo info = new StopInfo();
-        performStopActivityInner(r, info, show, true);
+        performStopActivityInner(r, info, show, true, "handleStopActivity");
 
         if (localLOGV) Slog.v(
             TAG, "Finishing stop of " + r + ": show=" + show
@@ -3874,7 +3917,7 @@ public final class ActivityThread {
         }
 
         if (!show && !r.stopped) {
-            performStopActivityInner(r, null, show, false);
+            performStopActivityInner(r, null, show, false, "handleWindowVisibility");
         } else if (show && r.stopped) {
             // If we are getting ready to gc after going to the background, well
             // we are back active so skip it.
@@ -3913,6 +3956,8 @@ public final class ActivityThread {
                     }
                 }
                 r.stopped = true;
+                EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),
+                        r.activity.getComponentName().getClassName(), "sleeping");
             }
 
             // Make sure any pending writes are now committed.
@@ -4054,7 +4099,7 @@ public final class ActivityThread {
                     r.activity.mCalled = false;
                     mInstrumentation.callActivityOnPause(r.activity);
                     EventLog.writeEvent(LOG_AM_ON_PAUSE_CALLED, UserHandle.myUserId(),
-                            r.activity.getComponentName().getClassName());
+                            r.activity.getComponentName().getClassName(), "destroy");
                     if (!r.activity.mCalled) {
                         throw new SuperNotCalledException(
                             "Activity " + safeToComponentShortString(r.intent)
@@ -4086,6 +4131,8 @@ public final class ActivityThread {
                     }
                 }
                 r.stopped = true;
+                EventLog.writeEvent(LOG_AM_ON_STOP_CALLED, UserHandle.myUserId(),
+                        r.activity.getComponentName().getClassName(), "destroy");
             }
             if (getNonConfigInstance) {
                 try {
@@ -4210,6 +4257,7 @@ public final class ActivityThread {
         synchronized (mResourcesManager) {
             for (int i=0; i<mRelaunchingActivities.size(); i++) {
                 ActivityClientRecord r = mRelaunchingActivities.get(i);
+                if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: " + this + ", trying: " + r);
                 if (r.token == token) {
                     target = r;
                     if (pendingResults != null) {
@@ -4240,14 +4288,19 @@ public final class ActivityThread {
             }
 
             if (target == null) {
+                if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: target is null, fromServer:"
+                        + fromServer);
                 target = new ActivityClientRecord();
                 target.token = token;
                 target.pendingResults = pendingResults;
                 target.pendingIntents = pendingNewIntents;
                 target.mPreserveWindow = preserveWindow;
                 if (!fromServer) {
-                    ActivityClientRecord existing = mActivities.get(token);
+                    final ActivityClientRecord existing = mActivities.get(token);
+                    if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: " + existing);
                     if (existing != null) {
+                        if (DEBUG_ORDER) Slog.d(TAG, "requestRelaunchActivity: paused= "
+                                + existing.paused);;
                         target.startsNotResumed = existing.paused;
                         target.overrideConfig = existing.overrideConfig;
                     }
@@ -4270,8 +4323,8 @@ public final class ActivityThread {
             target.pendingConfigChanges |= configChanges;
             target.relaunchSeq = getLifecycleSeq();
         }
-        if (DEBUG_ORDER) Slog.d(TAG, "relaunchActivity " + ActivityThread.this
-                + " operation received seq: " + target.relaunchSeq);
+        if (DEBUG_ORDER) Slog.d(TAG, "relaunchActivity " + ActivityThread.this + ", target "
+                + target + " operation received seq: " + target.relaunchSeq);
     }
 
     private void handleRelaunchActivity(ActivityClientRecord tmp) {
@@ -4385,7 +4438,7 @@ public final class ActivityThread {
 
         // Need to ensure state is saved.
         if (!r.paused) {
-            performPauseActivity(r.token, false, r.isPreHoneycomb());
+            performPauseActivity(r.token, false, r.isPreHoneycomb(), "handleRelaunchActivity");
         }
         if (r.state == null && !r.stopped && !r.isPreHoneycomb()) {
             callCallActivityOnSaveInstanceState(r);
@@ -4415,7 +4468,7 @@ public final class ActivityThread {
         r.startsNotResumed = tmp.startsNotResumed;
         r.overrideConfig = tmp.overrideConfig;
 
-        handleLaunchActivity(r, currentIntent);
+        handleLaunchActivity(r, currentIntent, "handleRelaunchActivity");
 
         if (!tmp.onlyLocalRequest) {
             try {
@@ -4710,29 +4763,87 @@ public final class ActivityThread {
 
     final void handleDispatchPackageBroadcast(int cmd, String[] packages) {
         boolean hasPkgInfo = false;
-        if (packages != null) {
-            synchronized (mResourcesManager) {
-                for (int i=packages.length-1; i>=0; i--) {
-                    //Slog.i(TAG, "Cleaning old package: " + packages[i]);
-                    if (!hasPkgInfo) {
-                        WeakReference<LoadedApk> ref;
-                        ref = mPackages.get(packages[i]);
-                        if (ref != null && ref.get() != null) {
+        switch (cmd) {
+            case IApplicationThread.PACKAGE_REMOVED:
+            case IApplicationThread.PACKAGE_REMOVED_DONT_KILL:
+            {
+                final boolean killApp = cmd == IApplicationThread.PACKAGE_REMOVED;
+                if (packages == null) {
+                    break;
+                }
+                synchronized (mResourcesManager) {
+                    for (int i = packages.length - 1; i >= 0; i--) {
+                        if (!hasPkgInfo) {
+                            WeakReference<LoadedApk> ref = mPackages.get(packages[i]);
+                            if (ref != null && ref.get() != null) {
+                                hasPkgInfo = true;
+                            } else {
+                                ref = mResourcePackages.get(packages[i]);
+                                if (ref != null && ref.get() != null) {
+                                    hasPkgInfo = true;
+                                }
+                            }
+                        }
+                        if (killApp) {
+                            mPackages.remove(packages[i]);
+                            mResourcePackages.remove(packages[i]);
+                        }
+                    }
+                }
+                break;
+            }
+            case IApplicationThread.PACKAGE_REPLACED:
+            {
+                if (packages == null) {
+                    break;
+                }
+                synchronized (mResourcesManager) {
+                    for (int i = packages.length - 1; i >= 0; i--) {
+                        WeakReference<LoadedApk> ref = mPackages.get(packages[i]);
+                        LoadedApk pkgInfo = ref != null ? ref.get() : null;
+                        if (pkgInfo != null) {
                             hasPkgInfo = true;
                         } else {
                             ref = mResourcePackages.get(packages[i]);
-                            if (ref != null && ref.get() != null) {
+                            pkgInfo = ref != null ? ref.get() : null;
+                            if (pkgInfo != null) {
                                 hasPkgInfo = true;
                             }
                         }
+                        // If the package is being replaced, yet it still has a valid
+                        // LoadedApk object, the package was updated with _DONT_KILL.
+                        // Adjust it's internal references to the application info and
+                        // resources.
+                        if (pkgInfo != null) {
+                            try {
+                                final String packageName = packages[i];
+                                final ApplicationInfo aInfo =
+                                        sPackageManager.getApplicationInfo(
+                                                packageName,
+                                                0 /*flags*/,
+                                                UserHandle.myUserId());
+
+                                if (mActivities.size() > 0) {
+                                    for (ActivityClientRecord ar : mActivities.values()) {
+                                        if (ar.activityInfo.applicationInfo.packageName
+                                                .equals(packageName)) {
+                                            ar.activityInfo.applicationInfo = aInfo;
+                                            ar.packageInfo = pkgInfo;
+                                        }
+                                    }
+                                }
+                                final List<String> oldPaths =
+                                        sPackageManager.getPreviousCodePaths(packageName);
+                                pkgInfo.updateApplicationInfo(aInfo, oldPaths);
+                            } catch (RemoteException e) {
+                            }
+                        }
                     }
-                    mPackages.remove(packages[i]);
-                    mResourcePackages.remove(packages[i]);
                 }
+                break;
             }
         }
-        ApplicationPackageManager.handlePackageBroadcast(cmd, packages,
-                hasPkgInfo);
+        ApplicationPackageManager.handlePackageBroadcast(cmd, packages, hasPkgInfo);
     }
 
     final void handleLowMemory() {
@@ -4793,8 +4904,9 @@ public final class ActivityThread {
 
     // Keep in sync with installd (frameworks/native/cmds/installd/commands.cpp).
     private static File getPrimaryProfileFile(String packageName) {
-         return new File("/data/misc/profiles/cur/" + UserHandle.myUserId() +
-              "/" + packageName + "/primary.prof");
+        File profileDir = Environment.getDataProfilesDePackageDirectory(
+                UserHandle.myUserId(), packageName);
+        return new File(profileDir, "primary.prof");
     }
 
     private static void setupJitProfileSupport(LoadedApk loadedApk, File cacheDir) {
@@ -4825,11 +4937,15 @@ public final class ActivityThread {
                 Os.fchmod(fd, permissions);
                 Os.fchown(fd, appInfo.uid, appInfo.uid);
             } catch (ErrnoException e) {
-                Log.v(TAG, "Unable to create jit profile file " + profileFile, e);
+                Log.v(TAG, "Unable to create jit profile file "
+                        + profileFile + ": " + e.getMessage());
                 try {
                     Os.unlink(profileFile.getAbsolutePath());
                 } catch (ErrnoException unlinkErr) {
-                    Log.v(TAG, "Unable to unlink jit profile file " + profileFile, unlinkErr);
+                    if (unlinkErr.errno != OsConstants.ENOENT) {
+                        Log.v(TAG, "Unable to unlink jit profile file "
+                                + profileFile + ": " + unlinkErr.getMessage());
+                    }
                 }
                 return;
             } finally {
@@ -4837,8 +4953,17 @@ public final class ActivityThread {
             }
         }
 
+        final File foreignDexProfilesFile =
+                Environment.getDataProfilesDeForeignDexDirectory(UserHandle.myUserId());
+        String foreignDexProfilesPath = null;
+        if (!foreignDexProfilesFile.exists()) {
+            Log.v(TAG, "ForeignDexProfilesPath does not exists:" +
+                    foreignDexProfilesFile.getPath());
+        } else {
+            foreignDexProfilesPath = foreignDexProfilesFile.getAbsolutePath();
+        }
         VMRuntime.registerAppInfo(profileFile.getAbsolutePath(), appInfo.dataDir,
-                codePaths.toArray(new String[codePaths.size()]));
+                codePaths.toArray(new String[codePaths.size()]), foreignDexProfilesPath);
     }
 
     private void updateDefaultDensity() {
@@ -4856,6 +4981,9 @@ public final class ActivityThread {
             DdmVmInternal.enableRecentAllocations(true);
         }
 
+        // Note when this process has started.
+        Process.setStartTimes(SystemClock.elapsedRealtime(), SystemClock.uptimeMillis());
+
         mBoundApplication = data;
         mConfiguration = new Configuration(data.config);
         mCompatConfiguration = new Configuration(data.config);
index b569416..455f869 100644 (file)
@@ -201,6 +201,7 @@ public class AlarmManager {
             try {
                 mService.remove(null, this);
             } catch (RemoteException ex) {
+                throw ex.rethrowFromSystemServer();
             }
 
             synchronized (AlarmManager.class) {
@@ -656,6 +657,7 @@ public class AlarmManager {
             mService.set(mPackageName, type, triggerAtMillis, windowMillis, intervalMillis, flags,
                     operation, recipientWrapper, listenerTag, workSource, alarmClock);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -886,6 +888,7 @@ public class AlarmManager {
         try {
             mService.remove(operation, null);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -926,6 +929,7 @@ public class AlarmManager {
         try {
             mService.setTime(millis);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -965,6 +969,7 @@ public class AlarmManager {
         try {
             mService.setTimeZone(timeZone);
         } catch (RemoteException ex) {
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -973,7 +978,7 @@ public class AlarmManager {
         try {
             return mService.getNextWakeFromIdleTime();
         } catch (RemoteException ex) {
-            return Long.MAX_VALUE;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -1005,7 +1010,7 @@ public class AlarmManager {
         try {
             return mService.getNextAlarmClock(userId);
         } catch (RemoteException ex) {
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
index 9d1dfdd..82c4c51 100644 (file)
@@ -704,8 +704,8 @@ public class AppOpsManager {
      * (and system ui) to bypass the user restriction when active.
      */
     private static boolean[] sOpAllowSystemRestrictionBypass = new boolean[] {
-            false, //COARSE_LOCATION
-            false, //FINE_LOCATION
+            true, //COARSE_LOCATION
+            true, //FINE_LOCATION
             false, //GPS
             false, //VIBRATE
             false, //READ_CONTACTS
index b20c091..0fc097e 100644 (file)
@@ -86,6 +86,18 @@ class ApplicationLoaders {
                                                             String libraryPermittedPath,
                                                             boolean isShared);
 
+    /**
+     * Adds a new path the classpath of the given loader.
+     * @throws IllegalStateException if the provided class loader is not a {@link PathClassLoader}.
+     */
+    void addPath(ClassLoader classLoader, String dexPath) {
+        if (!(classLoader instanceof PathClassLoader)) {
+            throw new IllegalStateException("class loader is not a PathClassLoader");
+        }
+        final PathClassLoader baseDexClassLoader = (PathClassLoader) classLoader;
+        baseDexClassLoader.addDexPath(dexPath);
+    }
+
     private final ArrayMap<String, ClassLoader> mLoaders = new ArrayMap<String, ClassLoader>();
 
     private static final ApplicationLoaders gApplicationLoaders
index 4d466d3..38f32f7 100644 (file)
@@ -30,7 +30,6 @@ import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.ComponentInfo;
-import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.EphemeralApplicationInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IOnPermissionsChangeListener;
@@ -54,7 +53,6 @@ import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
-import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -1095,6 +1093,14 @@ public class ApplicationPackageManager extends PackageManager {
     }
 
     @Override
+    public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+            int badgeDensity) {
+        Drawable badgeDrawable = getDrawableForDensity(
+            com.android.internal.R.drawable.ic_corp_badge, badgeDensity);
+        return getBadgedDrawable(drawable, badgeDrawable, badgeLocation, true);
+    }
+
+    @Override
     public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
         final int badgeResId = getBadgeResIdForUser(user.getIdentifier());
         if (badgeResId == 0) {
@@ -1116,24 +1122,27 @@ public class ApplicationPackageManager extends PackageManager {
 
     @Override
     public Drawable getUserBadgeForDensity(UserHandle user, int density) {
-        return getManagedProfileIconForDensity(user, density,
-                com.android.internal.R.drawable.ic_corp_badge);
+        return getManagedProfileIconForDensity(user, com.android.internal.R.drawable.ic_corp_badge,
+                density);
     }
 
     @Override
     public Drawable getUserBadgeForDensityNoBackground(UserHandle user, int density) {
-        return getManagedProfileIconForDensity(user, density,
-                com.android.internal.R.drawable.ic_corp_badge_no_background);
+        return getManagedProfileIconForDensity(user,
+                com.android.internal.R.drawable.ic_corp_badge_no_background, density);
     }
 
-    private Drawable getManagedProfileIconForDensity(UserHandle user, int density,
-            int drawableId) {
+    private Drawable getDrawableForDensity(int drawableId, int density) {
+        if (density <= 0) {
+            density = mContext.getResources().getDisplayMetrics().densityDpi;
+        }
+        return Resources.getSystem().getDrawableForDensity(drawableId, density);
+    }
+
+    private Drawable getManagedProfileIconForDensity(UserHandle user, int drawableId, int density) {
         UserInfo userInfo = getUserIfProfile(user.getIdentifier());
         if (userInfo != null && userInfo.isManagedProfile()) {
-            if (density <= 0) {
-                density = mContext.getResources().getDisplayMetrics().densityDpi;
-            }
-            return Resources.getSystem().getDrawableForDensity(drawableId, density);
+            return getDrawableForDensity(drawableId, density);
         }
         return null;
     }
@@ -1469,80 +1478,27 @@ public class ApplicationPackageManager extends PackageManager {
     @Override
     public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
                                String installerPackageName) {
-        final VerificationParams verificationParams = new VerificationParams(null, null,
-                null, VerificationParams.NO_UID);
-        installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
-                installerPackageName, verificationParams, null, mContext.getUserId());
-    }
-
-    @Override
-    public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
-            int flags, String installerPackageName, Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-        final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
-                null, VerificationParams.NO_UID);
-        installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
-                installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
-    }
-
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
         installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
-                installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
+                installerPackageName, mContext.getUserId());
     }
 
     @Override
     public void installPackage(Uri packageURI, PackageInstallObserver observer,
             int flags, String installerPackageName) {
-        installPackageAsUser(packageURI, observer, flags, installerPackageName,
-                mContext.getUserId());
-    }
-
-    @Override
-    public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer, int flags,
-               String installerPackageName, int userId) {
-        final VerificationParams verificationParams = new VerificationParams(null, null,
-                null, VerificationParams.NO_UID);
-        installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null,
-                userId);
-    }
-
-    @Override
-    public void installPackageWithVerification(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-        final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
-                null, VerificationParams.NO_UID);
-        installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
-                encryptionParams, mContext.getUserId());
-    }
-
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-        installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
-                encryptionParams, mContext.getUserId());
+        installCommon(packageURI, observer, flags, installerPackageName, mContext.getUserId());
     }
 
     private void installCommon(Uri packageURI,
             PackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams,
             int userId) {
         if (!"file".equals(packageURI.getScheme())) {
             throw new UnsupportedOperationException("Only file:// URIs are supported");
         }
-        if (encryptionParams != null) {
-            throw new UnsupportedOperationException("ContainerEncryptionParams not supported");
-        }
 
         final String originPath = packageURI.getPath();
         try {
             mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
-                    verificationParams, null, userId);
+                    userId);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -1587,9 +1543,9 @@ public class ApplicationPackageManager extends PackageManager {
     }
 
     @Override
-    public void verifyIntentFilter(int id, int verificationCode, List<String> outFailedDomains) {
+    public void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) {
         try {
-            mPM.verifyIntentFilter(id, verificationCode, outFailedDomains);
+            mPM.verifyIntentFilter(id, verificationCode, failedDomains);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
index 59ecc03..744ddf7 100644 (file)
@@ -548,11 +548,12 @@ public abstract class ApplicationThreadNative extends Binder
             boolean dumpInfo = data.readInt() != 0;
             boolean dumpDalvik = data.readInt() != 0;
             boolean dumpSummaryOnly = data.readInt() != 0;
+            boolean dumpUnreachable = data.readInt() != 0;
             String[] args = data.readStringArray();
             if (fd != null) {
                 try {
                     dumpMemInfo(fd.getFileDescriptor(), mi, checkin, dumpInfo,
-                            dumpDalvik, dumpSummaryOnly, args);
+                            dumpDalvik, dumpSummaryOnly, dumpUnreachable, args);
                 } finally {
                     try {
                         fd.close();
@@ -1328,7 +1329,8 @@ class ApplicationThreadProxy implements IApplicationThread {
     }
 
     public void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin,
-            boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) throws RemoteException {
+            boolean dumpInfo, boolean dumpDalvik, boolean dumpSummaryOnly,
+            boolean dumpUnreachable, String[] args) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IApplicationThread.descriptor);
@@ -1338,6 +1340,7 @@ class ApplicationThreadProxy implements IApplicationThread {
         data.writeInt(dumpInfo ? 1 : 0);
         data.writeInt(dumpDalvik ? 1 : 0);
         data.writeInt(dumpSummaryOnly ? 1 : 0);
+        data.writeInt(dumpUnreachable ? 1 : 0);
         data.writeStringArray(args);
         mRemote.transact(DUMP_MEM_INFO_TRANSACTION, data, reply, 0);
         reply.readException();
index b7eaf39..1f1f318 100644 (file)
@@ -27,14 +27,13 @@ import java.util.Objects;
 /**
  * Rule instance information for zen mode.
  */
-public class AutomaticZenRule implements Parcelable {
+public final class AutomaticZenRule implements Parcelable {
 
     private boolean enabled = false;
     private String name;
     private @InterruptionFilter int interruptionFilter;
     private Uri conditionId;
     private ComponentName owner;
-    private String id;
     private long creationTime;
 
     /**
@@ -63,9 +62,8 @@ public class AutomaticZenRule implements Parcelable {
      * @hide
      */
     public AutomaticZenRule(String name, ComponentName owner, Uri conditionId,
-            int interruptionFilter, boolean enabled, String id, long creationTime) {
+            int interruptionFilter, boolean enabled, long creationTime) {
         this(name, owner, conditionId, interruptionFilter, enabled);
-        this.id = id;
         this.creationTime = creationTime;
     }
 
@@ -77,9 +75,6 @@ public class AutomaticZenRule implements Parcelable {
         interruptionFilter = source.readInt();
         conditionId = source.readParcelable(null);
         owner = source.readParcelable(null);
-        if (source.readInt() == 1) {
-            id = source.readString();
-        }
         creationTime = source.readLong();
     }
 
@@ -119,20 +114,13 @@ public class AutomaticZenRule implements Parcelable {
     }
 
     /**
-     * Returns the wall time in milliseconds when this rule was created, if known.
+     * Returns the time this rule was created, represented as milliseconds since the epoch.
      */
     public long getCreationTime() {
       return creationTime;
     }
 
     /**
-     * Returns the unique identifier for this rule.
-     */
-    public String getId() {
-      return id;
-    }
-
-    /**
      * Sets the representation of the state that causes this rule to become active.
      */
     public void setConditionId(Uri conditionId) {
@@ -178,12 +166,6 @@ public class AutomaticZenRule implements Parcelable {
         dest.writeInt(interruptionFilter);
         dest.writeParcelable(conditionId, 0);
         dest.writeParcelable(owner, 0);
-        if (id != null) {
-            dest.writeInt(1);
-            dest.writeString(id);
-        } else {
-            dest.writeInt(0);
-        }
         dest.writeLong(creationTime);
     }
 
@@ -195,7 +177,6 @@ public class AutomaticZenRule implements Parcelable {
                 .append(",interruptionFilter=").append(interruptionFilter)
                 .append(",conditionId=").append(conditionId)
                 .append(",owner=").append(owner)
-                .append(",id=").append(id)
                 .append(",creationTime=").append(creationTime)
                 .append(']').toString();
     }
@@ -210,13 +191,12 @@ public class AutomaticZenRule implements Parcelable {
                 && other.interruptionFilter == interruptionFilter
                 && Objects.equals(other.conditionId, conditionId)
                 && Objects.equals(other.owner, owner)
-                && Objects.equals(other.id, id)
                 && other.creationTime == creationTime;
     }
 
     @Override
     public int hashCode() {
-        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, id, creationTime);
+        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner, creationTime);
     }
 
     public static final Parcelable.Creator<AutomaticZenRule> CREATOR
index 4b0dfc7..3a51aff 100644 (file)
@@ -16,8 +16,6 @@
 
 package android.app;
 
-import com.android.internal.util.FastPrintWriter;
-
 import android.graphics.Rect;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -33,6 +31,8 @@ import android.view.View;
 import android.view.ViewGroup;
 import android.view.ViewTreeObserver;
 
+import com.android.internal.util.FastPrintWriter;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
 import java.util.ArrayList;
@@ -717,10 +717,12 @@ final class BackStackRecord extends FragmentTransaction implements
 
         bumpBackStackNesting(1);
 
-        SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
-        SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
-        calculateFragments(firstOutFragments, lastInFragments);
-        beginTransition(firstOutFragments, lastInFragments, false);
+        if (mManager.mCurState >= Fragment.CREATED) {
+            SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
+            SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
+            calculateFragments(firstOutFragments, lastInFragments);
+            beginTransition(firstOutFragments, lastInFragments, false);
+        }
 
         Op op = mHead;
         while (op != null) {
@@ -842,6 +844,14 @@ final class BackStackRecord extends FragmentTransaction implements
                     firstOutFragments.remove(containerId);
                 }
             }
+            /**
+             * Ensure that fragments that are entering are at least at the CREATED state
+             * so that they may load Transitions using TransitionInflater.
+             */
+            if (fragment.mState < Fragment.CREATED && mManager.mCurState >= Fragment.CREATED) {
+                mManager.makeActive(fragment);
+                mManager.moveToState(fragment, Fragment.CREATED, 0, 0, false);
+            }
         }
     }
 
@@ -986,7 +996,6 @@ final class BackStackRecord extends FragmentTransaction implements
      */
     private TransitionState beginTransition(SparseArray<Fragment> firstOutFragments,
             SparseArray<Fragment> lastInFragments, boolean isBack) {
-        ensureFragmentsAreInitialized(lastInFragments);
         TransitionState state = new TransitionState();
 
         // Adding a non-existent target view makes sure that the transitions don't target
@@ -1012,21 +1021,6 @@ final class BackStackRecord extends FragmentTransaction implements
         return state;
     }
 
-    /**
-     * Ensure that fragments that are entering are at least at the CREATED state
-     * so that they may load Transitions using TransitionInflater.
-     */
-    private void ensureFragmentsAreInitialized(SparseArray<Fragment> lastInFragments) {
-        final int count = lastInFragments.size();
-        for (int i = 0; i < count; i++) {
-            final Fragment fragment = lastInFragments.valueAt(i);
-            if (fragment.mState < Fragment.CREATED) {
-                mManager.makeActive(fragment);
-                mManager.moveToState(fragment, Fragment.CREATED, 0, 0, false);
-            }
-        }
-    }
-
     private static Transition cloneTransition(Transition transition) {
         if (transition != null) {
             transition = transition.clone();
@@ -1663,12 +1657,14 @@ final class BackStackRecord extends FragmentTransaction implements
             pw.flush();
         }
 
-        if (state == null) {
-            if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) {
-                state = beginTransition(firstOutFragments, lastInFragments, true);
+        if (mManager.mCurState >= Fragment.CREATED) {
+            if (state == null) {
+                if (firstOutFragments.size() != 0 || lastInFragments.size() != 0) {
+                    state = beginTransition(firstOutFragments, lastInFragments, true);
+                }
+            } else if (!doStateMove) {
+                setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
             }
-        } else if (!doStateMove) {
-            setNameOverrides(state, mSharedElementTargetNames, mSharedElementSourceNames);
         }
 
         bumpBackStackNesting(-1);
index 47eec8b..e76f991 100644 (file)
@@ -396,9 +396,11 @@ class ContextImpl extends Context {
 
     /**
      * Try our best to migrate all files from source to target that match
-     * requested prefix. Return false if we have any trouble migrating.
+     * requested prefix.
+     *
+     * @return the number of files moved, or -1 if there was trouble.
      */
-    private static boolean migrateFiles(File sourceDir, File targetDir, final String prefix) {
+    private static int migrateFiles(File sourceDir, File targetDir, final String prefix) {
         final File[] sourceFiles = FileUtils.listFilesOrEmpty(sourceDir, new FilenameFilter() {
             @Override
             public boolean accept(File dir, String name) {
@@ -406,7 +408,7 @@ class ContextImpl extends Context {
             }
         });
 
-        boolean res = true;
+        int res = 0;
         for (File sourceFile : sourceFiles) {
             final File targetFile = new File(targetDir, sourceFile.getName());
             Log.d(TAG, "Migrating " + sourceFile + " to " + targetFile);
@@ -416,9 +418,12 @@ class ContextImpl extends Context {
                 if (!sourceFile.delete()) {
                     throw new IOException("Failed to clean up " + sourceFile);
                 }
+                if (res != -1) {
+                    res++;
+                }
             } catch (IOException e) {
                 Log.w(TAG, "Failed to migrate " + sourceFile + ": " + e);
-                res = false;
+                res = -1;
             }
         }
         return res;
@@ -430,12 +435,17 @@ class ContextImpl extends Context {
             final File source = sourceContext.getSharedPreferencesPath(name);
             final File target = getSharedPreferencesPath(name);
 
-            // Evict any in-memory caches for either location
-            final ArrayMap<File, SharedPreferencesImpl> cache = getSharedPreferencesCacheLocked();
-            cache.remove(source);
-            cache.remove(target);
-
-            return migrateFiles(source.getParentFile(), target.getParentFile(), source.getName());
+            final int res = migrateFiles(source.getParentFile(), target.getParentFile(),
+                    source.getName());
+            if (res > 0) {
+                // We moved at least one file, so evict any in-memory caches for
+                // either location
+                final ArrayMap<File, SharedPreferencesImpl> cache =
+                        getSharedPreferencesCacheLocked();
+                cache.remove(source);
+                cache.remove(target);
+            }
+            return res != -1;
         }
     }
 
@@ -675,7 +685,8 @@ class ContextImpl extends Context {
         synchronized (ContextImpl.class) {
             final File source = sourceContext.getDatabasePath(name);
             final File target = getDatabasePath(name);
-            return migrateFiles(source.getParentFile(), target.getParentFile(), source.getName());
+            return migrateFiles(source.getParentFile(), target.getParentFile(),
+                    source.getName()) != -1;
         }
     }
 
index aafb3c6..6870bbf 100644 (file)
@@ -2509,6 +2509,7 @@ public class Fragment implements ComponentCallbacks2, OnCreateContextMenuListene
             throw new SuperNotCalledException("Fragment " + this
                     + " did not call through to super.onDestroy()");
         }
+        mChildFragmentManager = null;
     }
 
     private static Transition loadTransition(Context context, TypedArray typedArray,
index 78a054b..0631943 100644 (file)
@@ -1525,7 +1525,7 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
             throw new IllegalStateException("Must be called from main thread of fragment host");
         }
 
-        if (allowStateLoss) {
+        if (!allowStateLoss) {
             checkStateLoss();
         }
 
@@ -1625,7 +1625,9 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
             final BackStackRecord bss = mBackStack.remove(last);
             SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
             SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
-            bss.calculateBackFragments(firstOutFragments, lastInFragments);
+            if (mCurState >= Fragment.CREATED) {
+                bss.calculateBackFragments(firstOutFragments, lastInFragments);
+            }
             bss.popFromBackStack(true, null, firstOutFragments, lastInFragments);
             reportBackStackChanged();
         } else {
@@ -1672,8 +1674,10 @@ final class FragmentManagerImpl extends FragmentManager implements LayoutInflate
             final int LAST = states.size()-1;
             SparseArray<Fragment> firstOutFragments = new SparseArray<Fragment>();
             SparseArray<Fragment> lastInFragments = new SparseArray<Fragment>();
-            for (int i=0; i<=LAST; i++) {
-                states.get(i).calculateBackFragments(firstOutFragments, lastInFragments);
+            if (mCurState >= Fragment.CREATED) {
+                for (int i = 0; i <= LAST; i++) {
+                    states.get(i).calculateBackFragments(firstOutFragments, lastInFragments);
+                }
             }
             BackStackRecord.TransitionState state = null;
             for (int i=0; i<=LAST; i++) {
index 2cb6151..70bff80 100644 (file)
@@ -143,7 +143,7 @@ public interface IActivityManager extends IInterface {
     public boolean moveActivityTaskToBack(IBinder token, boolean nonRoot) throws RemoteException;
     public void moveTaskBackwards(int task) throws RemoteException;
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) throws RemoteException;
-    public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
+    public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) throws RemoteException;
     public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
     public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode,
@@ -171,6 +171,16 @@ public interface IActivityManager extends IInterface {
     public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
             Rect tempDockedTaskInsetBounds,
             Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) throws RemoteException;
+    /**
+     * Resizes the pinned stack.
+     *
+     * @param pinnedBounds The bounds for the pinned stack.
+     * @param tempPinnedTaskBounds The temporary bounds for the tasks in the pinned stack, which
+     *                             might be different from the stack bounds to allow more
+     *                             flexibility while resizing, or {@code null} if they should be the
+     *                             same as the stack bounds.
+     */
+    public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) throws RemoteException;
     public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
     public List<StackInfo> getAllStackInfos() throws RemoteException;
     public StackInfo getStackInfo(int stackId) throws RemoteException;
@@ -305,7 +315,7 @@ public interface IActivityManager extends IInterface {
         String packageName, boolean waitForDebugger, boolean persistent)
         throws RemoteException;
     public void setAlwaysFinish(boolean enabled) throws RemoteException;
-    public void setActivityController(IActivityController watcher)
+    public void setActivityController(IActivityController watcher, boolean imAMonkey)
         throws RemoteException;
     public void setLenientBackgroundCheck(boolean enabled) throws RemoteException;
     public int getMemoryTrimLevel() throws RemoteException;
@@ -982,4 +992,5 @@ public interface IActivityManager extends IInterface {
     int REMOVE_STACK = IBinder.FIRST_CALL_TRANSACTION + 367;
     int SET_LENIENT_BACKGROUND_CHECK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+368;
     int GET_MEMORY_TRIM_LEVEL_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION+369;
+    int RESIZE_PINNED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 370;
 }
index b55da88..628bde0 100644 (file)
@@ -123,8 +123,13 @@ public interface IApplicationThread extends IInterface {
     void dumpHeap(boolean managed, String path, ParcelFileDescriptor fd)
             throws RemoteException;
     void setSchedulingGroup(int group) throws RemoteException;
+    // the package has been removed, clean up internal references
     static final int PACKAGE_REMOVED = 0;
     static final int EXTERNAL_STORAGE_UNAVAILABLE = 1;
+    // the package is being modified in-place, don't kill it and retain references to it
+    static final int PACKAGE_REMOVED_DONT_KILL = 2;
+    // a previously removed package was replaced with a new version [eg. upgrade, split added, ...]
+    static final int PACKAGE_REPLACED = 3;
     void dispatchPackageBroadcast(int cmd, String[] packages) throws RemoteException;
     void scheduleCrash(String msg) throws RemoteException;
     void dumpActivity(FileDescriptor fd, IBinder servicetoken, String prefix, String[] args)
@@ -133,7 +138,8 @@ public interface IApplicationThread extends IInterface {
     void updatePackageCompatibilityInfo(String pkg, CompatibilityInfo info) throws RemoteException;
     void scheduleTrimMemory(int level) throws RemoteException;
     void dumpMemInfo(FileDescriptor fd, Debug.MemoryInfo mem, boolean checkin, boolean dumpInfo,
-            boolean dumpDalvik, boolean dumpSummaryOnly, String[] args) throws RemoteException;
+            boolean dumpDalvik, boolean dumpSummaryOnly, boolean dumpUnreachable,
+            String[] args) throws RemoteException;
     void dumpGfxInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void dumpDbInfo(FileDescriptor fd, String[] args) throws RemoteException;
     void unstableProviderDied(IBinder provider) throws RemoteException;
index 8be00aa..5697924 100644 (file)
@@ -97,9 +97,9 @@ interface INotificationManager
     boolean isNotificationPolicyAccessGrantedForPackage(String pkg);
     void setNotificationPolicyAccessGranted(String pkg, boolean granted);
     AutomaticZenRule getAutomaticZenRule(String id);
-    List<AutomaticZenRule> getAutomaticZenRules();
-    AutomaticZenRule addAutomaticZenRule(in AutomaticZenRule automaticZenRule);
-    boolean updateAutomaticZenRule(in AutomaticZenRule automaticZenRule);
+    List<ZenModeConfig.ZenRule> getZenRules();
+    String addAutomaticZenRule(in AutomaticZenRule automaticZenRule);
+    boolean updateAutomaticZenRule(String id, in AutomaticZenRule automaticZenRule);
     boolean removeAutomaticZenRule(String id);
     boolean removeAutomaticZenRules(String packageName);
     int getRuleInstanceCount(in ComponentName owner);
index 06fe515..cd17078 100644 (file)
@@ -58,6 +58,7 @@ import java.lang.reflect.Method;
 import java.net.URL;
 import java.util.List;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Enumeration;
 import java.util.Objects;
@@ -83,24 +84,25 @@ public final class LoadedApk {
     private static final String TAG = "LoadedApk";
 
     private final ActivityThread mActivityThread;
-    private ApplicationInfo mApplicationInfo;
     final String mPackageName;
-    private final String mAppDir;
-    private final String mResDir;
-    private final String[] mSplitAppDirs;
-    private final String[] mSplitResDirs;
-    private final String[] mOverlayDirs;
-    private final String[] mSharedLibraries;
-    private final String mDataDir;
-    private final String mLibDir;
-    private final File mDataDirFile;
-    private final File mDeviceEncryptedDataDirFile;
-    private final File mCredentialEncryptedDataDirFile;
+    private ApplicationInfo mApplicationInfo;
+    private String mAppDir;
+    private String mResDir;
+    private String[] mSplitAppDirs;
+    private String[] mSplitResDirs;
+    private String[] mOverlayDirs;
+    private String[] mSharedLibraries;
+    private String mDataDir;
+    private String mLibDir;
+    private File mDataDirFile;
+    private File mDeviceEncryptedDataDirFile;
+    private File mCredentialEncryptedDataDirFile;
     private final ClassLoader mBaseClassLoader;
     private final boolean mSecurityViolation;
     private final boolean mIncludeCode;
     private final boolean mRegisterPackage;
     private final DisplayAdjustments mDisplayAdjustments = new DisplayAdjustments();
+    /** WARNING: This may change. Don't hold external references to it. */
     Resources mResources;
     private ClassLoader mClassLoader;
     private Application mApplication;
@@ -129,23 +131,10 @@ public final class LoadedApk {
     public LoadedApk(ActivityThread activityThread, ApplicationInfo aInfo,
             CompatibilityInfo compatInfo, ClassLoader baseLoader,
             boolean securityViolation, boolean includeCode, boolean registerPackage) {
-        final int myUid = Process.myUid();
-        aInfo = adjustNativeLibraryPaths(aInfo);
 
         mActivityThread = activityThread;
-        mApplicationInfo = aInfo;
+        setApplicationInfo(aInfo);
         mPackageName = aInfo.packageName;
-        mAppDir = aInfo.sourceDir;
-        mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
-        mSplitAppDirs = aInfo.splitSourceDirs;
-        mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
-        mOverlayDirs = aInfo.resourceDirs;
-        mSharedLibraries = aInfo.sharedLibraryFiles;
-        mDataDir = aInfo.dataDir;
-        mDataDirFile = FileUtils.newFileOrNull(mDataDir);
-        mDeviceEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceEncryptedDataDir);
-        mCredentialEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialEncryptedDataDir);
-        mLibDir = aInfo.nativeLibraryDir;
         mBaseClassLoader = baseLoader;
         mSecurityViolation = securityViolation;
         mIncludeCode = includeCode;
@@ -266,130 +255,189 @@ public final class LoadedApk {
         return ai.sharedLibraryFiles;
     }
 
-    public ClassLoader getClassLoader() {
+    public void updateApplicationInfo(ApplicationInfo aInfo, List<String> oldPaths) {
+        setApplicationInfo(aInfo);
+
+        final List<String> newPaths = new ArrayList<>();
+        makePaths(mActivityThread, aInfo, newPaths, null /*libPaths*/);
+        final List<String> addedPaths = new ArrayList<>(newPaths.size());
+
+        if (oldPaths != null) {
+            for (String path : newPaths) {
+                final String apkName = path.substring(path.lastIndexOf(File.separator));
+                boolean match = false;
+                for (String oldPath : oldPaths) {
+                    final String oldApkName = oldPath.substring(path.lastIndexOf(File.separator));
+                    if (apkName.equals(oldApkName)) {
+                        match = true;
+                        break;
+                    }
+                }
+                if (!match) {
+                    addedPaths.add(path);
+                }
+            }
+        } else {
+            addedPaths.addAll(newPaths);
+        }
         synchronized (this) {
-            if (mClassLoader != null) {
-                return mClassLoader;
+            mClassLoader = createOrUpdateClassLoaderLocked(addedPaths);
+            if (mResources != null) {
+                mResources = mActivityThread.getNewTopLevelResources(mResDir, mSplitResDirs,
+                        mOverlayDirs, mApplicationInfo.sharedLibraryFiles, Display.DEFAULT_DISPLAY,
+                        null /*overrideConfiguration*/, this);
             }
+        }
+    }
 
-            if (mPackageName.equals("android")) {
-                if (mBaseClassLoader == null) {
-                    mClassLoader = ClassLoader.getSystemClassLoader();
-                } else {
-                    mClassLoader = mBaseClassLoader;
-                }
-                return mClassLoader;
-            }
+    private void setApplicationInfo(ApplicationInfo aInfo) {
+        final int myUid = Process.myUid();
+        aInfo = adjustNativeLibraryPaths(aInfo);
+        mApplicationInfo = aInfo;
+        mAppDir = aInfo.sourceDir;
+        mResDir = aInfo.uid == myUid ? aInfo.sourceDir : aInfo.publicSourceDir;
+        mSplitAppDirs = aInfo.splitSourceDirs;
+        mSplitResDirs = aInfo.uid == myUid ? aInfo.splitSourceDirs : aInfo.splitPublicSourceDirs;
+        mOverlayDirs = aInfo.resourceDirs;
+        mSharedLibraries = aInfo.sharedLibraryFiles;
+        mDataDir = aInfo.dataDir;
+        mLibDir = aInfo.nativeLibraryDir;
+        mDataDirFile = FileUtils.newFileOrNull(aInfo.dataDir);
+        mDeviceEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.deviceEncryptedDataDir);
+        mCredentialEncryptedDataDirFile = FileUtils.newFileOrNull(aInfo.credentialEncryptedDataDir);
+    }
 
-            // Avoid the binder call when the package is the current application package.
-            // The activity manager will perform ensure that dexopt is performed before
-            // spinning up the process.
-            if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
-                final String isa = VMRuntime.getRuntime().vmInstructionSet();
-                try {
-                    ActivityThread.getPackageManager().notifyPackageUse(mPackageName);
-                } catch (RemoteException re) {
-                    throw re.rethrowFromSystemServer();
-                }
-            }
+    public static void makePaths(ActivityThread activityThread, ApplicationInfo aInfo,
+            List<String> outZipPaths, List<String> outLibPaths) {
+        final String appDir = aInfo.sourceDir;
+        final String[] splitAppDirs = aInfo.splitSourceDirs;
+        final String libDir = aInfo.nativeLibraryDir;
+        final String[] sharedLibraries = aInfo.sharedLibraryFiles;
+
+        outZipPaths.clear();
+        outZipPaths.add(appDir);
+        if (splitAppDirs != null) {
+            Collections.addAll(outZipPaths, splitAppDirs);
+        }
 
-            final List<String> zipPaths = new ArrayList<>();
-            final List<String> apkPaths = new ArrayList<>();
-            final List<String> libPaths = new ArrayList<>();
+        if (outLibPaths != null) {
+            outLibPaths.clear();
+        }
 
-            if (mRegisterPackage) {
-                try {
-                    ActivityManagerNative.getDefault().addPackageDependency(mPackageName);
-                } catch (RemoteException e) {
-                    throw e.rethrowFromSystemServer();
-                }
+        /*
+         * The following is a bit of a hack to inject
+         * instrumentation into the system: If the app
+         * being started matches one of the instrumentation names,
+         * then we combine both the "instrumentation" and
+         * "instrumented" app into the path, along with the
+         * concatenation of both apps' shared library lists.
+         */
+
+        String instrumentationPackageName = activityThread.mInstrumentationPackageName;
+        String instrumentationAppDir = activityThread.mInstrumentationAppDir;
+        String[] instrumentationSplitAppDirs = activityThread.mInstrumentationSplitAppDirs;
+        String instrumentationLibDir = activityThread.mInstrumentationLibDir;
+
+        String instrumentedAppDir = activityThread.mInstrumentedAppDir;
+        String[] instrumentedSplitAppDirs = activityThread.mInstrumentedSplitAppDirs;
+        String instrumentedLibDir = activityThread.mInstrumentedLibDir;
+        String[] instrumentationLibs = null;
+
+        if (appDir.equals(instrumentationAppDir)
+                || appDir.equals(instrumentedAppDir)) {
+            outZipPaths.clear();
+            outZipPaths.add(instrumentationAppDir);
+            if (instrumentationSplitAppDirs != null) {
+                Collections.addAll(outZipPaths, instrumentationSplitAppDirs);
+            }
+            outZipPaths.add(instrumentedAppDir);
+            if (instrumentedSplitAppDirs != null) {
+                Collections.addAll(outZipPaths, instrumentedSplitAppDirs);
             }
 
-            zipPaths.add(mAppDir);
-            if (mSplitAppDirs != null) {
-                Collections.addAll(zipPaths, mSplitAppDirs);
+            if (outLibPaths != null) {
+                outLibPaths.add(instrumentationLibDir);
+                outLibPaths.add(instrumentedLibDir);
             }
 
-            libPaths.add(mLibDir);
+            if (!instrumentedAppDir.equals(instrumentationAppDir)) {
+                instrumentationLibs = getLibrariesFor(instrumentationPackageName);
+            }
+        }
 
-            /*
-             * The following is a bit of a hack to inject
-             * instrumentation into the system: If the app
-             * being started matches one of the instrumentation names,
-             * then we combine both the "instrumentation" and
-             * "instrumented" app into the path, along with the
-             * concatenation of both apps' shared library lists.
-             */
+        if (outLibPaths != null) {
+            if (outLibPaths.isEmpty()) {
+                outLibPaths.add(libDir);
+            }
 
-            String instrumentationPackageName = mActivityThread.mInstrumentationPackageName;
-            String instrumentationAppDir = mActivityThread.mInstrumentationAppDir;
-            String[] instrumentationSplitAppDirs = mActivityThread.mInstrumentationSplitAppDirs;
-            String instrumentationLibDir = mActivityThread.mInstrumentationLibDir;
-
-            String instrumentedAppDir = mActivityThread.mInstrumentedAppDir;
-            String[] instrumentedSplitAppDirs = mActivityThread.mInstrumentedSplitAppDirs;
-            String instrumentedLibDir = mActivityThread.mInstrumentedLibDir;
-            String[] instrumentationLibs = null;
-
-            if (mAppDir.equals(instrumentationAppDir)
-                    || mAppDir.equals(instrumentedAppDir)) {
-                zipPaths.clear();
-                zipPaths.add(instrumentationAppDir);
-                if (instrumentationSplitAppDirs != null) {
-                    Collections.addAll(zipPaths, instrumentationSplitAppDirs);
-                }
-                zipPaths.add(instrumentedAppDir);
-                if (instrumentedSplitAppDirs != null) {
-                    Collections.addAll(zipPaths, instrumentedSplitAppDirs);
+            // Add path to libraries in apk for current abi. Do this now because more entries
+            // will be added to zipPaths that shouldn't be part of the library path.
+            if (aInfo.primaryCpuAbi != null) {
+                for (String apk : outZipPaths) {
+                    outLibPaths.add(apk + "!/lib/" + aInfo.primaryCpuAbi);
                 }
+            }
 
-                libPaths.clear();
-                libPaths.add(instrumentationLibDir);
-                libPaths.add(instrumentedLibDir);
+            if (aInfo.isSystemApp() && !aInfo.isUpdatedSystemApp()) {
+                // Add path to system libraries to libPaths;
+                // Access to system libs should be limited
+                // to bundled applications; this is why updated
+                // system apps are not included.
+                outLibPaths.add(System.getProperty("java.library.path"));
+            }
+        }
 
-                if (!instrumentedAppDir.equals(instrumentationAppDir)) {
-                    instrumentationLibs = getLibrariesFor(instrumentationPackageName);
+        if (sharedLibraries != null) {
+            for (String lib : sharedLibraries) {
+                if (!outZipPaths.contains(lib)) {
+                    outZipPaths.add(0, lib);
                 }
             }
+        }
 
-            apkPaths.addAll(zipPaths);
-
-            if (mSharedLibraries != null) {
-                for (String lib : mSharedLibraries) {
-                    if (!zipPaths.contains(lib)) {
-                        zipPaths.add(0, lib);
-                    }
+        if (instrumentationLibs != null) {
+            for (String lib : instrumentationLibs) {
+                if (!outZipPaths.contains(lib)) {
+                    outZipPaths.add(0, lib);
                 }
             }
+        }
 
-            if (instrumentationLibs != null) {
-                for (String lib : instrumentationLibs) {
-                    if (!zipPaths.contains(lib)) {
-                        zipPaths.add(0, lib);
-                    }
+        final String zip = TextUtils.join(File.pathSeparator, outZipPaths);
+    }
+
+    private ClassLoader createOrUpdateClassLoaderLocked(List<String> addedPaths) {
+        final ClassLoader classLoader;
+        if (mIncludeCode && !mPackageName.equals("android")) {
+            // Avoid the binder call when the package is the current application package.
+            // The activity manager will perform ensure that dexopt is performed before
+            // spinning up the process.
+            if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
+                VMRuntime.getRuntime().vmInstructionSet();
+                try {
+                    ActivityThread.getPackageManager().notifyPackageUse(mPackageName);
+                } catch (RemoteException re) {
+                    throw re.rethrowFromSystemServer();
                 }
             }
 
-            final String zip = mIncludeCode ? TextUtils.join(File.pathSeparator, zipPaths) : "";
+            final List<String> zipPaths = new ArrayList<>();
+            final List<String> libPaths = new ArrayList<>();
 
-            // Add path to libraries in apk for current abi
-            if (mApplicationInfo.primaryCpuAbi != null) {
-                for (String apk : apkPaths) {
-                  libPaths.add(apk + "!/lib/" + mApplicationInfo.primaryCpuAbi);
+            if (mRegisterPackage) {
+                try {
+                    ActivityManagerNative.getDefault().addPackageDependency(mPackageName);
+                } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
             }
 
+            makePaths(mActivityThread, mApplicationInfo, zipPaths, libPaths);
+            final String zip = TextUtils.join(File.pathSeparator, zipPaths);
+            final boolean isBundledApp = mApplicationInfo.isSystemApp()
+                    && !mApplicationInfo.isUpdatedSystemApp();
             String libraryPermittedPath = mDataDir;
-            boolean isBundledApp = false;
-
-            if (mApplicationInfo.isSystemApp()) {
-                isBundledApp = true;
-                // Add path to system libraries to libPaths;
-                // Access to system libs should be limited
-                // to bundled applications; this is why updated
-                // system apps are not included.
-                libPaths.add(System.getProperty("java.library.path"));
-
+            if (isBundledApp) {
                 // This is necessary to grant bundled apps access to
                 // libraries located in subdirectories of /system/lib
                 libraryPermittedPath += File.pathSeparator +
@@ -414,15 +462,42 @@ public final class LoadedApk {
                 Slog.v(ActivityThread.TAG, "Class path: " + zip +
                         ", JNI path: " + librarySearchPath);
 
-            // Temporarily disable logging of disk reads on the Looper thread
-            // as this is early and necessary.
-            StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+            if (mClassLoader == null) {
+                // Temporarily disable logging of disk reads on the Looper thread
+                // as this is early and necessary.
+                StrictMode.ThreadPolicy oldPolicy = StrictMode.allowThreadDiskReads();
+
+                classLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
+                        mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
+                        libraryPermittedPath, mBaseClassLoader);
 
-            mClassLoader = ApplicationLoaders.getDefault().getClassLoader(zip,
-                    mApplicationInfo.targetSdkVersion, isBundledApp, librarySearchPath,
-                    libraryPermittedPath, mBaseClassLoader);
+                StrictMode.setThreadPolicy(oldPolicy);
+            } else if (addedPaths != null && addedPaths.size() > 0) {
+                final String add = TextUtils.join(File.pathSeparator, addedPaths);
+                ApplicationLoaders.getDefault().addPath(mClassLoader, add);
+                classLoader = mClassLoader;
+            } else {
+                classLoader = mClassLoader;
+            }
+        } else {
+            if (mClassLoader == null) {
+                if (mBaseClassLoader == null) {
+                    classLoader = ClassLoader.getSystemClassLoader();
+                } else {
+                    classLoader = mBaseClassLoader;
+                }
+            } else {
+                classLoader = mClassLoader;
+            }
+        }
+        return classLoader;
+    }
 
-            StrictMode.setThreadPolicy(oldPolicy);
+    public ClassLoader getClassLoader() {
+        synchronized (this) {
+            if (mClassLoader == null) {
+                mClassLoader = createOrUpdateClassLoaderLocked(null /*addedPaths*/);
+            }
             return mClassLoader;
         }
     }
@@ -1103,7 +1178,6 @@ public final class LoadedApk {
 
         private RuntimeException mUnbindLocation;
 
-        private boolean mDied;
         private boolean mForgotten;
 
         private static class ConnectionInfo {
@@ -1202,7 +1276,6 @@ public final class LoadedApk {
             ServiceDispatcher.ConnectionInfo old;
 
             synchronized (this) {
-                mDied = true;
                 old = mActiveConnections.remove(name);
                 if (old == null || old.binder != service) {
                     // Death for someone different than who we last
@@ -1237,7 +1310,6 @@ public final class LoadedApk {
 
                 if (service != null) {
                     // A new service is being connected... set it all up.
-                    mDied = false;
                     info = new ConnectionInfo();
                     info.binder = service;
                     info.deathMonitor = new DeathMonitor(name, service);
index 873e337..2a1e3c2 100644 (file)
@@ -144,7 +144,7 @@ public class LocalActivityManager {
             
             if (desiredState == RESUMED) {
                 if (localLOGV) Log.v(TAG, r.id + ": resuming");
-                mActivityThread.performResumeActivity(r, true);
+                mActivityThread.performResumeActivity(r, true, "moveToState-INITIALIZING");
                 r.curState = RESUMED;
             }
             
@@ -167,7 +167,7 @@ public class LocalActivityManager {
                 if (desiredState == RESUMED) {
                     if (localLOGV) Log.v(TAG, r.id + ": restarting and resuming");
                     mActivityThread.performRestartActivity(r);
-                    mActivityThread.performResumeActivity(r, true);
+                    mActivityThread.performResumeActivity(r, true, "moveToState-CREATED");
                     r.curState = RESUMED;
                 }
                 return;
@@ -176,13 +176,13 @@ public class LocalActivityManager {
                 if (desiredState == RESUMED) {
                     // Need to resume it...
                     if (localLOGV) Log.v(TAG, r.id + ": resuming");
-                    mActivityThread.performResumeActivity(r, true);
+                    mActivityThread.performResumeActivity(r, true, "moveToState-STARTED");
                     r.instanceState = null;
                     r.curState = RESUMED;
                 }
                 if (desiredState == CREATED) {
                     if (localLOGV) Log.v(TAG, r.id + ": stopping");
-                    mActivityThread.performStopActivity(r, false);
+                    mActivityThread.performStopActivity(r, false, "moveToState-STARTED");
                     r.curState = CREATED;
                 }
                 return;
@@ -197,7 +197,7 @@ public class LocalActivityManager {
                     if (localLOGV) Log.v(TAG, r.id + ": pausing");
                     performPause(r, mFinishing);
                     if (localLOGV) Log.v(TAG, r.id + ": stopping");
-                    mActivityThread.performStopActivity(r, false);
+                    mActivityThread.performStopActivity(r, false, "moveToState-RESUMED");
                     r.curState = CREATED;
                 }
                 return;
@@ -205,9 +205,9 @@ public class LocalActivityManager {
     }
     
     private void performPause(LocalActivityRecord r, boolean finishing) {
-        boolean needState = r.instanceState == null;
-        Bundle instanceState = mActivityThread.performPauseActivity(r,
-                finishing, needState);
+        final boolean needState = r.instanceState == null;
+        final Bundle instanceState = mActivityThread.performPauseActivity(
+                r, finishing, needState, "performPause");
         if (needState) {
             r.instanceState = instanceState;
         }
index 344315d..16aee78 100644 (file)
@@ -48,8 +48,12 @@ import android.util.Log;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Objects;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Class to notify the user of events that happen.  This is how you tell
@@ -413,13 +417,20 @@ public class NotificationManager
      * Returns AutomaticZenRules owned by the caller.
      *
      * <p>
-     * Only available if policy access is granted to this package.
+     * Throws a SecurityException if policy access is granted to this package.
      * See {@link #isNotificationPolicyAccessGranted}.
      */
-    public List<AutomaticZenRule> getAutomaticZenRules() {
+    public Map<String, AutomaticZenRule> getAutomaticZenRules() {
         INotificationManager service = getService();
         try {
-            return service.getAutomaticZenRules();
+            List<ZenModeConfig.ZenRule> rules = service.getZenRules();
+            Map<String, AutomaticZenRule> ruleMap = new HashMap<>();
+            for (ZenModeConfig.ZenRule rule : rules) {
+                ruleMap.put(rule.id, new AutomaticZenRule(rule.name, rule.component,
+                        rule.conditionId, zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
+                        rule.creationTime));
+            }
+            return ruleMap;
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -429,7 +440,7 @@ public class NotificationManager
      * Returns the AutomaticZenRule with the given id, if it exists and the caller has access.
      *
      * <p>
-     * Only available if policy access is granted to this package.
+     * Throws a SecurityException if policy access is granted to this package.
      * See {@link #isNotificationPolicyAccessGranted}.
      *
      * <p>
@@ -449,14 +460,13 @@ public class NotificationManager
      * Creates the given zen rule.
      *
      * <p>
-     * Only available if policy access is granted to this package.
+     * Throws a SecurityException if policy access is granted to this package.
      * See {@link #isNotificationPolicyAccessGranted}.
      *
      * @param automaticZenRule the rule to create.
-     * @return A fully populated {@link AutomaticZenRule} if the rule was persisted successfully,
-     * null otherwise.
+     * @return The id of the newly created rule; null if the rule could not be created.
      */
-    public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
+    public String addAutomaticZenRule(AutomaticZenRule automaticZenRule) {
         INotificationManager service = getService();
         try {
             return service.addAutomaticZenRule(automaticZenRule);
@@ -469,18 +479,19 @@ public class NotificationManager
      * Updates the given zen rule.
      *
      * <p>
-     * Only available if policy access is granted to this package.
+     * Throws a SecurityException if policy access is granted to this package.
      * See {@link #isNotificationPolicyAccessGranted}.
      *
      * <p>
      * Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}.
+     * @param id The id of the rule to update
      * @param automaticZenRule the rule to update. 
      * @return Whether the rule was successfully updated.
      */
-    public boolean updateAutomaticZenRule(AutomaticZenRule automaticZenRule) {
+    public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule) {
         INotificationManager service = getService();
         try {
-            return service.updateAutomaticZenRule(automaticZenRule);
+            return service.updateAutomaticZenRule(id, automaticZenRule);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -490,7 +501,7 @@ public class NotificationManager
      * Deletes the automatic zen rule with the given id.
      *
      * <p>
-     * Only available if policy access is granted to this package.
+     * Throws a SecurityException if policy access is granted to this package.
      * See {@link #isNotificationPolicyAccessGranted}.
      *
      * <p>
@@ -651,7 +662,7 @@ public class NotificationManager
 
     /**
      * Notification policy configuration.  Represents user-preferences for notification
-     * filtering and prioritization.
+     * filtering.
      */
     public static class Policy implements android.os.Parcelable {
         /** Reminder notifications are prioritized. */
@@ -696,13 +707,13 @@ public class NotificationManager
          */
         public static final int SUPPRESSED_EFFECTS_UNSET = -1;
         /**
-         * Whether notification suppressed by DND should not interruption visually when the screen
-         * is off.
+         * Whether notifications suppressed by DND should not interrupt visually (e.g. with
+         * notification lights or by turning the screen on) when the screen is off.
          */
         public static final int SUPPRESSED_EFFECT_SCREEN_OFF = 1 << 0;
         /**
-         * Whether notification suppressed by DND should not interruption visually when the screen
-         * is on.
+         * Whether notifications suppressed by DND should not interrupt visually when the screen
+         * is on (e.g. by peeking onto the screen).
          */
         public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 1;
 
@@ -717,13 +728,27 @@ public class NotificationManager
          */
         public final int suppressedVisualEffects;
 
-
-        @Deprecated
+        /**
+         * Constructs a policy for Do Not Disturb priority mode behavior.
+         *
+         * @param priorityCategories bitmask of categories of notifications that can bypass DND.
+         * @param priorityCallSenders which callers can bypass DND.
+         * @param priorityMessageSenders which message senders can bypass DND.
+         */
         public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders) {
             this(priorityCategories, priorityCallSenders, priorityMessageSenders,
                     SUPPRESSED_EFFECTS_UNSET);
         }
 
+        /**
+         * Constructs a policy for Do Not Disturb priority mode behavior.
+         *
+         * @param priorityCategories bitmask of categories of notifications that can bypass DND.
+         * @param priorityCallSenders which callers can bypass DND.
+         * @param priorityMessageSenders which message senders can bypass DND.
+         * @param suppressedVisualEffects which visual interruptions should be suppressed from
+         *                                notifications that are filtered by DND.
+         */
         public Policy(int priorityCategories, int priorityCallSenders, int priorityMessageSenders,
                 int suppressedVisualEffects) {
             this.priorityCategories = priorityCategories;
@@ -854,7 +879,6 @@ public class NotificationManager
                 return new Policy[size];
             }
         };
-
     }
 
     /**
@@ -879,9 +903,8 @@ public class NotificationManager
             final List<StatusBarNotification> list = parceledList.getList();
             return list.toArray(new StatusBarNotification[list.size()]);
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to talk to notification manager. Woe!", e);
+            throw e.rethrowFromSystemServer();
         }
-        return new StatusBarNotification[0];
     }
 
     /**
@@ -902,9 +925,8 @@ public class NotificationManager
         try {
             return zenModeToInterruptionFilter(service.getZenMode());
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to talk to notification manager. Woe!", e);
+            throw e.rethrowFromSystemServer();
         }
-        return INTERRUPTION_FILTER_UNKNOWN;
     }
 
     /**
@@ -925,7 +947,7 @@ public class NotificationManager
         try {
             service.setInterruptionFilter(mContext.getOpPackageName(), interruptionFilter);
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to talk to notification manager. Woe!", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
index 94e584e..bc44553 100644 (file)
@@ -23,6 +23,7 @@ import android.content.res.AssetManager;
 import android.content.res.CompatibilityInfo;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.ResourcesImpl;
 import android.content.res.ResourcesKey;
 import android.hardware.display.DisplayManagerGlobal;
 import android.util.ArrayMap;
@@ -250,7 +251,8 @@ public class ResourcesManager {
         } else {
             config = getConfiguration();
         }
-        r = new Resources(assets, dm, config, compatInfo, classLoader);
+        r = new Resources(classLoader);
+        r.setImpl(new ResourcesImpl(assets, dm, config, compatInfo));
         if (DEBUG) Slog.i(TAG, "Created app resources " + resDir + " " + r + ": "
                 + r.getConfiguration() + " appScale=" + r.getCompatibilityInfo().applicationScale);
 
@@ -288,6 +290,19 @@ public class ResourcesManager {
         }
     }
 
+    /**
+     * Removes the top level Resources for applications with the given compatibility info.
+     * @see #getTopLevelResources(String, String[], String[], String[], int, Configuration, CompatibilityInfo, ClassLoader)
+     */
+    void removeTopLevelResources(String resDir, int displayId, Configuration overrideConfiguration,
+            CompatibilityInfo compatInfo) {
+        final float scale = compatInfo.applicationScale;
+        final Configuration overrideConfigCopy = (overrideConfiguration != null)
+                ? new Configuration(overrideConfiguration) : null;
+        final ResourcesKey key = new ResourcesKey(resDir, displayId, overrideConfigCopy, scale);
+        mActiveResources.remove(key);
+    }
+
     /* package */ void setDefaultLocalesLocked(LocaleList locales) {
         final int bestLocale;
         if (mHasNonSystemLocales) {
index 9e32164..ac4abf5 100644 (file)
@@ -686,8 +686,7 @@ public class SearchManager
         try {
             return mService.getGlobalSearchActivities();
         } catch (RemoteException ex) {
-            Log.e(TAG, "getGlobalSearchActivities() failed: " + ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -698,8 +697,7 @@ public class SearchManager
         try {
             return mService.getGlobalSearchActivity();
         } catch (RemoteException ex) {
-            Log.e(TAG, "getGlobalSearchActivity() failed: " + ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -716,8 +714,7 @@ public class SearchManager
         try {
             return mService.getWebSearchActivity();
         } catch (RemoteException ex) {
-            Log.e(TAG, "getWebSearchActivity() failed: " + ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -850,8 +847,7 @@ public class SearchManager
         try {
             return mService.getSearchableInfo(componentName);
         } catch (RemoteException ex) {
-            Log.e(TAG, "getSearchableInfo() failed: " + ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -935,8 +931,7 @@ public class SearchManager
         try {
             return mService.getSearchablesInGlobalSearch();
         } catch (RemoteException e) {
-            Log.e(TAG, "getSearchablesInGlobalSearch() failed: " + e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -958,8 +953,7 @@ public class SearchManager
             }
             return intent;
         } catch (RemoteException re) {
-            Log.e(TAG, "getAssistIntent() failed: " + re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -977,7 +971,7 @@ public class SearchManager
             }
             mService.launchAssist(args);
         } catch (RemoteException re) {
-            Log.e(TAG, "launchAssist() failed: " + re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -995,8 +989,7 @@ public class SearchManager
             }
             return mService.launchLegacyAssist(hint, userHandle, args);
         } catch (RemoteException re) {
-            Log.e(TAG, "launchAssist() failed: " + re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 }
index b899116..e57a9b5 100644 (file)
@@ -123,8 +123,7 @@ public class StatusBarManager {
                 svc.disable(what, mToken, mContext.getPackageName());
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -141,8 +140,7 @@ public class StatusBarManager {
                 svc.disable2(what, mToken, mContext.getPackageName());
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -156,8 +154,7 @@ public class StatusBarManager {
                 svc.expandNotificationsPanel();
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
     
@@ -171,8 +168,7 @@ public class StatusBarManager {
                 svc.collapsePanels();
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -193,8 +189,7 @@ public class StatusBarManager {
                 svc.expandSettingsPanel(subPanel);
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -206,8 +201,7 @@ public class StatusBarManager {
                     contentDescription);
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -218,8 +212,7 @@ public class StatusBarManager {
                 svc.removeIcon(slot);
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -230,8 +223,7 @@ public class StatusBarManager {
                 svc.setIconVisibility(slot, visible);
             }
         } catch (RemoteException ex) {
-            // system process is dead anyway.
-            throw new RuntimeException(ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
index 307c3eb..b1c5fd8 100644 (file)
@@ -226,7 +226,7 @@ final class SystemServiceRegistry {
         SYSTEM_SERVICE_NAMES.put(android.text.ClipboardManager.class, Context.CLIPBOARD_SERVICE);
 
         registerService(Context.CONNECTIVITY_SERVICE, ConnectivityManager.class,
-                new StaticOuterContextServiceFetcher<ConnectivityManager>() {
+                new StaticApplicationContextServiceFetcher<ConnectivityManager>() {
             @Override
             public ConnectivityManager createService(Context context) {
                 IBinder b = ServiceManager.getService(Context.CONNECTIVITY_SERVICE);
@@ -840,22 +840,21 @@ final class SystemServiceRegistry {
     }
 
     /**
-     * Like StaticServiceFetcher, creates only one instance of the service per process, but when
-     * creating the service for the first time, passes it the outer context of the creating
-     * component.
+     * Like StaticServiceFetcher, creates only one instance of the service per application, but when
+     * creating the service for the first time, passes it the application context of the creating
+     * application.
      *
-     * TODO: Is this safe in the case where multiple applications share the same process?
      * TODO: Delete this once its only user (ConnectivityManager) is known to work well in the
      * case where multiple application components each have their own ConnectivityManager object.
      */
-    static abstract class StaticOuterContextServiceFetcher<T> implements ServiceFetcher<T> {
+    static abstract class StaticApplicationContextServiceFetcher<T> implements ServiceFetcher<T> {
         private T mCachedInstance;
 
         @Override
         public final T getService(ContextImpl ctx) {
-            synchronized (StaticOuterContextServiceFetcher.this) {
+            synchronized (StaticApplicationContextServiceFetcher.this) {
                 if (mCachedInstance == null) {
-                    mCachedInstance = createService(ctx.getOuterContext());
+                    mCachedInstance = createService(ctx.getApplicationContext());
                 }
                 return mCachedInstance;
             }
index 56b4249..69e8df8 100644 (file)
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.annotation.IntDef;
+import android.annotation.TestApi;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.os.RemoteException;
@@ -158,7 +159,7 @@ public class UiModeManager {
             try {
                 mService.enableCarMode(flags);
             } catch (RemoteException e) {
-                Log.e(TAG, "disableCarMode: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -181,7 +182,7 @@ public class UiModeManager {
             try {
                 mService.disableCarMode(flags);
             } catch (RemoteException e) {
-                Log.e(TAG, "disableCarMode: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -200,7 +201,7 @@ public class UiModeManager {
             try {
                 return mService.getCurrentModeType();
             } catch (RemoteException e) {
-                Log.e(TAG, "getCurrentModeType: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return Configuration.UI_MODE_TYPE_NORMAL;
@@ -233,7 +234,7 @@ public class UiModeManager {
             try {
                 mService.setNightMode(mode);
             } catch (RemoteException e) {
-                Log.e(TAG, "setNightMode: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -257,7 +258,7 @@ public class UiModeManager {
             try {
                 return mService.getNightMode();
             } catch (RemoteException e) {
-                Log.e(TAG, "getNightMode: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return -1;
@@ -266,13 +267,15 @@ public class UiModeManager {
     /**
      * @return If UI mode is locked or not. When UI mode is locked, calls to change UI mode
      *         like {@link #enableCarMode(int)} will silently fail.
+     * @hide
      */
+    @TestApi
     public boolean isUiModeLocked() {
         if (mService != null) {
             try {
                 return mService.isUiModeLocked();
             } catch (RemoteException e) {
-                Log.e(TAG, "isUiModeLocked: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return true;
@@ -286,13 +289,15 @@ public class UiModeManager {
      * mode will fail silently.
      *
      * @return {@code true} if night mode is locked or {@code false} otherwise
+     * @hide
      */
+    @TestApi
     public boolean isNightModeLocked() {
         if (mService != null) {
             try {
                 return mService.isNightModeLocked();
             } catch (RemoteException e) {
-                Log.e(TAG, "isNightModeLocked: RemoteException", e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return true;
index b7e31ab..6bc03f7 100644 (file)
@@ -293,7 +293,7 @@ public class WallpaperManager {
                             return null;
                         }
                     } catch (RemoteException e) {
-                        // Ignore
+                        throw e.rethrowFromSystemServer();
                     }
                 }
                 if (mWallpaper != null) {
@@ -349,7 +349,7 @@ public class WallpaperManager {
                     }
                 }
             } catch (RemoteException e) {
-                // Ignore
+                throw e.rethrowFromSystemServer();
             }
             return null;
         }
@@ -691,7 +691,7 @@ public class WallpaperManager {
                 Bundle outParams = new Bundle();
                 return sGlobals.mService.getWallpaper(null, which, outParams, userId);
             } catch (RemoteException e) {
-                return null;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -720,7 +720,7 @@ public class WallpaperManager {
                 return sGlobals.mService.getWallpaperInfo();
             }
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -844,7 +844,7 @@ public class WallpaperManager {
                 }
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
         return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
@@ -950,7 +950,7 @@ public class WallpaperManager {
                 }
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
         return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
     }
@@ -1067,7 +1067,7 @@ public class WallpaperManager {
                 }
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
 
         return result.getInt(EXTRA_NEW_WALLPAPER_ID, 0);
@@ -1088,7 +1088,7 @@ public class WallpaperManager {
             String name = "res:" + resources.getResourceName(resid);
             return sGlobals.mService.hasNamedWallpaper(name);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1114,8 +1114,7 @@ public class WallpaperManager {
         try {
             return sGlobals.mService.getWidthHint();
         } catch (RemoteException e) {
-            // Shouldn't happen!
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1141,8 +1140,7 @@ public class WallpaperManager {
         try {
             return sGlobals.mService.getHeightHint();
         } catch (RemoteException e) {
-            // Shouldn't happen!
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1203,7 +1201,7 @@ public class WallpaperManager {
                         mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1224,7 +1222,7 @@ public class WallpaperManager {
                 sGlobals.mService.setDisplayPadding(padding, mContext.getOpPackageName());
             }
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1245,7 +1243,7 @@ public class WallpaperManager {
                     windowToken, x, y);
             //Log.v(TAG, "...app returning after sending display offset!");
         } catch (RemoteException e) {
-            // Ignore.
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1274,7 +1272,7 @@ public class WallpaperManager {
         try {
             sGlobals.mService.clearWallpaper(mContext.getOpPackageName(), which, userId);
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1296,9 +1294,8 @@ public class WallpaperManager {
             sGlobals.mService.setWallpaperComponentChecked(name, mContext.getOpPackageName());
             return true;
         } catch (RemoteException e) {
-            // Ignore
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -1321,7 +1318,7 @@ public class WallpaperManager {
                     windowToken, xOffset, yOffset, mWallpaperXStep, mWallpaperYStep);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
-            // Ignore.
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1359,7 +1356,7 @@ public class WallpaperManager {
                     windowToken, action, x, y, z, extras, false);
             //Log.v(TAG, "...app returning after sending offsets!");
         } catch (RemoteException e) {
-            // Ignore.
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1375,7 +1372,7 @@ public class WallpaperManager {
             try {
                 return sGlobals.mService.isWallpaperSupported(mContext.getOpPackageName());
             } catch (RemoteException e) {
-                // Ignore
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1395,7 +1392,7 @@ public class WallpaperManager {
             try {
                 return sGlobals.mService.isWallpaperSettingAllowed(mContext.getOpPackageName());
             } catch (RemoteException e) {
-                // Ignore
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1416,7 +1413,7 @@ public class WallpaperManager {
             WindowManagerGlobal.getWindowSession().setWallpaperPosition(
                     windowToken, -1, -1, -1, -1);
         } catch (RemoteException e) {
-            // Ignore.
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1436,6 +1433,25 @@ public class WallpaperManager {
     }
 
     /**
+     * Remove one or more currently set wallpapers, reverting to the system default
+     * display for each one.  If {@link #FLAG_SET_SYSTEM} is set in the {@code which}
+     * parameter, the intent {@link Intent#ACTION_WALLPAPER_CHANGED} will be broadcast
+     * upon success.
+     *
+     * @param which A bitwise combination of {@link #FLAG_SET_SYSTEM} or
+     *   {@link #FLAG_SET_LOCK}
+     * @throws IOException If an error occurs reverting to the built-in wallpaper.
+     */
+    public void clear(int which) throws IOException {
+        if ((which & FLAG_SET_SYSTEM) != 0) {
+            clear();
+        }
+        if ((which & FLAG_SET_LOCK) != 0) {
+            clearWallpaper(FLAG_SET_LOCK, mContext.getUserId());
+        }
+    }
+
+    /**
      * Open stream representing the default static image wallpaper.
      *
      * @hide
@@ -1497,9 +1513,8 @@ public class WallpaperManager {
         try {
             return sGlobals.mService.setLockWallpaperCallback(callback);
         } catch (RemoteException e) {
-            Log.e(TAG, "Unable to contact wallpaper service");
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     // Private completion callback for setWallpaper() synchronization
index 74fe13a..c4037f8 100644 (file)
@@ -100,9 +100,6 @@ public class DevicePolicyManager {
     private final IDevicePolicyManager mService;
     private final boolean mParentInstance;
 
-    private static final String REMOTE_EXCEPTION_MESSAGE =
-            "Failed to talk with device policy manager service";
-
     private DevicePolicyManager(Context context, boolean parentInstance) {
         this(context,
                 IDevicePolicyManager.Stub.asInterface(
@@ -347,6 +344,68 @@ public class DevicePolicyManager {
             = "android.app.action.PROVISION_FINALIZATION";
 
     /**
+     * Action: Bugreport sharing with device owner has been accepted by the user.
+     *
+     * @hide
+     */
+    public static final String ACTION_BUGREPORT_SHARING_ACCEPTED =
+            "com.android.server.action.BUGREPORT_SHARING_ACCEPTED";
+
+    /**
+     * Action: Bugreport sharing with device owner has been declined by the user.
+     *
+     * @hide
+     */
+    public static final String ACTION_BUGREPORT_SHARING_DECLINED =
+            "com.android.server.action.BUGREPORT_SHARING_DECLINED";
+
+    /**
+     * Action: Bugreport has been collected and is dispatched to {@link DevicePolicyManagerService}.
+     *
+     * @hide
+     */
+    public static final String ACTION_REMOTE_BUGREPORT_DISPATCH =
+            "android.intent.action.REMOTE_BUGREPORT_DISPATCH";
+
+    /**
+     * Extra for shared bugreport's SHA-256 hash.
+     *
+     * @hide
+     */
+    public static final String EXTRA_REMOTE_BUGREPORT_HASH =
+            "android.intent.extra.REMOTE_BUGREPORT_HASH";
+
+    /**
+     * Extra for remote bugreport notification shown type.
+     *
+     * @hide
+     */
+    public static final String EXTRA_BUGREPORT_NOTIFICATION_TYPE =
+            "android.app.extra.bugreport_notification_type";
+
+    /**
+     * Notification type for a started remote bugreport flow.
+     *
+     * @hide
+     */
+    public static final int NOTIFICATION_BUGREPORT_STARTED = 1;
+
+    /**
+     * Notification type for a bugreport that has already been accepted to be shared, but is still
+     * being taken.
+     *
+     * @hide
+     */
+    public static final int NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED = 2;
+
+    /**
+     * Notification type for a bugreport that has been taken and can be shared or declined.
+     *
+     * @hide
+     */
+    public static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
+
+    /**
      * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that
      * allows a mobile device management application or NFC programmer application which starts
      * managed provisioning to pass data to the management application instance after provisioning.
@@ -989,7 +1048,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isAdminActive(admin, userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1004,7 +1063,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isRemovingAdmin(admin, userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1029,7 +1088,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getActiveAdmins(userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -1054,7 +1113,7 @@ public class DevicePolicyManager {
             try {
                 return mService.packageHasActiveAdmins(packageName, userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1074,7 +1133,7 @@ public class DevicePolicyManager {
             try {
                 mService.removeActiveAdmin(admin, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1093,7 +1152,7 @@ public class DevicePolicyManager {
             try {
                 return mService.hasGrantedPolicy(admin, usesPolicy, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1109,7 +1168,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isSeparateProfileChallengeAllowed(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1227,7 +1286,7 @@ public class DevicePolicyManager {
             try {
                 mService.setPasswordQuality(admin, quality, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1254,7 +1313,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordQuality(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return PASSWORD_QUALITY_UNSPECIFIED;
@@ -1291,7 +1350,7 @@ public class DevicePolicyManager {
             try {
                 mService.setPasswordMinimumLength(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1319,7 +1378,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordMinimumLength(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1357,7 +1416,7 @@ public class DevicePolicyManager {
             try {
                 mService.setPasswordMinimumUpperCase(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1391,7 +1450,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordMinimumUpperCase(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1429,7 +1488,7 @@ public class DevicePolicyManager {
             try {
                 mService.setPasswordMinimumLowerCase(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1463,7 +1522,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordMinimumLowerCase(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1500,7 +1559,7 @@ public class DevicePolicyManager {
             try {
                 mService.setPasswordMinimumLetters(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1533,7 +1592,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordMinimumLetters(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1570,7 +1629,7 @@ public class DevicePolicyManager {
             try {
                 mService.setPasswordMinimumNumeric(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1603,7 +1662,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordMinimumNumeric(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1640,7 +1699,7 @@ public class DevicePolicyManager {
             try {
                 mService.setPasswordMinimumSymbols(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1672,7 +1731,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordMinimumSymbols(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1709,7 +1768,7 @@ public class DevicePolicyManager {
             try {
                 mService.setPasswordMinimumNonLetter(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1742,7 +1801,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordMinimumNonLetter(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1780,7 +1839,7 @@ public class DevicePolicyManager {
             try {
                 mService.setPasswordHistoryLength(admin, length, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1816,7 +1875,7 @@ public class DevicePolicyManager {
             try {
                 mService.setPasswordExpirationTimeout(admin, timeout, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1840,7 +1899,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordExpirationTimeout(admin, myUserId(), mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1864,7 +1923,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordExpiration(admin, myUserId(), mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1893,7 +1952,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPasswordHistoryLength(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -1931,7 +1990,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isActivePasswordSufficient(myUserId(), mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1951,7 +2010,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isProfileActivePasswordSufficientForParent(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -1988,7 +2047,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getCurrentFailedPasswordAttempts(userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return -1;
@@ -2005,7 +2064,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getDoNotAskCredentialsOnBoot();
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2039,7 +2098,7 @@ public class DevicePolicyManager {
             try {
                 mService.setMaximumFailedPasswordsForWipe(admin, num, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2068,7 +2127,7 @@ public class DevicePolicyManager {
                 return mService.getMaximumFailedPasswordsForWipe(
                         admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -2087,7 +2146,7 @@ public class DevicePolicyManager {
                 return mService.getProfileWithMinimumFailedPasswordsForWipe(
                         userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return UserHandle.USER_NULL;
@@ -2155,7 +2214,7 @@ public class DevicePolicyManager {
             try {
                 return mService.resetPassword(password, flags);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2183,7 +2242,7 @@ public class DevicePolicyManager {
             try {
                 mService.setMaximumTimeToLock(admin, timeMs, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2212,7 +2271,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getMaximumTimeToLock(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -2235,7 +2294,7 @@ public class DevicePolicyManager {
             try {
                 mService.lockNow(mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2272,7 +2331,7 @@ public class DevicePolicyManager {
             try {
                 mService.wipeData(flags);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2342,7 +2401,7 @@ public class DevicePolicyManager {
                 }
                 return mService.setGlobalProxy(admin, hostSpec, exclSpec);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -2370,7 +2429,7 @@ public class DevicePolicyManager {
             try {
                 mService.setRecommendedGlobalProxy(admin, proxyInfo);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2386,7 +2445,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getGlobalProxyAdmin(myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -2515,7 +2574,7 @@ public class DevicePolicyManager {
             try {
                 return mService.setStorageEncryption(admin, encrypt);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return ENCRYPTION_STATUS_UNSUPPORTED;
@@ -2535,7 +2594,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getStorageEncryption(admin, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2570,7 +2629,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getStorageEncryptionStatus(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return ENCRYPTION_STATUS_UNSUPPORTED;
@@ -2591,7 +2650,7 @@ public class DevicePolicyManager {
             try {
                 return mService.installCaCert(admin, certBuffer);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2612,7 +2671,7 @@ public class DevicePolicyManager {
             } catch (CertificateException e) {
                 Log.w(TAG, "Unable to parse certificate", e);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2640,7 +2699,7 @@ public class DevicePolicyManager {
                     }
                 }
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return certs;
@@ -2659,7 +2718,7 @@ public class DevicePolicyManager {
                 mService.uninstallCaCerts(admin, new TrustedCertificateStore().userAliases()
                         .toArray(new String[0]));
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -2677,7 +2736,7 @@ public class DevicePolicyManager {
                 mService.enforceCanManageCaCerts(admin);
                 return getCaCertAlias(certBuffer) != null;
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             } catch (CertificateException ce) {
                 Log.w(TAG, "Could not parse certificate", ce);
             }
@@ -2737,7 +2796,7 @@ public class DevicePolicyManager {
                     .getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded();
             return mService.installKeyPair(admin, pkcs8Key, pemCert, alias, requestAccess);
         } catch (RemoteException e) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            throw e.rethrowFromSystemServer();
         } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
             Log.w(TAG, "Failed to obtain private key material", e);
         } catch (CertificateException | IOException e) {
@@ -2753,15 +2812,14 @@ public class DevicePolicyManager {
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or
      *            {@code null} if calling from a delegated certificate installer.
      * @param alias The private key alias under which the certificate is installed.
-     * @return {@code true} if the keys were both removed, {@code false} otherwise.
+     * @return {@code true} if the certificate alias no longer exists, {@code false} otherwise.
      */
     public boolean removeKeyPair(@Nullable ComponentName admin, @NonNull String alias) {
         try {
             return mService.removeKeyPair(admin, alias);
         } catch (RemoteException e) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -2800,7 +2858,7 @@ public class DevicePolicyManager {
             try {
                 mService.setCertInstallerPackage(admin, installerPackage);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2818,7 +2876,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getCertInstallerPackage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -2845,7 +2903,7 @@ public class DevicePolicyManager {
             try {
                 return mService.setAlwaysOnVpnPackage(admin, vpnPackage);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2865,7 +2923,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getAlwaysOnVpnPackage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -2890,7 +2948,7 @@ public class DevicePolicyManager {
             try {
                 mService.setCameraDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2911,7 +2969,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getCameraDisabled(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2921,7 +2979,7 @@ public class DevicePolicyManager {
      * Called by a device owner to request a bugreport.
      *
      * <p>There must be only one user on the device, managed by the device owner.
-     * Otherwise a security exception will be thrown.
+     * Otherwise a {@link SecurityException} will be thrown.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @return {@code true} if the bugreport collection started successfully, or {@code false}
@@ -2933,7 +2991,7 @@ public class DevicePolicyManager {
             try {
                 return mService.requestBugreport(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -2970,7 +3028,7 @@ public class DevicePolicyManager {
             try {
                 mService.setScreenCaptureDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2991,7 +3049,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getScreenCaptureDisabled(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3014,7 +3072,7 @@ public class DevicePolicyManager {
             try {
                 mService.setAutoTimeRequired(admin, required);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3027,7 +3085,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getAutoTimeRequired();
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3052,7 +3110,7 @@ public class DevicePolicyManager {
             try {
                 mService.setForceEphemeralUsers(admin, forceEphemeralUsers);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3066,7 +3124,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getForceEphemeralUsers(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3115,7 +3173,7 @@ public class DevicePolicyManager {
             try {
                 mService.setKeyguardDisabledFeatures(admin, which, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3144,7 +3202,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getKeyguardDisabledFeatures(admin, userHandle, mParentInstance);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return KEYGUARD_DISABLE_FEATURES_NONE;
@@ -3159,7 +3217,7 @@ public class DevicePolicyManager {
             try {
                 mService.setActiveAdmin(policyReceiver, refreshing, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3179,7 +3237,7 @@ public class DevicePolicyManager {
             try {
                 mService.getRemoveWarning(admin, result, myUserId());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3194,7 +3252,7 @@ public class DevicePolicyManager {
                 mService.setActivePasswordState(quality, length, letters, uppercase, lowercase,
                         numbers, symbols, nonletter, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3207,7 +3265,7 @@ public class DevicePolicyManager {
             try {
                 mService.reportFailedPasswordAttempt(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3220,7 +3278,7 @@ public class DevicePolicyManager {
             try {
                 mService.reportSuccessfulPasswordAttempt(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3233,7 +3291,7 @@ public class DevicePolicyManager {
             try {
                 mService.reportFailedFingerprintAttempt(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3246,7 +3304,7 @@ public class DevicePolicyManager {
             try {
                 mService.reportSuccessfulFingerprintAttempt(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3260,7 +3318,7 @@ public class DevicePolicyManager {
             try {
                 mService.reportKeyguardDismissed(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3274,7 +3332,7 @@ public class DevicePolicyManager {
             try {
                 mService.reportKeyguardSecured(userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3327,7 +3385,7 @@ public class DevicePolicyManager {
             try {
                 return mService.setDeviceOwner(who, ownerName, userId);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3409,7 +3467,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getDeviceOwnerComponent(callingUserOnly);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3428,7 +3486,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getDeviceOwnerUserId();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return UserHandle.USER_NULL;
@@ -3448,7 +3506,7 @@ public class DevicePolicyManager {
             try {
                 mService.clearDeviceOwner(packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -3491,7 +3549,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getDeviceOwnerName();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3544,7 +3602,7 @@ public class DevicePolicyManager {
                 mService.setActiveAdmin(admin, false, myUserId);
                 return mService.setProfileOwner(admin, ownerName, myUserId);
             } catch (RemoteException re) {
-                throw new IllegalArgumentException("Couldn't set profile owner.", re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3564,7 +3622,7 @@ public class DevicePolicyManager {
             try {
                 mService.clearProfileOwner(admin);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -3578,7 +3636,7 @@ public class DevicePolicyManager {
             try {
                 return mService.hasUserSetupCompleted();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return true;
@@ -3609,8 +3667,7 @@ public class DevicePolicyManager {
                 }
                 return mService.setProfileOwner(admin, ownerName, userHandle);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-                throw new IllegalArgumentException("Couldn't set profile owner.", re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3638,7 +3695,7 @@ public class DevicePolicyManager {
             try {
                 return mService.setDeviceOwnerLockScreenInfo(admin, info);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3652,7 +3709,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getDeviceOwnerLockScreenInfo();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3680,7 +3737,7 @@ public class DevicePolicyManager {
             try {
                 return mService.setPackagesSuspended(admin, packageNames, suspended);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return packageNames;
@@ -3699,7 +3756,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPackageSuspended(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3718,7 +3775,7 @@ public class DevicePolicyManager {
             try {
                 mService.setProfileEnabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3739,7 +3796,7 @@ public class DevicePolicyManager {
             try {
                 mService.setProfileName(admin, profileName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3759,7 +3816,7 @@ public class DevicePolicyManager {
                 return profileOwner != null
                         && profileOwner.getPackageName().equals(packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3785,9 +3842,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getProfileOwner(userId);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-                throw new IllegalArgumentException(
-                        "Requested profile owner for invalid userId", re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3804,9 +3859,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getProfileOwnerName(Process.myUserHandle().getIdentifier());
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-                throw new IllegalArgumentException(
-                        "Requested profile owner for invalid userId", re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3825,9 +3878,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getProfileOwnerName(userId);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-                throw new IllegalArgumentException(
-                        "Requested profile owner for invalid userId", re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3856,7 +3907,7 @@ public class DevicePolicyManager {
             try {
                 mService.addPersistentPreferredActivity(admin, filter, activity);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3877,7 +3928,7 @@ public class DevicePolicyManager {
             try {
                 mService.clearPackagePersistentPreferredActivities(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3903,7 +3954,7 @@ public class DevicePolicyManager {
             try {
                 mService.setApplicationRestrictionsManagingPackage(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -3921,7 +3972,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getApplicationRestrictionsManagingPackage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -3937,7 +3988,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isCallerApplicationRestrictionsManagingPackage();
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -3982,7 +4033,7 @@ public class DevicePolicyManager {
             try {
                 mService.setApplicationRestrictions(admin, packageName, settings);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4012,7 +4063,7 @@ public class DevicePolicyManager {
             try {
                 mService.setTrustAgentConfiguration(admin, target, configuration);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4043,7 +4094,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getTrustAgentConfiguration(admin, agent, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return new ArrayList<PersistableBundle>(); // empty list
@@ -4064,7 +4115,7 @@ public class DevicePolicyManager {
             try {
                 mService.setCrossProfileCallerIdDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4083,7 +4134,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getCrossProfileCallerIdDisabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4100,7 +4151,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getCrossProfileCallerIdDisabledForUser(userHandle.getIdentifier());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4122,7 +4173,7 @@ public class DevicePolicyManager {
             try {
                 mService.setCrossProfileContactsSearchDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4141,7 +4192,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getCrossProfileContactsSearchDisabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4160,7 +4211,7 @@ public class DevicePolicyManager {
                 return mService
                         .getCrossProfileContactsSearchDisabledForUser(userHandle.getIdentifier());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4178,7 +4229,7 @@ public class DevicePolicyManager {
                 mService.startManagedQuickContact(actualLookupKey, actualContactId,
                         isContactIdIgnored, directoryId, originalIntent);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4212,7 +4263,7 @@ public class DevicePolicyManager {
             try {
                 mService.setBluetoothContactSharingDisabled(admin, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4234,7 +4285,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getBluetoothContactSharingDisabled(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return true;
@@ -4254,7 +4305,7 @@ public class DevicePolicyManager {
                 return mService.getBluetoothContactSharingDisabledForUser(userHandle
                         .getIdentifier());
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return true;
@@ -4276,7 +4327,7 @@ public class DevicePolicyManager {
             try {
                 mService.addCrossProfileIntentFilter(admin, filter, flags);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4292,7 +4343,7 @@ public class DevicePolicyManager {
             try {
                 mService.clearCrossProfileIntentFilters(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4324,7 +4375,7 @@ public class DevicePolicyManager {
             try {
                 return mService.setPermittedAccessibilityServices(admin, packageNames);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4344,7 +4395,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPermittedAccessibilityServices(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4367,7 +4418,7 @@ public class DevicePolicyManager {
                 return mService.isAccessibilityServicePermittedByAdmin(admin, packageName,
                         userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4391,7 +4442,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPermittedAccessibilityServicesForUser(userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4425,7 +4476,7 @@ public class DevicePolicyManager {
             try {
                 return mService.setPermittedInputMethods(admin, packageNames);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4446,7 +4497,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPermittedInputMethods(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4468,7 +4519,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isInputMethodPermittedByAdmin(admin, packageName, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4491,7 +4542,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getPermittedInputMethodsForCurrentUser();
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4511,7 +4562,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getKeepUninstalledPackages(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4534,7 +4585,7 @@ public class DevicePolicyManager {
             try {
                 mService.setKeepUninstalledPackages(admin, packageNames);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4639,9 +4690,8 @@ public class DevicePolicyManager {
         try {
             return mService.createAndManageUser(admin, name, profileOwner, adminExtras, flags);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -4656,8 +4706,7 @@ public class DevicePolicyManager {
         try {
             return mService.removeUser(admin, userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -4674,8 +4723,7 @@ public class DevicePolicyManager {
         try {
             return mService.switchUser(admin, userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -4701,7 +4749,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getApplicationRestrictions(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4723,7 +4771,7 @@ public class DevicePolicyManager {
             try {
                 mService.setUserRestriction(admin, key, true);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4744,7 +4792,7 @@ public class DevicePolicyManager {
             try {
                 mService.setUserRestriction(admin, key, false);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4771,7 +4819,7 @@ public class DevicePolicyManager {
             try {
                 ret = mService.getUserRestrictions(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return ret == null ? new Bundle() : ret;
@@ -4793,7 +4841,7 @@ public class DevicePolicyManager {
             try {
                 return mService.setApplicationHidden(admin, packageName, hidden);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4811,7 +4859,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isApplicationHidden(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -4829,7 +4877,7 @@ public class DevicePolicyManager {
             try {
                 mService.enableSystemApp(admin, packageName);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4848,7 +4896,7 @@ public class DevicePolicyManager {
             try {
                 return mService.enableSystemAppWithIntent(admin, intent);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return 0;
@@ -4879,7 +4927,7 @@ public class DevicePolicyManager {
             try {
                 mService.setAccountManagementDisabled(admin, accountType, disabled);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4907,7 +4955,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getAccountTypesWithManagementDisabledAsUser(userId);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -4938,7 +4986,7 @@ public class DevicePolicyManager {
             try {
                 mService.setLockTaskPackages(admin, packages);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -4954,7 +5002,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getLockTaskPackages(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -4970,7 +5018,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isLockTaskPermitted(pkg);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return false;
@@ -5017,7 +5065,7 @@ public class DevicePolicyManager {
             try {
                 mService.setGlobalSetting(admin, setting, value);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -5045,7 +5093,7 @@ public class DevicePolicyManager {
             try {
                 mService.setSecureSetting(admin, setting, value);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -5066,7 +5114,7 @@ public class DevicePolicyManager {
             try {
                 mService.setRestrictionsProvider(admin, provider);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -5082,7 +5130,7 @@ public class DevicePolicyManager {
             try {
                 mService.setMasterVolumeMuted(admin, on);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -5098,7 +5146,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isMasterVolumeMuted(admin);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -5118,7 +5166,7 @@ public class DevicePolicyManager {
             try {
                 mService.setUninstallBlocked(admin, packageName, uninstallBlocked);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -5142,7 +5190,7 @@ public class DevicePolicyManager {
             try {
                 return mService.isUninstallBlocked(admin, packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -5170,7 +5218,7 @@ public class DevicePolicyManager {
             try {
                 return mService.addCrossProfileWidgetProvider(admin, packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -5198,7 +5246,7 @@ public class DevicePolicyManager {
             try {
                 return mService.removeCrossProfileWidgetProvider(admin, packageName);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return false;
@@ -5222,7 +5270,7 @@ public class DevicePolicyManager {
                     return providers;
                 }
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return Collections.emptyList();
@@ -5238,7 +5286,7 @@ public class DevicePolicyManager {
         try {
             mService.setUserIcon(admin, icon);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5258,7 +5306,7 @@ public class DevicePolicyManager {
             try {
                 mService.setSystemUpdatePolicy(admin, policy);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -5273,7 +5321,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getSystemUpdatePolicy();
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
         return null;
@@ -5297,8 +5345,7 @@ public class DevicePolicyManager {
         try {
             return mService.setKeyguardDisabled(admin, disabled);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5317,8 +5364,7 @@ public class DevicePolicyManager {
         try {
             return mService.setStatusBarDisabled(admin, disabled);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5337,7 +5383,7 @@ public class DevicePolicyManager {
             try {
                 mService.notifyPendingSystemUpdate(updateReceivedTime);
             } catch (RemoteException re) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+                throw re.rethrowFromSystemServer();
             }
         }
     }
@@ -5363,7 +5409,7 @@ public class DevicePolicyManager {
         try {
             mService.setPermissionPolicy(admin, policy);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5377,7 +5423,7 @@ public class DevicePolicyManager {
         try {
             return mService.getPermissionPolicy(admin);
         } catch (RemoteException re) {
-            return PERMISSION_POLICY_PROMPT;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5414,8 +5460,7 @@ public class DevicePolicyManager {
         try {
             return mService.setPermissionGrantState(admin, packageName, permission, grantState);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5441,8 +5486,7 @@ public class DevicePolicyManager {
         try {
             return mService.getPermissionGrantState(admin, packageName, permission);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return PERMISSION_GRANT_STATE_DEFAULT;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5460,8 +5504,7 @@ public class DevicePolicyManager {
         try {
             return mService.isProvisioningAllowed(action);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5477,8 +5520,7 @@ public class DevicePolicyManager {
         try {
             return mService.isManagedProfile(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5493,8 +5535,7 @@ public class DevicePolicyManager {
         try {
             return mService.isSystemOnlyUser(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5510,8 +5551,7 @@ public class DevicePolicyManager {
         try {
             return mService.getWifiMacAddress();
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5522,7 +5562,7 @@ public class DevicePolicyManager {
         try {
             mService.reboot(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5552,7 +5592,7 @@ public class DevicePolicyManager {
             try {
                 mService.setShortSupportMessage(admin, message);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -5569,7 +5609,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getShortSupportMessage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -5595,7 +5635,7 @@ public class DevicePolicyManager {
             try {
                 mService.setLongSupportMessage(admin, message);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -5612,7 +5652,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getLongSupportMessage(admin);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -5632,7 +5672,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getShortSupportMessageForUser(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -5653,7 +5693,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getLongSupportMessageForUser(admin, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return null;
@@ -5674,8 +5714,7 @@ public class DevicePolicyManager {
             }
             return new DevicePolicyManager(mContext, true);
         } catch (RemoteException e) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -5686,6 +5725,9 @@ public class DevicePolicyManager {
      * <p> Device logs contain various information intended for security auditing purposes.
      * See {@link SecurityEvent} for details.
      *
+     * <p>There must be only one user on the device, managed by the device owner.
+     * Otherwise a {@link SecurityException} will be thrown.
+     *
      * @param admin Which device owner this request is associated with.
      * @param enabled whether device logging should be enabled or not.
      * @see #retrieveDeviceLogs
@@ -5694,13 +5736,16 @@ public class DevicePolicyManager {
         try {
             mService.setDeviceLoggingEnabled(admin, enabled);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
     /**
      * Return whether device logging is enabled or not by the device owner.
      *
+     * <p>Can only be called by the device owner, otherwise a {@link SecurityException} will be
+     * thrown.
+     *
      * @param admin Which device owner this request is associated with.
      * @return {@code true} if device logging is enabled by device owner, {@code false} otherwise.
      */
@@ -5708,8 +5753,7 @@ public class DevicePolicyManager {
         try {
             return mService.getDeviceLoggingEnabled(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5720,6 +5764,9 @@ public class DevicePolicyManager {
      * <p> Access to the logs is rate limited and it will only return new logs after the device
      * owner has been notified via {@link DeviceAdminReceiver#onSecurityLogsAvailable}.
      *
+     * <p>There must be only one user on the device, managed by the device owner.
+     * Otherwise a {@link SecurityException} will be thrown.
+     *
      * @param admin Which device owner this request is associated with.
      * @return the new batch of device logs which is a list of {@link SecurityEvent},
      * or {@code null} if rate limitation is exceeded or if logging is currently disabled.
@@ -5734,8 +5781,7 @@ public class DevicePolicyManager {
                 return null;
             }
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5764,6 +5810,9 @@ public class DevicePolicyManager {
      * result, this API is provided as best-effort and the returned logs may contain corrupted data.
      * </strong>
      *
+     * <p>There must be only one user on the device, managed by the device owner.
+     * Otherwise a {@link SecurityException} will be thrown.
+     *
      * @param admin Which device owner this request is associated with.
      * @return Device logs from before the latest reboot of the system.
      */
@@ -5772,8 +5821,7 @@ public class DevicePolicyManager {
             ParceledListSlice<SecurityEvent> list = mService.retrievePreviousDeviceLogs(admin);
             return list.getList();
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return Collections.<SecurityEvent>emptyList();
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5792,7 +5840,7 @@ public class DevicePolicyManager {
         try {
             mService.setOrganizationColor(admin, color);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5811,7 +5859,7 @@ public class DevicePolicyManager {
         try {
             mService.setOrganizationColorForUser(color, userId);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5826,8 +5874,7 @@ public class DevicePolicyManager {
         try {
             return mService.getOrganizationColor(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return 0;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5842,8 +5889,7 @@ public class DevicePolicyManager {
         try {
             return mService.getOrganizationColorForUser(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return 0;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5862,7 +5908,7 @@ public class DevicePolicyManager {
         try {
             mService.setOrganizationName(admin, title);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5877,8 +5923,7 @@ public class DevicePolicyManager {
         try {
             return mService.getOrganizationName(admin);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5894,8 +5939,7 @@ public class DevicePolicyManager {
         try {
             return mService.getOrganizationNameForUser(userHandle);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
-            return null;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -5911,7 +5955,7 @@ public class DevicePolicyManager {
             try {
                 return mService.getUserProvisioningState();
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
         return STATE_USER_UNMANAGED;
@@ -5929,7 +5973,7 @@ public class DevicePolicyManager {
             try {
                 mService.setUserProvisioningState(state, userHandle);
             } catch (RemoteException e) {
-                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -5956,7 +6000,7 @@ public class DevicePolicyManager {
         try {
             mService.setAffiliationIds(admin, new ArrayList<String>(ids));
         } catch (RemoteException e) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -5971,8 +6015,7 @@ public class DevicePolicyManager {
         try {
             return mService != null && mService.isAffiliatedUser();
         } catch (RemoteException e) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -5987,8 +6030,7 @@ public class DevicePolicyManager {
         try {
             return mService.isUninstallInQueue(packageName);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
-            return false;
+            throw re.rethrowFromSystemServer();
         }
     }
 
@@ -6000,7 +6042,7 @@ public class DevicePolicyManager {
         try {
             mService.uninstallPackageWithActiveAdmins(packageName);
         } catch (RemoteException re) {
-            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
+            throw re.rethrowFromSystemServer();
         }
     }
 }
index 0a0d77d..8cdfee5 100644 (file)
@@ -69,4 +69,13 @@ public abstract class DevicePolicyManagerInternal {
      * @return true if the uid is an active admin with the given policy.
      */
     public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
+
+    /**
+     * Checks if a given package has a device or a profile owner for the given user
+     *
+     * @param packageName The package to check
+     * @param userId the userId to check for.
+     * @return true if package has a device or profile owner, false otherwise.
+     */
+    public abstract boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId);
 }
index 829685b..13823a2 100644 (file)
@@ -116,7 +116,7 @@ public class SecurityLog {
     /**
      * A class representing a security event log entry.
      */
-    public static class SecurityEvent implements Parcelable {
+    public static final class SecurityEvent implements Parcelable {
         private Event mEvent;
 
         /** @hide */
index 01f72ef..70d47ee 100644 (file)
@@ -23,6 +23,7 @@ import android.util.Log;
 
 /**
  * Out Of Band Data for Bluetooth device.
+ * @hide
  */
 public class OobData implements Parcelable {
     private byte[] securityManagerTk;
diff --git a/core/java/android/content/pm/ContainerEncryptionParams.java b/core/java/android/content/pm/ContainerEncryptionParams.java
deleted file mode 100644 (file)
index ab3aa27..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.text.TextUtils;
-import android.util.Slog;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.Arrays;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-
-/**
- * Represents encryption parameters used to read a container.
- *
- * @deprecated encrypted containers are legacy.
- * @hide
- */
-@SystemApi
-@Deprecated
-public class ContainerEncryptionParams implements Parcelable {
-    protected static final String TAG = "ContainerEncryptionParams";
-
-    /** What we print out first when toString() is called. */
-    private static final String TO_STRING_PREFIX = "ContainerEncryptionParams{";
-
-    /**
-     * Parameter type for parceling that indicates the next parameters are
-     * IvParameters.
-     */
-    private static final int ENC_PARAMS_IV_PARAMETERS = 1;
-
-    /** Parameter type for paceling that indicates there are no MAC parameters. */
-    private static final int MAC_PARAMS_NONE = 1;
-
-    /** The encryption algorithm used. */
-    private final String mEncryptionAlgorithm;
-
-    /** The parameter spec to be used for encryption. */
-    private final IvParameterSpec mEncryptionSpec;
-
-    /** Secret key to be used for decryption. */
-    private final SecretKey mEncryptionKey;
-
-    /** Algorithm name for the MAC to be used. */
-    private final String mMacAlgorithm;
-
-    /** The parameter spec to be used for the MAC tag authentication. */
-    private final AlgorithmParameterSpec mMacSpec;
-
-    /** Secret key to be used for MAC tag authentication. */
-    private final SecretKey mMacKey;
-
-    /** MAC tag authenticating the data in the container. */
-    private final byte[] mMacTag;
-
-    /** Offset into file where authenticated (e.g., MAC protected) data begins. */
-    private final long mAuthenticatedDataStart;
-
-    /** Offset into file where encrypted data begins. */
-    private final long mEncryptedDataStart;
-
-    /**
-     * Offset into file for the end of encrypted data (and, by extension,
-     * authenticated data) in file.
-     */
-    private final long mDataEnd;
-
-    public ContainerEncryptionParams(String encryptionAlgorithm,
-            AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey)
-            throws InvalidAlgorithmParameterException {
-        this(encryptionAlgorithm, encryptionSpec, encryptionKey, null, null, null, null, -1, -1,
-                -1);
-    }
-
-    /**
-     * Creates container encryption specifications for installing from encrypted
-     * containers.
-     *
-     * @param encryptionAlgorithm encryption algorithm to use; format matches
-     *            JCE
-     * @param encryptionSpec algorithm parameter specification
-     * @param encryptionKey key used for decryption
-     * @param macAlgorithm MAC algorithm to use; format matches JCE
-     * @param macSpec algorithm parameters specification, may be {@code null}
-     * @param macKey key used for authentication (i.e., for the MAC tag)
-     * @param macTag message authentication code (MAC) tag for the authenticated
-     *            data
-     * @param authenticatedDataStart offset of start of authenticated data in
-     *            stream
-     * @param encryptedDataStart offset of start of encrypted data in stream
-     * @param dataEnd offset of the end of both the authenticated and encrypted
-     *            data
-     * @throws InvalidAlgorithmParameterException
-     */
-    public ContainerEncryptionParams(String encryptionAlgorithm,
-            AlgorithmParameterSpec encryptionSpec, SecretKey encryptionKey, String macAlgorithm,
-            AlgorithmParameterSpec macSpec, SecretKey macKey, byte[] macTag,
-            long authenticatedDataStart, long encryptedDataStart, long dataEnd)
-            throws InvalidAlgorithmParameterException {
-        if (TextUtils.isEmpty(encryptionAlgorithm)) {
-            throw new NullPointerException("algorithm == null");
-        } else if (encryptionSpec == null) {
-            throw new NullPointerException("encryptionSpec == null");
-        } else if (encryptionKey == null) {
-            throw new NullPointerException("encryptionKey == null");
-        }
-
-        if (!TextUtils.isEmpty(macAlgorithm)) {
-            if (macKey == null) {
-                throw new NullPointerException("macKey == null");
-            }
-        }
-
-        if (!(encryptionSpec instanceof IvParameterSpec)) {
-            throw new InvalidAlgorithmParameterException(
-                    "Unknown parameter spec class; must be IvParameters");
-        }
-
-        mEncryptionAlgorithm = encryptionAlgorithm;
-        mEncryptionSpec = (IvParameterSpec) encryptionSpec;
-        mEncryptionKey = encryptionKey;
-
-        mMacAlgorithm = macAlgorithm;
-        mMacSpec = macSpec;
-        mMacKey = macKey;
-        mMacTag = macTag;
-
-        mAuthenticatedDataStart = authenticatedDataStart;
-        mEncryptedDataStart = encryptedDataStart;
-        mDataEnd = dataEnd;
-    }
-
-    public String getEncryptionAlgorithm() {
-        return mEncryptionAlgorithm;
-    }
-
-    public AlgorithmParameterSpec getEncryptionSpec() {
-        return mEncryptionSpec;
-    }
-
-    public SecretKey getEncryptionKey() {
-        return mEncryptionKey;
-    }
-
-    public String getMacAlgorithm() {
-        return mMacAlgorithm;
-    }
-
-    public AlgorithmParameterSpec getMacSpec() {
-        return mMacSpec;
-    }
-
-    public SecretKey getMacKey() {
-        return mMacKey;
-    }
-
-    public byte[] getMacTag() {
-        return mMacTag;
-    }
-
-    public long getAuthenticatedDataStart() {
-        return mAuthenticatedDataStart;
-    }
-
-    public long getEncryptedDataStart() {
-        return mEncryptedDataStart;
-    }
-
-    public long getDataEnd() {
-        return mDataEnd;
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (this == o) {
-            return true;
-        }
-
-        if (!(o instanceof ContainerEncryptionParams)) {
-            return false;
-        }
-
-        final ContainerEncryptionParams other = (ContainerEncryptionParams) o;
-
-        // Primitive comparison
-        if ((mAuthenticatedDataStart != other.mAuthenticatedDataStart)
-                || (mEncryptedDataStart != other.mEncryptedDataStart)
-                || (mDataEnd != other.mDataEnd)) {
-            return false;
-        }
-
-        // String comparison
-        if (!mEncryptionAlgorithm.equals(other.mEncryptionAlgorithm)
-                || !mMacAlgorithm.equals(other.mMacAlgorithm)) {
-            return false;
-        }
-
-        // Object comparison
-        if (!isSecretKeyEqual(mEncryptionKey, other.mEncryptionKey)
-                || !isSecretKeyEqual(mMacKey, other.mMacKey)) {
-            return false;
-        }
-
-        if (!Arrays.equals(mEncryptionSpec.getIV(), other.mEncryptionSpec.getIV())
-                || !Arrays.equals(mMacTag, other.mMacTag) || (mMacSpec != other.mMacSpec)) {
-            return false;
-        }
-
-        return true;
-    }
-
-    private static final boolean isSecretKeyEqual(SecretKey key1, SecretKey key2) {
-        final String keyFormat = key1.getFormat();
-        final String otherKeyFormat = key2.getFormat();
-
-        if (keyFormat == null) {
-            if (keyFormat != otherKeyFormat) {
-                return false;
-            }
-
-            if (key1.getEncoded() != key2.getEncoded()) {
-                return false;
-            }
-        } else {
-            if (!keyFormat.equals(key2.getFormat())) {
-                return false;
-            }
-
-            if (!Arrays.equals(key1.getEncoded(), key2.getEncoded())) {
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int hash = 3;
-
-        hash += 5 * mEncryptionAlgorithm.hashCode();
-        hash += 7 * Arrays.hashCode(mEncryptionSpec.getIV());
-        hash += 11 * mEncryptionKey.hashCode();
-        hash += 13 * mMacAlgorithm.hashCode();
-        hash += 17 * mMacKey.hashCode();
-        hash += 19 * Arrays.hashCode(mMacTag);
-        hash += 23 * mAuthenticatedDataStart;
-        hash += 29 * mEncryptedDataStart;
-        hash += 31 * mDataEnd;
-
-        return hash;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX);
-
-        sb.append("mEncryptionAlgorithm=\"");
-        sb.append(mEncryptionAlgorithm);
-        sb.append("\",");
-        sb.append("mEncryptionSpec=");
-        sb.append(mEncryptionSpec.toString());
-        sb.append("mEncryptionKey=");
-        sb.append(mEncryptionKey.toString());
-
-        sb.append("mMacAlgorithm=\"");
-        sb.append(mMacAlgorithm);
-        sb.append("\",");
-        sb.append("mMacSpec=");
-        sb.append(mMacSpec.toString());
-        sb.append("mMacKey=");
-        sb.append(mMacKey.toString());
-
-        sb.append(",mAuthenticatedDataStart=");
-        sb.append(mAuthenticatedDataStart);
-        sb.append(",mEncryptedDataStart=");
-        sb.append(mEncryptedDataStart);
-        sb.append(",mDataEnd=");
-        sb.append(mDataEnd);
-        sb.append('}');
-
-        return sb.toString();
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mEncryptionAlgorithm);
-        dest.writeInt(ENC_PARAMS_IV_PARAMETERS);
-        dest.writeByteArray(mEncryptionSpec.getIV());
-        dest.writeSerializable(mEncryptionKey);
-
-        dest.writeString(mMacAlgorithm);
-        dest.writeInt(MAC_PARAMS_NONE);
-        dest.writeByteArray(new byte[0]);
-        dest.writeSerializable(mMacKey);
-
-        dest.writeByteArray(mMacTag);
-
-        dest.writeLong(mAuthenticatedDataStart);
-        dest.writeLong(mEncryptedDataStart);
-        dest.writeLong(mDataEnd);
-    }
-
-    private ContainerEncryptionParams(Parcel source) throws InvalidAlgorithmParameterException {
-        mEncryptionAlgorithm = source.readString();
-        final int encParamType = source.readInt();
-        final byte[] encParamsEncoded = source.createByteArray();
-        mEncryptionKey = (SecretKey) source.readSerializable();
-
-        mMacAlgorithm = source.readString();
-        final int macParamType = source.readInt();
-        source.createByteArray(); // byte[] macParamsEncoded
-        mMacKey = (SecretKey) source.readSerializable();
-
-        mMacTag = source.createByteArray();
-
-        mAuthenticatedDataStart = source.readLong();
-        mEncryptedDataStart = source.readLong();
-        mDataEnd = source.readLong();
-
-        switch (encParamType) {
-            case ENC_PARAMS_IV_PARAMETERS:
-                mEncryptionSpec = new IvParameterSpec(encParamsEncoded);
-                break;
-            default:
-                throw new InvalidAlgorithmParameterException("Unknown parameter type "
-                        + encParamType);
-        }
-
-        switch (macParamType) {
-            case MAC_PARAMS_NONE:
-                mMacSpec = null;
-                break;
-            default:
-                throw new InvalidAlgorithmParameterException("Unknown parameter type "
-                        + macParamType);
-        }
-
-        if (mEncryptionKey == null) {
-            throw new NullPointerException("encryptionKey == null");
-        }
-    }
-
-    public static final Parcelable.Creator<ContainerEncryptionParams> CREATOR =
-            new Parcelable.Creator<ContainerEncryptionParams>() {
-        public ContainerEncryptionParams createFromParcel(Parcel source) {
-            try {
-                return new ContainerEncryptionParams(source);
-            } catch (InvalidAlgorithmParameterException e) {
-                Slog.e(TAG, "Invalid algorithm parameters specified", e);
-                return null;
-            }
-        }
-
-        public ContainerEncryptionParams[] newArray(int size) {
-            return new ContainerEncryptionParams[size];
-        }
-    };
-}
\ No newline at end of file
index d6b674c..0389085 100644 (file)
@@ -46,7 +46,6 @@ import android.content.pm.PermissionInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
-import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -214,19 +213,11 @@ interface IPackageManager {
     List<InstrumentationInfo> queryInstrumentation(
             String targetPackage, int flags);
 
-    void installPackage(in String originPath,
-            in IPackageInstallObserver2 observer,
-            int flags,
-            in String installerPackageName,
-            in VerificationParams verificationParams,
-            in String packageAbiOverride);
-
+    /** @deprecated Use PackageInstaller instead */
     void installPackageAsUser(in String originPath,
             in IPackageInstallObserver2 observer,
             int flags,
             in String installerPackageName,
-            in VerificationParams verificationParams,
-            in String packageAbiOverride,
             int userId);
 
     void finishPackageInstall(int token);
@@ -539,4 +530,7 @@ interface IPackageManager {
     String getServicesSystemSharedLibraryPackageName();
 
     boolean isPackageDeviceAdminOnAnyUser(String packageName);
+
+    List<String> getPreviousCodePaths(in String packageName);
+
 }
index 2cbb782..700a40d 100644 (file)
@@ -1042,6 +1042,11 @@ public class PackageInstaller {
         }
 
         /** {@hide} */
+        public void setInstallFlagsDontKillApp() {
+            installFlags |= PackageManager.INSTALL_DONT_KILL_APP;
+        }
+
+        /** {@hide} */
         public void dump(IndentingPrintWriter pw) {
             pw.printPair("mode", mode);
             pw.printHexPair("installFlags", installFlags);
index 4df8303..edd888b 100644 (file)
 
 package android.content.pm;
 
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
 import android.content.res.XmlResourceParser;
 
 import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.UserHandle;
+import android.text.BidiFormatter;
+import android.text.TextPaint;
 import android.text.TextUtils;
 import android.util.Printer;
 
@@ -38,6 +42,8 @@ import java.util.Comparator;
  * in the implementation of Parcelable in subclasses.
  */
 public class PackageItemInfo {
+    private static final float MAX_LABEL_SIZE_PX = 500f;
+
     /**
      * Public name of this item. From the "android:name" attribute.
      */
@@ -140,6 +146,56 @@ public class PackageItemInfo {
     }
 
     /**
+     * Same as {@link #loadLabel(PackageManager)} with the addition that
+     * the returned label is safe for being presented in the UI since it
+     * will not contain new lines and the length will be limited to a
+     * reasonable amount. This prevents a malicious party to influence UI
+     * layout via the app label misleading the user into performing a
+     * detrimental for them action. If the label is too long it will be
+     * truncated and ellipsized at the end.
+     *
+     * @param pm A PackageManager from which the label can be loaded; usually
+     * the PackageManager from which you originally retrieved this item
+     * @return Returns a CharSequence containing the item's label. If the
+     * item does not have a label, its name is returned.
+     *
+     * @hide
+     */
+    @SystemApi
+    public @NonNull CharSequence loadSafeLabel(@NonNull PackageManager pm) {
+        // loadLabel() always returns non-null
+        CharSequence label = loadLabel(pm);
+
+        // If the label contains new line characters it may push the UI
+        // down to hide a part of it. Labels shouldn't have new line
+        // characters, so just truncate at the first time one is seen.
+        String labelStr = label.toString();
+        final int labelLength = labelStr.length();
+        int offset = 0;
+        while (offset < labelLength) {
+            final int codePoint = labelStr.codePointAt(offset);
+            final int type = Character.getType(codePoint);
+            if (type == Character.LINE_SEPARATOR
+                    || type == Character.CONTROL
+                    || type == Character.PARAGRAPH_SEPARATOR) {
+                labelStr = labelStr.substring(0, offset);
+                break;
+            }
+            offset += Character.charCount(codePoint);
+        }
+
+        if (labelStr.isEmpty()) {
+            return labelStr;
+        }
+
+        TextPaint paint = new TextPaint();
+        paint.setTextSize(42);
+
+        return TextUtils.ellipsize(labelStr, paint, MAX_LABEL_SIZE_PX,
+                TextUtils.TruncateAt.END);
+    }
+
+    /**
      * Retrieve the current graphical icon associated with this item.  This
      * will call back on the given PackageManager to load the icon from
      * the application.
index 4dd8155..0dc856c 100644 (file)
@@ -538,6 +538,7 @@ public abstract class PackageManager {
             INSTALL_FORCE_VOLUME_UUID,
             INSTALL_FORCE_PERMISSION_PROMPT,
             INSTALL_EPHEMERAL,
+            INSTALL_DONT_KILL_APP,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface InstallFlags {}
@@ -640,6 +641,15 @@ public abstract class PackageManager {
     public static final int INSTALL_EPHEMERAL = 0x00000800;
 
     /**
+     * Flag parameter for {@link #installPackage} to indicate that this package contains
+     * a feature split to an existing application and the existing application should not
+     * be killed during the installation process.
+     *
+     * @hide
+     */
+    public static final int INSTALL_DONT_KILL_APP = 0x00001000;
+
+    /**
      * Flag parameter for
      * {@link #setComponentEnabledSetting(android.content.ComponentName, int, int)} to indicate
      * that you don't want to kill the app containing the component.  Be careful when you set this
@@ -1088,6 +1098,7 @@ public abstract class PackageManager {
             DELETE_KEEP_DATA,
             DELETE_ALL_USERS,
             DELETE_SYSTEM_APP,
+            DELETE_DONT_KILL_APP,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface DeleteFlags {}
@@ -1120,6 +1131,15 @@ public abstract class PackageManager {
     public static final int DELETE_SYSTEM_APP = 0x00000004;
 
     /**
+     * Flag parameter for {@link #deletePackage} to indicate that, if you are calling
+     * uninstall on a package that is replaced to provide new feature splits, the
+     * existing application should not be killed during the removal process.
+     *
+     * @hide
+     */
+    public static final int DELETE_DONT_KILL_APP = 0x00000008;
+
+    /**
      * Return code for when package deletion succeeds. This is passed to the
      * {@link IPackageDeleteObserver} if the system succeeded in deleting the
      * package.
@@ -1292,6 +1312,7 @@ public abstract class PackageManager {
      *
      * @hide
      */
+    @SystemApi
     public static final int INTENT_FILTER_VERIFICATION_SUCCESS = 1;
 
     /**
@@ -1301,6 +1322,7 @@ public abstract class PackageManager {
      *
      * @hide
      */
+    @SystemApi
     public static final int INTENT_FILTER_VERIFICATION_FAILURE = -1;
 
     /**
@@ -4339,6 +4361,32 @@ public abstract class PackageManager {
             throws NameNotFoundException;
 
     /**
+     * Returns a managed-user-style badged copy of the given drawable allowing the user to
+     * distinguish it from the original drawable.
+     * The caller can specify the location in the bounds of the drawable to be
+     * badged where the badge should be applied as well as the density of the
+     * badge to be used.
+     * <p>
+     * If the original drawable is a BitmapDrawable and the backing bitmap is
+     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
+     * is performed in place and the original drawable is returned.
+     * </p>
+     *
+     * @param drawable The drawable to badge.
+     * @param badgeLocation Where in the bounds of the badged drawable to place
+     *         the badge. If it's {@code null}, the badge is applied on top of the entire
+     *         drawable being badged.
+     * @param badgeDensity The optional desired density for the badge as per
+     *         {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
+     *         the density of the display is used.
+     * @return A drawable that combines the original drawable and a badge as
+     *         determined by the system.
+     * @hide
+     */
+    public abstract Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+        int badgeDensity);
+
+    /**
      * If the target user is a managed profile of the calling user or if the
      * target user is the caller and is itself a managed profile, then this
      * returns a badged copy of the given icon to be able to distinguish it from
@@ -4367,17 +4415,17 @@ public abstract class PackageManager {
      * badge to be used.
      * <p>
      * If the original drawable is a BitmapDrawable and the backing bitmap is
-     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
      * is performed in place and the original drawable is returned.
      * </p>
      *
      * @param drawable The drawable to badge.
      * @param user The target user.
      * @param badgeLocation Where in the bounds of the badged drawable to place
-     *         the badge. If not provided, the badge is applied on top of the entire
+     *         the badge. If it's {@code null}, the badge is applied on top of the entire
      *         drawable being badged.
      * @param badgeDensity The optional desired density for the badge as per
-     *         {@link android.util.DisplayMetrics#densityDpi}. If not provided,
+     *         {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
      *         the density of the display is used.
      * @return A drawable that combines the original drawable and a badge as
      *         determined by the system.
@@ -4598,60 +4646,20 @@ public abstract class PackageManager {
      */
     @Deprecated
     public abstract void installPackage(
-            Uri packageURI, IPackageInstallObserver observer, @InstallFlags int flags,
+            Uri packageURI,
+            IPackageInstallObserver observer,
+            @InstallFlags int flags,
             String installerPackageName);
-
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackageWithVerification(Uri packageURI,
-            IPackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
-            Uri verificationURI, ContainerEncryptionParams encryptionParams);
-
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams);
-
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackage(Uri packageURI, PackageInstallObserver observer,
-            @InstallFlags int flags, String installerPackageName);
-
     /**
      * @deprecated replaced by {@link PackageInstaller}
      * @hide
      */
     @Deprecated
-    public abstract void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,
-            @InstallFlags int flags, String installerPackageName, @UserIdInt int userId);
-
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackageWithVerification(Uri packageURI,
-            PackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
-            Uri verificationURI, ContainerEncryptionParams encryptionParams);
-
-    /**
-     * @deprecated replaced by {@link PackageInstaller}
-     * @hide
-     */
-    @Deprecated
-    public abstract void installPackageWithVerificationAndEncryption(Uri packageURI,
-            PackageInstallObserver observer, @InstallFlags int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams);
+    public abstract void installPackage(
+            Uri packageURI,
+            PackageInstallObserver observer,
+            @InstallFlags int flags,
+            String installerPackageName);
 
     /**
      * If there is already an application with the given package name installed
@@ -4725,8 +4733,8 @@ public abstract class PackageManager {
 
     /**
      * Allows a package listening to the
-     * {@link Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION intent filter verification
-     * broadcast} to respond to the package manager. The response must include
+     * {@link Intent#ACTION_INTENT_FILTER_NEEDS_VERIFICATION} intent filter verification
+     * broadcast to respond to the package manager. The response must include
      * the {@code verificationCode} which is one of
      * {@link PackageManager#INTENT_FILTER_VERIFICATION_SUCCESS} or
      * {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}.
@@ -4735,7 +4743,7 @@ public abstract class PackageManager {
      *            {@link PackageManager#EXTRA_VERIFICATION_ID} Intent extra.
      * @param verificationCode either {@link PackageManager#INTENT_FILTER_VERIFICATION_SUCCESS}
      *            or {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}.
-     * @param outFailedDomains a list of failed domains if the verificationCode is
+     * @param failedDomains a list of failed domains if the verificationCode is
      *            {@link PackageManager#INTENT_FILTER_VERIFICATION_FAILURE}, otherwise null;
      * @throws SecurityException if the caller does not have the
      *            INTENT_FILTER_VERIFICATION_AGENT permission.
@@ -4744,7 +4752,7 @@ public abstract class PackageManager {
      */
     @SystemApi
     public abstract void verifyIntentFilter(int verificationId, int verificationCode,
-            List<String> outFailedDomains);
+            List<String> failedDomains);
 
     /**
      * Get the status of a Domain Verification Result for an IntentFilter. This is
index 7fe7f84..89f2fc4 100644 (file)
@@ -16,6 +16,8 @@
 
 package android.content.pm;
 
+import android.content.pm.PackageManager.NameNotFoundException;
+
 import java.util.List;
 
 /**
@@ -125,4 +127,17 @@ public abstract class PackageManagerInternal {
      * @return True a permissions review is required.
      */
     public abstract boolean isPermissionsReviewRequired(String packageName, int userId);
+
+    /**
+     * Gets all of the information we know about a particular package.
+     *
+     * @param packageName The package name to find.
+     * @param userId The user under which to check.
+     *
+     * @return An {@link ApplicationInfo} containing information about the
+     *         package.
+     * @throws NameNotFoundException if a package with the given name cannot be
+     *             found on the system.
+     */
+    public abstract ApplicationInfo getApplicationInfo(String packageName, int userId);
 }
index ce6ddfd..bc28ff1 100644 (file)
@@ -121,6 +121,10 @@ public class PackageParser {
 
     private static final int MAX_PACKAGES_PER_APK = 5;
 
+    public static final int APK_SIGNING_UNKNOWN = 0;
+    public static final int APK_SIGNING_V1 = 1;
+    public static final int APK_SIGNING_V2 = 2;
+
     // TODO: switch outError users to PackageParserException
     // TODO: refactor "codePath" to "apkPath"
 
@@ -1058,12 +1062,24 @@ public class PackageParser {
         return pkg;
     }
 
+    public static int getApkSigningVersion(Package pkg) {
+        try {
+            if (ApkSignatureSchemeV2Verifier.hasSignature(pkg.baseCodePath)) {
+                return APK_SIGNING_V2;
+            }
+            return APK_SIGNING_V1;
+        } catch (IOException e) {
+        }
+        return APK_SIGNING_UNKNOWN;
+    }
+
     /**
      * Collect certificates from all the APKs described in the given package,
      * populating {@link Package#mSignatures}. Also asserts that all APK
      * contents are signed correctly and consistently.
      */
-    public static void collectCertificates(Package pkg, int parseFlags) throws PackageParserException {
+    public static void collectCertificates(Package pkg, int parseFlags)
+            throws PackageParserException {
         collectCertificatesInternal(pkg, parseFlags);
         final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
         for (int i = 0; i < childCount; i++) {
@@ -1074,7 +1090,8 @@ public class PackageParser {
         }
     }
 
-    private static void collectCertificatesInternal(Package pkg, int parseFlags) throws PackageParserException {
+    private static void collectCertificatesInternal(Package pkg, int parseFlags)
+            throws PackageParserException {
         pkg.mCertificates = null;
         pkg.mSignatures = null;
         pkg.mSigningKeys = null;
@@ -4690,9 +4707,6 @@ public class PackageParser {
         // preferred up order.
         public int mPreferredOrder = 0;
 
-        // For use by package manager to keep track of where it needs to do dexopt.
-        public final ArraySet<String> mDexOptPerformed = new ArraySet<>(4);
-
         // For use by package manager to keep track of when a package was last used.
         public long mLastPackageUsageTimeInMills;
 
diff --git a/core/java/android/content/pm/VerificationParams.aidl b/core/java/android/content/pm/VerificationParams.aidl
deleted file mode 100644 (file)
index 5bb7f69..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-parcelable VerificationParams;
index fecda87..40d2a82 100644 (file)
@@ -23,29 +23,19 @@ package android.content.res;
  * @hide For internal use only.
  */
 public class ConfigurationBoundResourceCache<T> extends ThemedResourceCache<ConstantState<T>> {
-    private final Resources mResources;
-
-    /**
-     * Creates a cache for the given Resources instance.
-     *
-     * @param resources the resources to use when creating new instances
-     */
-    public ConfigurationBoundResourceCache(Resources resources) {
-        mResources = resources;
-    }
-
     /**
      * If the resource is cached, creates and returns a new instance of it.
      *
      * @param key a key that uniquely identifies the drawable resource
+     * @param resources a Resources object from which to create new instances.
      * @param theme the theme where the resource will be used
      * @return a new instance of the resource, or {@code null} if not in
      *         the cache
      */
-    public T getInstance(long key, Resources.Theme theme) {
+    public T getInstance(long key, Resources resources, Resources.Theme theme) {
         final ConstantState<T> entry = get(key, theme);
         if (entry != null) {
-            return entry.newInstance(mResources, theme);
+            return entry.newInstance(resources, theme);
         }
 
         return null;
index ba00134..7b27fac 100644 (file)
@@ -22,29 +22,19 @@ import android.graphics.drawable.Drawable;
  * Class which can be used to cache Drawable resources against a theme.
  */
 class DrawableCache extends ThemedResourceCache<Drawable.ConstantState> {
-    private final Resources mResources;
-
-    /**
-     * Creates a cache for the given Resources instance.
-     *
-     * @param resources the resources to use when creating new instances
-     */
-    public DrawableCache(Resources resources) {
-        mResources = resources;
-    }
-
     /**
      * If the resource is cached, creates and returns a new instance of it.
      *
      * @param key a key that uniquely identifies the drawable resource
+     * @param resources a Resources object from which to create new instances.
      * @param theme the theme where the resource will be used
      * @return a new instance of the resource, or {@code null} if not in
      *         the cache
      */
-    public Drawable getInstance(long key, Resources.Theme theme) {
+    public Drawable getInstance(long key, Resources resources, Resources.Theme theme) {
         final Drawable.ConstantState entry = get(key, theme);
         if (entry != null) {
-            return entry.newDrawable(mResources, theme);
+            return entry.newDrawable(resources, theme);
         }
 
         return null;
index a54f40f..f337fe6 100644 (file)
@@ -40,23 +40,17 @@ import android.annotation.StyleableRes;
 import android.annotation.XmlRes;
 import android.content.pm.ActivityInfo;
 import android.graphics.Movie;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
 import android.graphics.drawable.DrawableInflater;
-import android.icu.text.PluralRules;
 import android.os.Build;
 import android.os.Bundle;
-import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
-import android.util.LocaleList;
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.Pools.SynchronizedPool;
-import android.util.Slog;
 import android.util.TypedValue;
-import android.util.Xml;
 import android.view.ViewDebug;
 import android.view.ViewHierarchyEncoder;
 
@@ -68,8 +62,6 @@ import org.xmlpull.v1.XmlPullParserException;
 
 import java.io.IOException;
 import java.io.InputStream;
-import java.util.Arrays;
-import java.util.Locale;
 
 /**
  * Class for accessing an application's resources.  This sits on top of the
@@ -99,51 +91,15 @@ import java.util.Locale;
 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 boolean TRACE_FOR_MISS_PRELOAD = false;
-
-    private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative(
-            ActivityInfo.CONFIG_LAYOUT_DIRECTION);
-
-    private static final int ID_OTHER = 0x01000004;
-
     private static final Object sSync = new Object();
 
-    // Information about preloaded resources.  Note that they are not
-    // protected by a lock, because while preloading in zygote we are all
-    // single-threaded, and after that these are immutable.
-    private static final LongSparseArray<ConstantState>[] sPreloadedDrawables;
-    private static final LongSparseArray<ConstantState> sPreloadedColorDrawables
-            = new LongSparseArray<>();
-    private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
-            sPreloadedComplexColors = new LongSparseArray<>();
-
-    /** Size of the cyclical cache used to map XML files to blocks. */
-    private static final int XML_BLOCK_CACHE_SIZE = 4;
-
-    // Pool of TypedArrays targeted to this Resources object.
-    final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
-
     // Used by BridgeResources in layoutlib
     static Resources mSystem = null;
 
-    private static boolean sPreloaded;
-
-    /** Lock object used to protect access to caches and configuration. */
-    private final Object mAccessLock = new Object();
+    private ResourcesImpl mResourcesImpl;
 
-    // These are protected by mAccessLock.
-    private final Configuration mTmpConfig = new Configuration();
-    private final DrawableCache mDrawableCache = new DrawableCache(this);
-    private final DrawableCache mColorDrawableCache = new DrawableCache(this);
-    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
-            new ConfigurationBoundResourceCache<>(this);
-    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
-            new ConfigurationBoundResourceCache<>(this);
-    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
-            new ConfigurationBoundResourceCache<>(this);
+    // Pool of TypedArrays targeted to this Resources object.
+    final SynchronizedPool<TypedArray> mTypedArrayPool = new SynchronizedPool<>(5);
 
     /** Used to inflate drawable objects from XML. */
     private DrawableInflater mDrawableInflater;
@@ -154,29 +110,7 @@ public class Resources {
     /** Single-item pool used to minimize TypedValue allocations. */
     private TypedValue mTmpValue = new TypedValue();
 
-    private boolean mPreloading;
-
-    // Cyclical cache used for recently-accessed XML files.
-    private int mLastCachedXmlBlockIndex = -1;
-    private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
-    private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
-    private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
-
-    final AssetManager mAssets;
     final ClassLoader mClassLoader;
-    final DisplayMetrics mMetrics = new DisplayMetrics();
-
-    private final Configuration mConfiguration = new Configuration();
-
-    private PluralRules mPluralRule;
-
-    private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
-
-    static {
-        sPreloadedDrawables = new LongSparseArray[2];
-        sPreloadedDrawables[0] = new LongSparseArray<>();
-        sPreloadedDrawables[1] = new LongSparseArray<>();
-    }
 
     /**
      * Returns the most appropriate default theme for the specified target SDK version.
@@ -219,32 +153,20 @@ public class Resources {
     }
 
     /**
-     * @return the inflater used to create drawable objects
-     * @hide Pending API finalization.
+     * Return a global shared Resources object that provides access to only
+     * system resources (no application resources), and is not configured for
+     * the current screen (can not use dimension units, does not change based
+     * on orientation, etc).
      */
-    public final DrawableInflater getDrawableInflater() {
-        if (mDrawableInflater == null) {
-            mDrawableInflater = new DrawableInflater(this, mClassLoader);
+    public static Resources getSystem() {
+        synchronized (sSync) {
+            Resources ret = mSystem;
+            if (ret == null) {
+                ret = new Resources();
+                mSystem = ret;
+            }
+            return ret;
         }
-        return mDrawableInflater;
-    }
-
-    /**
-     * Used by AnimatorInflater.
-     *
-     * @hide
-     */
-    public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
-        return mAnimatorCache;
-    }
-
-    /**
-     * Used by AnimatorInflater.
-     *
-     * @hide
-     */
-    public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
-        return mStateListAnimatorCache;
     }
 
     /**
@@ -275,51 +197,73 @@ public class Resources {
      *               selecting/computing resource values (optional).
      */
     public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config) {
-        this(assets, metrics, config, CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO, null);
+        this(null);
+        mResourcesImpl = new ResourcesImpl(assets, metrics, config,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
     }
 
     /**
      * Creates a new Resources object with CompatibilityInfo.
      *
-     * @param assets Previously created AssetManager.
-     * @param metrics Current display metrics to consider when
-     *                selecting/computing resource values.
-     * @param config Desired device configuration to consider when
-     *               selecting/computing resource values (optional).
-     * @param compatInfo this resource's compatibility info. Must not be null.
      * @param classLoader class loader for the package used to load custom
      *                    resource classes, may be {@code null} to use system
      *                    class loader
      * @hide
      */
-    public Resources(AssetManager assets, DisplayMetrics metrics, Configuration config,
-            CompatibilityInfo compatInfo, @Nullable ClassLoader classLoader) {
-        mAssets = assets;
+    public Resources(@Nullable ClassLoader classLoader) {
         mClassLoader = classLoader == null ? ClassLoader.getSystemClassLoader() : classLoader;
-        mMetrics.setToDefaults();
-        if (compatInfo != null) {
-            mCompatibilityInfo = compatInfo;
-        }
-        updateConfiguration(config, metrics);
-        assets.ensureStringBlocks();
     }
 
     /**
-     * Return a global shared Resources object that provides access to only
-     * system resources (no application resources), and is not configured for
-     * the current screen (can not use dimension units, does not change based
-     * on orientation, etc).
+     * Only for creating the System resources.
      */
-    public static Resources getSystem() {
-        synchronized (sSync) {
-            Resources ret = mSystem;
-            if (ret == null) {
-                ret = new Resources();
-                mSystem = ret;
-            }
+    private Resources() {
+        this(null);
 
-            return ret;
+        final DisplayMetrics metrics = new DisplayMetrics();
+        metrics.setToDefaults();
+
+        final Configuration config = new Configuration();
+        config.setToDefaults();
+
+        mResourcesImpl = new ResourcesImpl(AssetManager.getSystem(), metrics, config,
+                CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO);
+    }
+
+    /**
+     * @hide
+     */
+    public void setImpl(ResourcesImpl impl) {
+        mResourcesImpl = impl;
+    }
+
+    /**
+     * @return the inflater used to create drawable objects
+     * @hide Pending API finalization.
+     */
+    public final DrawableInflater getDrawableInflater() {
+        if (mDrawableInflater == null) {
+            mDrawableInflater = new DrawableInflater(this, mClassLoader);
         }
+        return mDrawableInflater;
+    }
+
+    /**
+     * Used by AnimatorInflater.
+     *
+     * @hide
+     */
+    public ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
+        return mResourcesImpl.getAnimatorCache();
+    }
+
+    /**
+     * Used by AnimatorInflater.
+     *
+     * @hide
+     */
+    public ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
+        return mResourcesImpl.getStateListAnimatorCache();
     }
 
     /**
@@ -337,8 +281,8 @@ public class Resources {
      * @return CharSequence The string data associated with the resource, plus
      *         possibly styled text information.
      */
-    public CharSequence getText(@StringRes int id) throws NotFoundException {
-        CharSequence res = mAssets.getResourceText(id);
+    @NonNull public CharSequence getText(@StringRes int id) throws NotFoundException {
+        CharSequence res = mResourcesImpl.getAssets().getResourceText(id);
         if (res != null) {
             return res;
         }
@@ -366,41 +310,10 @@ public class Resources {
      * @return CharSequence The string data associated with the resource, plus
      *         possibly styled text information.
      */
+    @NonNull
     public CharSequence getQuantityText(@PluralsRes int id, int quantity)
             throws NotFoundException {
-        PluralRules rule = getPluralRule();
-        CharSequence res = mAssets.getResourceBagText(id,
-                attrForQuantityCode(rule.select(quantity)));
-        if (res != null) {
-            return res;
-        }
-        res = mAssets.getResourceBagText(id, ID_OTHER);
-        if (res != null) {
-            return res;
-        }
-        throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
-                + " quantity=" + quantity
-                + " item=" + rule.select(quantity));
-    }
-
-    private PluralRules getPluralRule() {
-        synchronized (sSync) {
-            if (mPluralRule == null) {
-                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
-            }
-            return mPluralRule;
-        }
-    }
-
-    private static int attrForQuantityCode(String quantityCode) {
-        switch (quantityCode) {
-            case PluralRules.KEYWORD_ZERO: return 0x01000005;
-            case PluralRules.KEYWORD_ONE:  return 0x01000006;
-            case PluralRules.KEYWORD_TWO:  return 0x01000007;
-            case PluralRules.KEYWORD_FEW:  return 0x01000008;
-            case PluralRules.KEYWORD_MANY: return 0x01000009;
-            default:                     return ID_OTHER;
-        }
+        return mResourcesImpl.getQuantityText(id, quantity);
     }
 
     /**
@@ -419,12 +332,7 @@ public class Resources {
      */
     @NonNull
     public String getString(@StringRes int id) throws NotFoundException {
-        final CharSequence res = getText(id);
-        if (res != null) {
-            return res.toString();
-        }
-        throw new NotFoundException("String resource ID #0x"
-                                    + Integer.toHexString(id));
+        return getText(id).toString();
     }
 
 
@@ -449,7 +357,8 @@ public class Resources {
     @NonNull
     public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
         final String raw = getString(id);
-        return String.format(mConfiguration.getLocales().get(0), raw, formatArgs);
+        return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw,
+                formatArgs);
     }
 
     /**
@@ -477,10 +386,12 @@ public class Resources {
      * @return String The string data associated with the resource,
      * stripped of styled text information.
      */
+    @NonNull
     public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
             throws NotFoundException {
         String raw = getQuantityText(id, quantity).toString();
-        return String.format(mConfiguration.getLocales().get(0), raw, formatArgs);
+        return String.format(mResourcesImpl.getConfiguration().getLocales().get(0), raw,
+                formatArgs);
     }
 
     /**
@@ -503,8 +414,8 @@ public class Resources {
      * @return String The string data associated with the resource,
      * stripped of styled text information.
      */
-    public String getQuantityString(@PluralsRes int id, int quantity)
-            throws NotFoundException {
+    @NonNull
+    public String getQuantityString(@PluralsRes int id, int quantity) throws NotFoundException {
         return getQuantityText(id, quantity).toString();
     }
 
@@ -523,7 +434,7 @@ public class Resources {
      *         possibly styled text information, or def if id is 0 or not found.
      */
     public CharSequence getText(@StringRes int id, CharSequence def) {
-        CharSequence res = id != 0 ? mAssets.getResourceText(id) : null;
+        CharSequence res = id != 0 ? mResourcesImpl.getAssets().getResourceText(id) : null;
         return res != null ? res : def;
     }
 
@@ -538,13 +449,13 @@ public class Resources {
      *
      * @return The styled text array associated with the resource.
      */
+    @NonNull
     public CharSequence[] getTextArray(@ArrayRes int id) throws NotFoundException {
-        CharSequence[] res = mAssets.getResourceTextArray(id);
+        CharSequence[] res = mResourcesImpl.getAssets().getResourceTextArray(id);
         if (res != null) {
             return res;
         }
-        throw new NotFoundException("Text array resource ID #0x"
-                                    + Integer.toHexString(id));
+        throw new NotFoundException("Text array resource ID #0x" + Integer.toHexString(id));
     }
 
     /**
@@ -558,14 +469,14 @@ public class Resources {
      *
      * @return The string array associated with the resource.
      */
+    @NonNull
     public String[] getStringArray(@ArrayRes int id)
             throws NotFoundException {
-        String[] res = mAssets.getResourceStringArray(id);
+        String[] res = mResourcesImpl.getAssets().getResourceStringArray(id);
         if (res != null) {
             return res;
         }
-        throw new NotFoundException("String array resource ID #0x"
-                                    + Integer.toHexString(id));
+        throw new NotFoundException("String array resource ID #0x" + Integer.toHexString(id));
     }
 
     /**
@@ -579,13 +490,13 @@ public class Resources {
      *
      * @return The int array associated with the resource.
      */
+    @NonNull
     public int[] getIntArray(@ArrayRes int id) throws NotFoundException {
-        int[] res = mAssets.getArrayIntResource(id);
+        int[] res = mResourcesImpl.getAssets().getArrayIntResource(id);
         if (res != null) {
             return res;
         }
-        throw new NotFoundException("Int array resource ID #0x"
-                                    + Integer.toHexString(id));
+        throw new NotFoundException("Int array resource ID #0x" + Integer.toHexString(id));
     }
 
     /**
@@ -601,16 +512,16 @@ public class Resources {
      * Be sure to call {@link TypedArray#recycle() TypedArray.recycle()}
      * when done with it.
      */
-    public TypedArray obtainTypedArray(@ArrayRes int id)
-            throws NotFoundException {
-        int len = mAssets.getArraySize(id);
+    @NonNull
+    public TypedArray obtainTypedArray(@ArrayRes int id) throws NotFoundException {
+        final ResourcesImpl impl = mResourcesImpl;
+        int len = impl.getAssets().getArraySize(id);
         if (len < 0) {
-            throw new NotFoundException("Array resource ID #0x"
-                                        + Integer.toHexString(id));
+            throw new NotFoundException("Array resource ID #0x" + Integer.toHexString(id));
         }
         
         TypedArray array = TypedArray.obtain(this, len);
-        array.mLength = mAssets.retrieveArray(id, array.mData);
+        array.mLength = impl.getAssets().retrieveArray(id, array.mData);
         array.mIndices[0] = 0;
         
         return array;
@@ -634,10 +545,12 @@ public class Resources {
      * @see #getDimensionPixelSize
      */
     public float getDimension(@DimenRes int id) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_DIMENSION) {
-                return TypedValue.complexToDimension(value.data, mMetrics);
+                return TypedValue.complexToDimension(value.data, impl.getDisplayMetrics());
             }
             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
@@ -666,10 +579,13 @@ public class Resources {
      * @see #getDimensionPixelSize
      */
     public int getDimensionPixelOffset(@DimenRes int id) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_DIMENSION) {
-                return TypedValue.complexToDimensionPixelOffset(value.data, mMetrics);
+                return TypedValue.complexToDimensionPixelOffset(value.data,
+                        impl.getDisplayMetrics());
             }
             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
@@ -699,10 +615,12 @@ public class Resources {
      * @see #getDimensionPixelOffset
      */
     public int getDimensionPixelSize(@DimenRes int id) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_DIMENSION) {
-                return TypedValue.complexToDimensionPixelSize(value.data, mMetrics);
+                return TypedValue.complexToDimensionPixelSize(value.data, impl.getDisplayMetrics());
             }
             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
                     + " type #0x" + Integer.toHexString(value.type) + " is not valid");
@@ -729,8 +647,9 @@ public class Resources {
      * @throws NotFoundException Throws NotFoundException if the given ID does not exist.
      */
     public float getFraction(@FractionRes int id, int base, int pbase) {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            mResourcesImpl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_FRACTION) {
                 return TypedValue.complexToFraction(value.data, base, pbase);
             }
@@ -800,9 +719,11 @@ public class Resources {
      */
     public Drawable getDrawable(@DrawableRes int id, @Nullable Theme theme)
             throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
-            return loadDrawable(value, id, theme);
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
+            return impl.loadDrawable(this, value, id, theme, true);
         } finally {
             releaseTempTypedValue(value);
         }
@@ -855,14 +776,16 @@ public class Resources {
      *             not exist.
      */
     public Drawable getDrawableForDensity(@DrawableRes int id, int density, @Nullable Theme theme) {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
-            getValueForDensity(id, density, value, true);
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValueForDensity(id, density, value, true);
 
             // If the drawable's XML lives in our current density qualifier,
             // it's okay to use a scaled version from the cache. Otherwise, we
             // need to actually load the drawable from XML.
-            final boolean useCache = value.density == mMetrics.densityDpi;
+            final DisplayMetrics metrics = impl.getDisplayMetrics();
+            final boolean useCache = value.density == metrics.densityDpi;
 
             /*
              * Pretend the requested density is actually the display density. If
@@ -873,18 +796,23 @@ public class Resources {
              */
             if (value.density > 0 && value.density != TypedValue.DENSITY_NONE) {
                 if (value.density == density) {
-                    value.density = mMetrics.densityDpi;
+                    value.density = metrics.densityDpi;
                 } else {
-                    value.density = (value.density * mMetrics.densityDpi) / density;
+                    value.density = (value.density * metrics.densityDpi) / density;
                 }
             }
-
-            return loadDrawable(value, id, theme, useCache);
+            return impl.loadDrawable(this, value, id, theme, useCache);
         } finally {
             releaseTempTypedValue(value);
         }
     }
 
+    @NonNull
+    Drawable loadDrawable(@NonNull TypedValue value, int id, @Nullable Theme theme)
+            throws NotFoundException {
+        return mResourcesImpl.loadDrawable(this, value, id, theme, true);
+    }
+
     /**
      * Return a movie object associated with the particular resource ID.
      * @param id The desired resource identifier, as generated by the aapt
@@ -894,13 +822,12 @@ public class Resources {
      * 
      */
     public Movie getMovie(@RawRes int id) throws NotFoundException {
-        InputStream is = openRawResource(id);
-        Movie movie = Movie.decodeStream(is);
+        final InputStream is = openRawResource(id);
+        final Movie movie = Movie.decodeStream(is);
         try {
             is.close();
-        }
-        catch (java.io.IOException e) {
-            // don't care, since the return value is valid
+        } catch (IOException e) {
+            // No one cares.
         }
         return movie;
     }
@@ -944,8 +871,10 @@ public class Resources {
      */
     @ColorInt
     public int getColor(@ColorRes int id, @Nullable Theme theme) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
             if (value.type >= TypedValue.TYPE_FIRST_INT
                     && value.type <= TypedValue.TYPE_LAST_INT) {
                 return value.data;
@@ -954,7 +883,7 @@ public class Resources {
                         + " type #0x" + Integer.toHexString(value.type) + " is not valid");
             }
 
-            final ColorStateList csl = loadColorStateList(value, id, theme);
+            final ColorStateList csl = impl.loadColorStateList(this, value, id, theme);
             return csl.getDefaultColor();
         } finally {
             releaseTempTypedValue(value);
@@ -1012,14 +941,27 @@ public class Resources {
     @Nullable
     public ColorStateList getColorStateList(@ColorRes int id, @Nullable Theme theme)
             throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
-            return loadColorStateList(value, id, theme);
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
+            return impl.loadColorStateList(this, value, id, theme);
         } finally {
             releaseTempTypedValue(value);
         }
     }
 
+    @Nullable
+    ColorStateList loadColorStateList(@NonNull TypedValue value, int id, @Nullable Theme theme)
+            throws NotFoundException {
+        return mResourcesImpl.loadColorStateList(this, value, id, theme);
+    }
+
+    @Nullable
+    public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, @Nullable Theme theme) {
+        return mResourcesImpl.loadComplexColor(this, value, id, theme);
+    }
+
     /**
      * Return a boolean associated with a particular resource ID.  This can be
      * used with any integral resource value, and will return true if it is
@@ -1034,8 +976,9 @@ public class Resources {
      * @return Returns the boolean value contained in the resource.
      */
     public boolean getBoolean(@BoolRes int id) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            mResourcesImpl.getValue(id, value, true);
             if (value.type >= TypedValue.TYPE_FIRST_INT
                     && value.type <= TypedValue.TYPE_LAST_INT) {
                 return value.data != 0;
@@ -1059,8 +1002,9 @@ public class Resources {
      * @return Returns the integer value contained in the resource.
      */
     public int getInteger(@IntegerRes int id) throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            mResourcesImpl.getValue(id, value, true);
             if (value.type >= TypedValue.TYPE_FIRST_INT
                     && value.type <= TypedValue.TYPE_LAST_INT) {
                 return value.data;
@@ -1086,8 +1030,9 @@ public class Resources {
      * @hide Pending API council approval.
      */
     public float getFloat(int id) {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            mResourcesImpl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_FLOAT) {
                 return value.getFloat();
             }
@@ -1195,20 +1140,6 @@ public class Resources {
     }
 
     /**
-     * Returns a TypedValue populated with data for the specified resource ID
-     * that's suitable for temporary use. The obtained TypedValue should be
-     * released using {@link #releaseTempTypedValue(TypedValue)}.
-     *
-     * @param id the resource ID for which data should be obtained
-     * @return a populated typed value suitable for temporary use
-     */
-    private TypedValue obtainTempTypedValue(@AnyRes int id) {
-        final TypedValue value = obtainTempTypedValue();
-        getValue(id, value, true);
-        return value;
-    }
-
-    /**
      * Returns a TypedValue suitable for temporary use. The obtained TypedValue
      * should be released using {@link #releaseTempTypedValue(TypedValue)}.
      *
@@ -1257,17 +1188,7 @@ public class Resources {
      */
     public InputStream openRawResource(@RawRes int id, TypedValue value)
             throws NotFoundException {
-        getValue(id, value, true);
-
-        try {
-            return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
-                    AssetManager.ACCESS_STREAMING);
-        } catch (Exception e) {
-            NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
-                    " from drawable resource ID #0x" + Integer.toHexString(id));
-            rnf.initCause(e);
-            throw rnf;
-        }
+        return mResourcesImpl.openRawResource(id, value);
     }
 
     /**
@@ -1293,12 +1214,9 @@ public class Resources {
      */
     public AssetFileDescriptor openRawResourceFd(@RawRes int id)
             throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
-            return mAssets.openNonAssetFd(value.assetCookie, value.string.toString());
-        } catch (Exception e) {
-            throw new NotFoundException("File " + value.string.toString() + " from drawable "
-                    + "resource ID #0x" + Integer.toHexString(id), e);
+            return mResourcesImpl.openRawResourceFd(id, value);
         } finally {
             releaseTempTypedValue(value);
         }
@@ -1321,12 +1239,7 @@ public class Resources {
      */
     public void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
             throws NotFoundException {
-        boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
-        if (found) {
-            return;
-        }
-        throw new NotFoundException("Resource ID #0x"
-                                    + Integer.toHexString(id));
+        mResourcesImpl.getValue(id, outValue, resolveRefs);
     }
 
     /**
@@ -1344,11 +1257,7 @@ public class Resources {
      */
     public void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
             boolean resolveRefs) throws NotFoundException {
-        boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
-        if (found) {
-            return;
-        }
-        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+        mResourcesImpl.getValueForDensity(id, density, outValue, resolveRefs);
     }
 
     /**
@@ -1373,12 +1282,7 @@ public class Resources {
      */
     public void getValue(String name, TypedValue outValue, boolean resolveRefs)
             throws NotFoundException {
-        int id = getIdentifier(name, "string", null);
-        if (id != 0) {
-            getValue(id, outValue, resolveRefs);
-            return;
-        }
-        throw new NotFoundException("String resource name " + name);
+        mResourcesImpl.getValue(name, outValue, resolveRefs);
     }
 
     /**
@@ -1397,6 +1301,15 @@ public class Resources {
      * retrieve XML attributes with style and theme information applied.
      */
     public final class Theme {
+        private ResourcesImpl.ThemeImpl mThemeImpl;
+
+        private Theme() {
+        }
+
+        void setImpl(ResourcesImpl.ThemeImpl impl) {
+            mThemeImpl = impl;
+        }
+
         /**
          * Place new attribute values into the theme.  The style resource
          * specified by <var>resid</var> will be retrieved from this Theme's
@@ -1415,12 +1328,7 @@ public class Resources {
          *              if not already defined in the theme.
          */
         public void applyStyle(int resId, boolean force) {
-            synchronized (mKey) {
-                AssetManager.applyThemeStyle(mTheme, resId, force);
-
-                mThemeResId = resId;
-                mKey.append(resId, force);
-            }
+            mThemeImpl.applyStyle(resId, force);
         }
 
         /**
@@ -1433,14 +1341,7 @@ public class Resources {
          * @param other The existing Theme to copy from.
          */
         public void setTo(Theme other) {
-            synchronized (mKey) {
-                synchronized (other.mKey) {
-                    AssetManager.copyTheme(mTheme, other.mTheme);
-
-                    mThemeResId = other.mThemeResId;
-                    mKey.setTo(other.getKey());
-                }
-            }
+            mThemeImpl.setTo(other.mThemeImpl);
         }
 
         /**
@@ -1463,13 +1364,7 @@ public class Resources {
          * @see #obtainStyledAttributes(AttributeSet, int[], int, int)
          */
         public TypedArray obtainStyledAttributes(@StyleableRes int[] attrs) {
-            synchronized (mKey) {
-                final int len = attrs.length;
-                final TypedArray array = TypedArray.obtain(Resources.this, len);
-                array.mTheme = this;
-                AssetManager.applyStyle(mTheme, 0, 0, 0, attrs, array.mData, array.mIndices);
-                return array;
-            }
+            return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, 0);
         }
 
         /**
@@ -1494,13 +1389,7 @@ public class Resources {
          */
         public TypedArray obtainStyledAttributes(@StyleRes int resId, @StyleableRes int[] attrs)
                 throws NotFoundException {
-            synchronized (mKey) {
-                final int len = attrs.length;
-                final TypedArray array = TypedArray.obtain(Resources.this, len);
-                array.mTheme = this;
-                AssetManager.applyStyle(mTheme, 0, resId, 0, attrs, array.mData, array.mIndices);
-                return array;
-            }
+            return mThemeImpl.obtainStyledAttributes(this, null, attrs, 0, resId);
         }
 
         /**
@@ -1553,23 +1442,7 @@ public class Resources {
          */
         public TypedArray obtainStyledAttributes(AttributeSet set,
                 @StyleableRes int[] attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {
-            synchronized (mKey) {
-                final int len = attrs.length;
-                final TypedArray array = TypedArray.obtain(Resources.this, len);
-
-                // XXX note that for now we only work with compiled XML files.
-                // To support generic XML files we will need to manually parse
-                // out the attributes from the XML file (applying type information
-                // contained in the resources and such).
-                final XmlBlock.Parser parser = (XmlBlock.Parser) set;
-                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
-                        parser != null ? parser.mParseState : 0,
-                        attrs, array.mData, array.mIndices);
-                array.mTheme = this;
-                array.mXml = parser;
-
-                return array;
-            }
+            return mThemeImpl.obtainStyledAttributes(this, set, attrs, defStyleAttr, defStyleRes);
         }
 
         /**
@@ -1588,20 +1461,7 @@ public class Resources {
          */
         @NonNull
         public TypedArray resolveAttributes(@NonNull int[] values, @NonNull int[] attrs) {
-            synchronized (mKey) {
-                final int len = attrs.length;
-                if (values == null || len != values.length) {
-                    throw new IllegalArgumentException(
-                            "Base attribute values must the same length as attrs");
-                }
-
-                final TypedArray array = TypedArray.obtain(Resources.this, len);
-                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
-                array.mTheme = this;
-                array.mXml = null;
-
-                return array;
-            }
+            return mThemeImpl.resolveAttributes(this, values, attrs);
         }
 
         /**
@@ -1622,9 +1482,7 @@ public class Resources {
          *         <var>outValue</var> is valid, else false.
          */
         public boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
-            synchronized (mKey) {
-                return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
-            }
+            return mThemeImpl.resolveAttribute(resid, outValue, resolveRefs);
         }
 
         /**
@@ -1634,7 +1492,7 @@ public class Resources {
          * @hide
          */
         public int[] getAllAttributes() {
-            return mAssets.getStyleAttributes(getAppliedStyleResId());
+            return mThemeImpl.getAllAttributes();
         }
 
         /**
@@ -1670,11 +1528,7 @@ public class Resources {
          * @see ActivityInfo
          */
         public int getChangingConfigurations() {
-            synchronized (mKey) {
-                final int nativeChangingConfig =
-                        AssetManager.getThemeChangingConfigurations(mTheme);
-                return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
-            }
+            return mThemeImpl.getChangingConfigurations();
         }
 
         /**
@@ -1685,43 +1539,23 @@ public class Resources {
          * @param prefix Text to prefix each line printed.
          */
         public void dump(int priority, String tag, String prefix) {
-            synchronized (mKey) {
-                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
-            }
-        }
-
-        @Override
-        protected void finalize() throws Throwable {
-            super.finalize();
-            mAssets.releaseTheme(mTheme);
-        }
-
-        /*package*/ Theme() {
-            mAssets = Resources.this.mAssets;
-            mTheme = mAssets.createTheme();
+            mThemeImpl.dump(priority, tag, prefix);
         }
 
-        /** Unique key for the series of styles applied to this theme. */
-        private final ThemeKey mKey = new ThemeKey();
-
-        @SuppressWarnings("hiding")
-        private final AssetManager mAssets;
-        private final long mTheme;
-
-        /** Resource identifier for the theme. */
-        private int mThemeResId = 0;
-
         // Needed by layoutlib.
         /*package*/ long getNativeTheme() {
-            return mTheme;
+            return mThemeImpl.getNativeTheme();
         }
 
         /*package*/ int getAppliedStyleResId() {
-            return mThemeResId;
+            return mThemeImpl.getAppliedStyleResId();
         }
 
-        /*package*/ ThemeKey getKey() {
-            return mKey;
+        /**
+         * @hide
+         */
+        public ThemeKey getKey() {
+            return mThemeImpl.getKey();
         }
 
         private String getResourceNameFromHexString(String hexString) {
@@ -1729,7 +1563,7 @@ public class Resources {
         }
 
         /**
-         * Parses {@link #mKey} and returns a String array that holds pairs of
+         * Parses {@link #getKey()} and returns a String array that holds pairs of
          * adjacent Theme data: resource name followed by whether or not it was
          * forced, as specified by {@link #applyStyle(int, boolean)}.
          *
@@ -1737,21 +1571,7 @@ public class Resources {
          */
         @ViewDebug.ExportedProperty(category = "theme", hasAdjacentMapping = true)
         public String[] getTheme() {
-            synchronized (mKey) {
-                final int N = mKey.mCount;
-                final String[] themes = new String[N * 2];
-                for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
-                    final int resId = mKey.mResId[j];
-                    final boolean forced = mKey.mForce[j];
-                    try {
-                        themes[i] = getResourceName(resId);
-                    } catch (NotFoundException e) {
-                        themes[i] = Integer.toHexString(i);
-                    }
-                    themes[i + 1] = forced ? "forced" : "not forced";
-                }
-                return themes;
-            }
+            return mThemeImpl.getTheme();
         }
 
         /** @hide */
@@ -1772,16 +1592,7 @@ public class Resources {
          * @hide
          */
         public void rebase() {
-            synchronized (mKey) {
-                AssetManager.clearTheme(mTheme);
-
-                // Reapply the same styles in the same order.
-                for (int i = 0; i < mKey.mCount; i++) {
-                    final int resId = mKey.mResId[i];
-                    final boolean force = mKey.mForce[i];
-                    AssetManager.applyThemeStyle(mTheme, resId, force);
-                }
-            }
+            mThemeImpl.rebase();
         }
     }
 
@@ -1870,7 +1681,9 @@ public class Resources {
      * @return Theme The newly created Theme container.
      */
     public final Theme newTheme() {
-        return new Theme();
+        Theme theme = new Theme();
+        theme.setImpl(mResourcesImpl.newThemeImpl());
+        return theme;
     }
 
     /**
@@ -1894,7 +1707,7 @@ public class Resources {
         // out the attributes from the XML file (applying type information
         // contained in the resources and such).
         XmlBlock.Parser parser = (XmlBlock.Parser)set;
-        mAssets.retrieveAttributes(parser.mParseState, attrs,
+        mResourcesImpl.getAssets().retrieveAttributes(parser.mParseState, attrs,
                 array.mData, array.mIndices);
 
         array.mXml = parser;
@@ -1905,151 +1718,16 @@ public class Resources {
     /**
      * Store the newly updated configuration.
      */
-    public void updateConfiguration(Configuration config,
-            DisplayMetrics metrics) {
+    public void updateConfiguration(Configuration config, DisplayMetrics metrics) {
         updateConfiguration(config, metrics, null);
     }
 
     /**
      * @hide
      */
-    public void updateConfiguration(Configuration config,
-            DisplayMetrics metrics, CompatibilityInfo compat) {
-        synchronized (mAccessLock) {
-            if (false) {
-                Slog.i(TAG, "**** Updating config of " + this + ": old config is "
-                        + mConfiguration + " old compat is " + mCompatibilityInfo);
-                Slog.i(TAG, "**** Updating config of " + this + ": new config is "
-                        + config + " new compat is " + compat);
-            }
-            if (compat != null) {
-                mCompatibilityInfo = compat;
-            }
-            if (metrics != null) {
-                mMetrics.setTo(metrics);
-            }
-            // NOTE: We should re-arrange this code to create a Display
-            // with the CompatibilityInfo that is used everywhere we deal
-            // with the display in relation to this app, rather than
-            // doing the conversion here.  This impl should be okay because
-            // we make sure to return a compatible display in the places
-            // where there are public APIs to retrieve the display...  but
-            // it would be cleaner and more maintainble to just be
-            // consistently dealing with a compatible display everywhere in
-            // the framework.
-            mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
-
-            final int configChanges = calcConfigChanges(config);
-
-            LocaleList locales = mConfiguration.getLocales();
-            if (locales.isEmpty()) {
-                locales = LocaleList.getAdjustedDefault();
-                mConfiguration.setLocales(locales);
-            }
-            if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
-                mMetrics.densityDpi = mConfiguration.densityDpi;
-                mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
-            }
-            mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
-
-            final int width, height;
-            if (mMetrics.widthPixels >= mMetrics.heightPixels) {
-                width = mMetrics.widthPixels;
-                height = mMetrics.heightPixels;
-            } else {
-                //noinspection SuspiciousNameCombination
-                width = mMetrics.heightPixels;
-                //noinspection SuspiciousNameCombination
-                height = mMetrics.widthPixels;
-            }
-
-            final int keyboardHidden;
-            if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
-                    && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
-                keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
-            } else {
-                keyboardHidden = mConfiguration.keyboardHidden;
-            }
-
-            mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
-                    adjustLanguageTag(locales.get(0).toLanguageTag()),
-                    mConfiguration.orientation,
-                    mConfiguration.touchscreen,
-                    mConfiguration.densityDpi, mConfiguration.keyboard,
-                    keyboardHidden, mConfiguration.navigation, width, height,
-                    mConfiguration.smallestScreenWidthDp,
-                    mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
-                    mConfiguration.screenLayout, mConfiguration.uiMode,
-                    Build.VERSION.RESOURCES_SDK_INT);
-
-            if (DEBUG_CONFIG) {
-                Slog.i(TAG, "**** Updating config of " + this + ": final config is "
-                        + mConfiguration + " final compat is " + mCompatibilityInfo);
-            }
-
-            mDrawableCache.onConfigurationChange(configChanges);
-            mColorDrawableCache.onConfigurationChange(configChanges);
-            mComplexColorCache.onConfigurationChange(configChanges);
-            mAnimatorCache.onConfigurationChange(configChanges);
-            mStateListAnimatorCache.onConfigurationChange(configChanges);
-
-            flushLayoutCache();
-        }
-        synchronized (sSync) {
-            if (mPluralRule != null) {
-                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
-            }
-        }
-    }
-
-    /**
-     * Called by ConfigurationBoundResourceCacheTest via reflection.
-     */
-    private int calcConfigChanges(Configuration config) {
-        int configChanges = 0xfffffff;
-        if (config != null) {
-            mTmpConfig.setTo(config);
-            int density = config.densityDpi;
-            if (density == Configuration.DENSITY_DPI_UNDEFINED) {
-                density = mMetrics.noncompatDensityDpi;
-            }
-
-            mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
-
-            if (mTmpConfig.getLocales().isEmpty()) {
-                mTmpConfig.setLocales(LocaleList.getDefault());
-            }
-            configChanges = mConfiguration.updateFrom(mTmpConfig);
-            configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
-        }
-        return configChanges;
-    }
-
-    /**
-     * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
-     * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
-     *
-     * All released versions of android prior to "L" used the deprecated language
-     * tags, so we will need to support them for backwards compatibility.
-     *
-     * Note that this conversion needs to take place *after* the call to
-     * {@code toLanguageTag} because that will convert all the deprecated codes to
-     * the new ones, even if they're set manually.
-     */
-    private static String adjustLanguageTag(String languageTag) {
-        final int separator = languageTag.indexOf('-');
-        final String language;
-        final String remainder;
-
-        if (separator == -1) {
-            language = languageTag;
-            remainder = "";
-        } else {
-            language = languageTag.substring(0, separator);
-            remainder = languageTag.substring(separator);
-        }
-
-        return Locale.adjustLanguageCode(language) + remainder;
+    public void updateConfiguration(Configuration config, DisplayMetrics metrics,
+                                    CompatibilityInfo compat) {
+        mResourcesImpl.updateConfiguration(config, metrics, compat);
     }
 
     /**
@@ -2074,9 +1752,7 @@ public class Resources {
      * @return The resource's current display metrics. 
      */
     public DisplayMetrics getDisplayMetrics() {
-        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
-                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
-        return mMetrics;
+        return mResourcesImpl.getDisplayMetrics();
     }
 
     /**
@@ -2086,13 +1762,13 @@ public class Resources {
      * @return The resource's current configuration. 
      */
     public Configuration getConfiguration() {
-        return mConfiguration;
+        return mResourcesImpl.getConfiguration();
     }
 
     /** @hide */
     public Configuration[] getSizeConfigurations() {
-        return mAssets.getSizeConfigurations();
-    };
+        return mResourcesImpl.getSizeConfigurations();
+    }
 
     /**
      * Return the compatibility mode information for the application.
@@ -2102,7 +1778,7 @@ public class Resources {
      * @hide
      */
     public CompatibilityInfo getCompatibilityInfo() {
-        return mCompatibilityInfo;
+        return mResourcesImpl.getCompatibilityInfo();
     }
 
     /**
@@ -2111,8 +1787,7 @@ public class Resources {
      */
     public void setCompatibilityInfo(CompatibilityInfo ci) {
         if (ci != null) {
-            mCompatibilityInfo = ci;
-            updateConfiguration(mConfiguration, mMetrics);
+            mResourcesImpl.updateConfiguration(null, null, ci);
         }
     }
     
@@ -2137,15 +1812,7 @@ public class Resources {
      *         resource was found.  (0 is not a valid resource ID.)
      */
     public int getIdentifier(String name, String defType, String defPackage) {
-        if (name == null) {
-            throw new NullPointerException("name is null");
-        }
-        try {
-            return Integer.parseInt(name);
-        } catch (Exception e) {
-            // Ignore
-        }
-        return mAssets.getResourceIdentifier(name, defType, defPackage);
+        return mResourcesImpl.getIdentifier(name, defType, defPackage);
     }
 
     /**
@@ -2172,10 +1839,7 @@ public class Resources {
      * @see #getResourceEntryName
      */
     public String getResourceName(@AnyRes int resid) throws NotFoundException {
-        String str = mAssets.getResourceName(resid);
-        if (str != null) return str;
-        throw new NotFoundException("Unable to find resource ID #0x"
-                + Integer.toHexString(resid));
+        return mResourcesImpl.getResourceName(resid);
     }
     
     /**
@@ -2191,10 +1855,7 @@ public class Resources {
      * @see #getResourceName
      */
     public String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
-        String str = mAssets.getResourcePackageName(resid);
-        if (str != null) return str;
-        throw new NotFoundException("Unable to find resource ID #0x"
-                + Integer.toHexString(resid));
+        return mResourcesImpl.getResourcePackageName(resid);
     }
     
     /**
@@ -2210,10 +1871,7 @@ public class Resources {
      * @see #getResourceName
      */
     public String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
-        String str = mAssets.getResourceTypeName(resid);
-        if (str != null) return str;
-        throw new NotFoundException("Unable to find resource ID #0x"
-                + Integer.toHexString(resid));
+        return mResourcesImpl.getResourceTypeName(resid);
     }
     
     /**
@@ -2229,10 +1887,7 @@ public class Resources {
      * @see #getResourceName
      */
     public String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
-        String str = mAssets.getResourceEntryName(resid);
-        if (str != null) return str;
-        throw new NotFoundException("Unable to find resource ID #0x"
-                + Integer.toHexString(resid));
+        return mResourcesImpl.getResourceEntryName(resid);
     }
     
     /**
@@ -2335,7 +1990,7 @@ public class Resources {
      * Retrieve underlying AssetManager storage for these resources.
      */
     public final AssetManager getAssets() {
-        return mAssets;
+        return mResourcesImpl.getAssets();
     }
 
     /**
@@ -2344,19 +1999,7 @@ public class Resources {
      * tools.
      */
     public final void flushLayoutCache() {
-        synchronized (mCachedXmlBlocks) {
-            Arrays.fill(mCachedXmlBlockCookies, 0);
-            Arrays.fill(mCachedXmlBlockFiles, null);
-
-            final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
-            for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
-                final XmlBlock oldBlock = cachedXmlBlocks[i];
-                if (oldBlock != null) {
-                    oldBlock.close();
-                }
-            }
-            Arrays.fill(cachedXmlBlocks, null);
-        }
+        mResourcesImpl.flushLayoutCache();
     }
 
     /**
@@ -2365,15 +2008,7 @@ public class Resources {
      * {@hide}
      */
     public final void startPreloading() {
-        synchronized (sSync) {
-            if (sPreloaded) {
-                throw new IllegalStateException("Resources already preloaded");
-            }
-            sPreloaded = true;
-            mPreloading = true;
-            mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
-            updateConfiguration(null, null);
-        }
+        mResourcesImpl.startPreloading();
     }
     
     /**
@@ -2381,441 +2016,14 @@ public class Resources {
      * to normal Resources operation.
      */
     public final void finishPreloading() {
-        if (mPreloading) {
-            mPreloading = false;
-            flushLayoutCache();
-        }
+        mResourcesImpl.finishPreloading();
     }
 
     /**
      * @hide
      */
     public LongSparseArray<ConstantState> getPreloadedDrawables() {
-        return sPreloadedDrawables[0];
-    }
-
-    private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
-            int resourceId, String name) {
-        // We allow preloading of resources even if they vary by font scale (which
-        // doesn't impact resource selection) or density (which we handle specially by
-        // simply turning off all preloading), as well as any other configs specified
-        // by the caller.
-        if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
-                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
-            String resName;
-            try {
-                resName = getResourceName(resourceId);
-            } catch (NotFoundException e) {
-                resName = "?";
-            }
-            // This should never happen in production, so we should log a
-            // warning even if we're not debugging.
-            Log.w(TAG, "Preloaded " + name + " resource #0x"
-                    + Integer.toHexString(resourceId)
-                    + " (" + resName + ") that varies with configuration!!");
-            return false;
-        }
-        if (TRACE_FOR_PRELOAD) {
-            String resName;
-            try {
-                resName = getResourceName(resourceId);
-            } catch (NotFoundException e) {
-                resName = "?";
-            }
-            Log.w(TAG, "Preloading " + name + " resource #0x"
-                    + Integer.toHexString(resourceId)
-                    + " (" + resName + ")");
-        }
-        return true;
-    }
-
-    @Nullable
-    Drawable loadDrawable(TypedValue value, int id, Theme theme) throws NotFoundException {
-        return loadDrawable(value, id, theme, true);
-    }
-
-    @Nullable
-    Drawable loadDrawable(TypedValue value, int id, Theme theme, boolean useCache)
-            throws NotFoundException {
-        try {
-            if (TRACE_FOR_PRELOAD) {
-                // Log only framework resources
-                if ((id >>> 24) == 0x1) {
-                    final String name = getResourceName(id);
-                    if (name != null) {
-                        Log.d("PreloadDrawable", name);
-                    }
-                }
-            }
-
-            final boolean isColorDrawable;
-            final DrawableCache caches;
-            final long key;
-            if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
-                    && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-                isColorDrawable = true;
-                caches = mColorDrawableCache;
-                key = value.data;
-            } else {
-                isColorDrawable = false;
-                caches = mDrawableCache;
-                key = (((long) value.assetCookie) << 32) | value.data;
-            }
-
-            // First, check whether we have a cached version of this drawable
-            // that was inflated against the specified theme. Skip the cache if
-            // we're currently preloading or we're not using the cache.
-            if (!mPreloading && useCache) {
-                final Drawable cachedDrawable = caches.getInstance(key, theme);
-                if (cachedDrawable != null) {
-                    return cachedDrawable;
-                }
-            }
-
-            // Next, check preloaded drawables. Preloaded drawables may contain
-            // unresolved theme attributes.
-            final ConstantState cs;
-            if (isColorDrawable) {
-                cs = sPreloadedColorDrawables.get(key);
-            } else {
-                cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
-            }
-
-            Drawable dr;
-            if (cs != null) {
-                dr = cs.newDrawable(this);
-            } else if (isColorDrawable) {
-                dr = new ColorDrawable(value.data);
-            } else {
-                dr = loadDrawableForCookie(value, id, null);
-            }
-
-            // Determine if the drawable has unresolved theme attributes. If it
-            // does, we'll need to apply a theme and store it in a theme-specific
-            // cache.
-            final boolean canApplyTheme = dr != null && dr.canApplyTheme();
-            if (canApplyTheme && theme != null) {
-                dr = dr.mutate();
-                dr.applyTheme(theme);
-                dr.clearMutated();
-            }
-
-            // If we were able to obtain a drawable, store it in the appropriate
-            // cache: preload, not themed, null theme, or theme-specific. Don't
-            // pollute the cache with drawables loaded from a foreign density.
-            if (dr != null && useCache) {
-                dr.setChangingConfigurations(value.changingConfigurations);
-                cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
-            }
-
-            return dr;
-        } catch (Exception e) {
-            String name;
-            try {
-                name = getResourceName(id);
-            } catch (NotFoundException e2) {
-                name = "(missing name)";
-            }
-
-            // The target drawable might fail to load for any number of
-            // reasons, but we always want to include the resource name.
-            // Since the client already expects this method to throw a
-            // NotFoundException, just throw one of those.
-            final NotFoundException nfe = new NotFoundException("Drawable " + name
-                    + " with resource ID #0x" + Integer.toHexString(id), e);
-            nfe.setStackTrace(new StackTraceElement[0]);
-            throw nfe;
-        }
-    }
-
-    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
-            Theme theme, boolean usesTheme, long key, Drawable dr) {
-        final ConstantState cs = dr.getConstantState();
-        if (cs == null) {
-            return;
-        }
-
-        if (mPreloading) {
-            final int changingConfigs = cs.getChangingConfigurations();
-            if (isColorDrawable) {
-                if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
-                    sPreloadedColorDrawables.put(key, cs);
-                }
-            } else {
-                if (verifyPreloadConfig(
-                        changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
-                    if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
-                        // If this resource does not vary based on layout direction,
-                        // we can put it in all of the preload maps.
-                        sPreloadedDrawables[0].put(key, cs);
-                        sPreloadedDrawables[1].put(key, cs);
-                    } else {
-                        // Otherwise, only in the layout dir we loaded it for.
-                        sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
-                    }
-                }
-            }
-        } else {
-            synchronized (mAccessLock) {
-                caches.put(key, theme, cs, usesTheme);
-            }
-        }
-    }
-
-    /**
-     * Loads a drawable from XML or resources stream.
-     */
-    private Drawable loadDrawableForCookie(TypedValue value, int id, Theme theme) {
-        if (value.string == null) {
-            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
-                    + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
-        }
-
-        final String file = value.string.toString();
-
-        if (TRACE_FOR_MISS_PRELOAD) {
-            // Log only framework resources
-            if ((id >>> 24) == 0x1) {
-                final String name = getResourceName(id);
-                if (name != null) {
-                    Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
-                            + ": " + name + " at " + file);
-                }
-            }
-        }
-
-        if (DEBUG_LOAD) {
-            Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
-        }
-
-        final Drawable dr;
-
-        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
-        try {
-            if (file.endsWith(".xml")) {
-                final XmlResourceParser rp = loadXmlResourceParser(
-                        file, id, value.assetCookie, "drawable");
-                dr = Drawable.createFromXml(this, rp, theme);
-                rp.close();
-            } else {
-                final InputStream is = mAssets.openNonAsset(
-                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
-                dr = Drawable.createFromResourceStream(this, value, is, file, null);
-                is.close();
-            }
-        } catch (Exception e) {
-            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-            final NotFoundException rnf = new NotFoundException(
-                    "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
-            rnf.initCause(e);
-            throw rnf;
-        }
-        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-
-        return dr;
-    }
-
-    /**
-     * Given the value and id, we can get the XML filename as in value.data, based on that, we
-     * first try to load CSL from the cache. If not found, try to get from the constant state.
-     * Last, parse the XML and generate the CSL.
-     */
-    private ComplexColor loadComplexColorFromName(Theme theme, TypedValue value, int id) {
-        final long key = (((long) value.assetCookie) << 32) | value.data;
-        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
-        ComplexColor complexColor = cache.getInstance(key, theme);
-        if (complexColor != null) {
-            return complexColor;
-        }
-
-        final android.content.res.ConstantState<ComplexColor> factory =
-                sPreloadedComplexColors.get(key);
-
-        if (factory != null) {
-            complexColor = factory.newInstance(this, theme);
-        }
-        if (complexColor == null) {
-            complexColor = loadComplexColorForCookie(value, id, theme);
-        }
-
-        if (complexColor != null) {
-            if (mPreloading) {
-                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
-                        "color")) {
-                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
-                }
-            } else {
-                cache.put(key, theme, complexColor.getConstantState());
-            }
-        }
-        return complexColor;
-    }
-
-    @Nullable
-    public ComplexColor loadComplexColor(@NonNull TypedValue value, int id, Theme theme) {
-        if (TRACE_FOR_PRELOAD) {
-            // Log only framework resources
-            if ((id >>> 24) == 0x1) {
-                final String name = getResourceName(id);
-                if (name != null) android.util.Log.d("loadComplexColor", name);
-            }
-        }
-
-        final long key = (((long) value.assetCookie) << 32) | value.data;
-
-        // Handle inline color definitions.
-        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
-                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-            return getColorStateListFromInt(value, key);
-        }
-
-        final String file = value.string.toString();
-
-        ComplexColor complexColor;
-        if (file.endsWith(".xml")) {
-            try {
-                complexColor = loadComplexColorFromName(theme, value, id);
-            } catch (Exception e) {
-                final NotFoundException rnf = new NotFoundException(
-                        "File " + file + " from complex color resource ID #0x"
-                                + Integer.toHexString(id));
-                rnf.initCause(e);
-                throw rnf;
-            }
-        } else {
-            throw new NotFoundException(
-                    "File " + file + " from drawable resource ID #0x"
-                            + Integer.toHexString(id) + ": .xml extension required");
-        }
-
-        return complexColor;
-    }
-
-    @Nullable
-    ColorStateList loadColorStateList(TypedValue value, int id, Theme theme)
-            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);
-            }
-        }
-
-        final long key = (((long) value.assetCookie) << 32) | value.data;
-
-        // Handle inline color definitions.
-        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
-                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
-            return getColorStateListFromInt(value, key);
-        }
-
-        ComplexColor complexColor = loadComplexColorFromName(theme, value, id);
-        if (complexColor != null && complexColor instanceof ColorStateList) {
-            return (ColorStateList) complexColor;
-        }
-
-        throw new NotFoundException(
-                "Can't find ColorStateList from drawable resource ID #0x"
-                        + Integer.toHexString(id));
-    }
-
-    @NonNull
-    private ColorStateList getColorStateListFromInt(@NonNull  TypedValue value, long key) {
-        ColorStateList csl;
-        final android.content.res.ConstantState<ComplexColor> factory =
-                sPreloadedComplexColors.get(key);
-        if (factory != null) {
-            return (ColorStateList) factory.newInstance();
-        }
-
-        csl = ColorStateList.valueOf(value.data);
-
-        if (mPreloading) {
-            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
-                    "color")) {
-                sPreloadedComplexColors.put(key, csl.getConstantState());
-            }
-        }
-
-        return csl;
-    }
-
-    /**
-     * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
-     * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
-     *
-     * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
-     * and selector tag.
-     *
-     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
-     */
-    @Nullable
-    private ComplexColor loadComplexColorForCookie(TypedValue value, int id, Theme theme) {
-        if (value.string == null) {
-            throw new UnsupportedOperationException(
-                    "Can't convert to ComplexColor: type=0x" + value.type);
-        }
-
-        final String file = value.string.toString();
-
-        if (TRACE_FOR_MISS_PRELOAD) {
-            // Log only framework resources
-            if ((id >>> 24) == 0x1) {
-                final String name = getResourceName(id);
-                if (name != null) {
-                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
-                            + ": " + name + " at " + file);
-                }
-            }
-        }
-
-        if (DEBUG_LOAD) {
-            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
-        }
-
-        ComplexColor complexColor = null;
-
-        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
-        if (file.endsWith(".xml")) {
-            try {
-                final XmlResourceParser parser = loadXmlResourceParser(
-                        file, id, value.assetCookie, "ComplexColor");
-
-                final AttributeSet attrs = Xml.asAttributeSet(parser);
-                int type;
-                while ((type = parser.next()) != XmlPullParser.START_TAG
-                        && type != XmlPullParser.END_DOCUMENT) {
-                    // Seek parser to start tag.
-                }
-                if (type != XmlPullParser.START_TAG) {
-                    throw new XmlPullParserException("No start tag found");
-                }
-
-                final String name = parser.getName();
-                if (name.equals("gradient")) {
-                    complexColor = GradientColor.createFromXmlInner(this, parser, attrs, theme);
-                } else if (name.equals("selector")) {
-                    complexColor = ColorStateList.createFromXmlInner(this, parser, attrs, theme);
-                }
-                parser.close();
-            } catch (Exception e) {
-                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-                final NotFoundException rnf = new NotFoundException(
-                        "File " + file + " from ComplexColor resource ID #0x"
-                                + Integer.toHexString(id));
-                rnf.initCause(e);
-                throw rnf;
-            }
-        } else {
-            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-            throw new NotFoundException(
-                    "File " + file + " from drawable resource ID #0x"
-                            + Integer.toHexString(id) + ": .xml extension required");
-        }
-        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
-
-        return complexColor;
+        return mResourcesImpl.getPreloadedDrawables();
     }
 
     /**
@@ -2829,10 +2037,12 @@ public class Resources {
     @NonNull
     XmlResourceParser loadXmlResourceParser(@AnyRes int id, @NonNull String type)
             throws NotFoundException {
-        final TypedValue value = obtainTempTypedValue(id);
+        final TypedValue value = obtainTempTypedValue();
         try {
+            final ResourcesImpl impl = mResourcesImpl;
+            impl.getValue(id, value, true);
             if (value.type == TypedValue.TYPE_STRING) {
-                return loadXmlResourceParser(value.string.toString(), id,
+                return impl.loadXmlResourceParser(value.string.toString(), id,
                         value.assetCookie, type);
             }
             throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id)
@@ -2853,49 +2063,9 @@ public class Resources {
      * @throws NotFoundException if the file could not be loaded
      */
     @NonNull
-    XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id,
-            int assetCookie, @NonNull String type) throws NotFoundException {
-        if (id != 0) {
-            try {
-                synchronized (mCachedXmlBlocks) {
-                    final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
-                    final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
-                    final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
-                    // First see if this block is in our cache.
-                    final int num = cachedXmlBlockFiles.length;
-                    for (int i = 0; i < num; i++) {
-                        if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
-                                && cachedXmlBlockFiles[i].equals(file)) {
-                            return cachedXmlBlocks[i].newParser();
-                        }
-                    }
-
-                    // Not in the cache, create a new block and put it at
-                    // the next slot in the cache.
-                    final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
-                    if (block != null) {
-                        final int pos = (mLastCachedXmlBlockIndex + 1) % num;
-                        mLastCachedXmlBlockIndex = pos;
-                        final XmlBlock oldBlock = cachedXmlBlocks[pos];
-                        if (oldBlock != null) {
-                            oldBlock.close();
-                        }
-                        cachedXmlBlockCookies[pos] = assetCookie;
-                        cachedXmlBlockFiles[pos] = file;
-                        cachedXmlBlocks[pos] = block;
-                        return block.newParser();
-                    }
-                }
-            } catch (Exception e) {
-                final NotFoundException rnf = new NotFoundException("File " + file
-                        + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
-                rnf.initCause(e);
-                throw rnf;
-            }
-        }
-
-        throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
-                + Integer.toHexString(id));
+    XmlResourceParser loadXmlResourceParser(String file, int id, int assetCookie,
+                                            String type) throws NotFoundException {
+        return mResourcesImpl.loadXmlResourceParser(file, id, assetCookie, type);
     }
 
     /**
@@ -2911,16 +2081,4 @@ public class Resources {
         }
         return theme.obtainStyledAttributes(set, attrs, 0, 0);
     }
-
-    private Resources() {
-        mAssets = AssetManager.getSystem();
-        mClassLoader = ClassLoader.getSystemClassLoader();
-        // NOTE: Intentionally leaving this uninitialized (all values set
-        // to zero), so that anyone who tries to do something that requires
-        // metrics will get a very wrong value.
-        mConfiguration.setToDefaults();
-        mMetrics.setToDefaults();
-        updateConfiguration(null, null);
-        mAssets.ensureStringBlocks();
-    }
 }
diff --git a/core/java/android/content/res/ResourcesImpl.java b/core/java/android/content/res/ResourcesImpl.java
new file mode 100644 (file)
index 0000000..2ffd372
--- /dev/null
@@ -0,0 +1,1140 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package android.content.res;
+
+import android.animation.Animator;
+import android.animation.StateListAnimator;
+import android.annotation.AnyRes;
+import android.annotation.AttrRes;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.PluralsRes;
+import android.annotation.RawRes;
+import android.annotation.StyleRes;
+import android.annotation.StyleableRes;
+import android.content.pm.ActivityInfo;
+import android.content.res.Resources.NotFoundException;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.icu.text.PluralRules;
+import android.os.Build;
+import android.os.Trace;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.LocaleList;
+import android.util.Log;
+import android.util.LongSparseArray;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.util.Xml;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.InputStream;
+import java.util.Arrays;
+import java.util.Locale;
+
+/**
+ * @hide
+ */
+public class ResourcesImpl {
+    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 boolean TRACE_FOR_MISS_PRELOAD = false;
+
+    private static final int LAYOUT_DIR_CONFIG = ActivityInfo.activityInfoConfigToNative(
+            ActivityInfo.CONFIG_LAYOUT_DIRECTION);
+
+    private static final int ID_OTHER = 0x01000004;
+
+    private static final Object sSync = new Object();
+
+    private static boolean sPreloaded;
+    private boolean mPreloading;
+
+    // Information about preloaded resources.  Note that they are not
+    // protected by a lock, because while preloading in zygote we are all
+    // single-threaded, and after that these are immutable.
+    private static final LongSparseArray<Drawable.ConstantState>[] sPreloadedDrawables;
+    private static final LongSparseArray<Drawable.ConstantState> sPreloadedColorDrawables
+            = new LongSparseArray<>();
+    private static final LongSparseArray<android.content.res.ConstantState<ComplexColor>>
+            sPreloadedComplexColors = new LongSparseArray<>();
+
+    /** Lock object used to protect access to caches and configuration. */
+    private final Object mAccessLock = new Object();
+
+    // These are protected by mAccessLock.
+    private final Configuration mTmpConfig = new Configuration();
+    private final DrawableCache mDrawableCache = new DrawableCache();
+    private final DrawableCache mColorDrawableCache = new DrawableCache();
+    private final ConfigurationBoundResourceCache<ComplexColor> mComplexColorCache =
+            new ConfigurationBoundResourceCache<>();
+    private final ConfigurationBoundResourceCache<Animator> mAnimatorCache =
+            new ConfigurationBoundResourceCache<>();
+    private final ConfigurationBoundResourceCache<StateListAnimator> mStateListAnimatorCache =
+            new ConfigurationBoundResourceCache<>();
+
+    /** Size of the cyclical cache used to map XML files to blocks. */
+    private static final int XML_BLOCK_CACHE_SIZE = 4;
+
+    // Cyclical cache used for recently-accessed XML files.
+    private int mLastCachedXmlBlockIndex = -1;
+    private final int[] mCachedXmlBlockCookies = new int[XML_BLOCK_CACHE_SIZE];
+    private final String[] mCachedXmlBlockFiles = new String[XML_BLOCK_CACHE_SIZE];
+    private final XmlBlock[] mCachedXmlBlocks = new XmlBlock[XML_BLOCK_CACHE_SIZE];
+
+
+    final AssetManager mAssets;
+    final DisplayMetrics mMetrics = new DisplayMetrics();
+
+    private PluralRules mPluralRule;
+
+    private final Configuration mConfiguration = new Configuration();
+    private CompatibilityInfo mCompatibilityInfo = CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
+
+    static {
+        sPreloadedDrawables = new LongSparseArray[2];
+        sPreloadedDrawables[0] = new LongSparseArray<>();
+        sPreloadedDrawables[1] = new LongSparseArray<>();
+    }
+
+    /**
+     * Creates a new ResourcesImpl object with CompatibilityInfo.
+     *
+     * @param assets Previously created AssetManager.
+     * @param metrics Current display metrics to consider when
+     *                selecting/computing resource values.
+     * @param config Desired device configuration to consider when
+     *               selecting/computing resource values (optional).
+     * @param compatInfo this resource's compatibility info. Must not be null.
+     */
+    public ResourcesImpl(AssetManager assets, DisplayMetrics metrics, Configuration config,
+                         CompatibilityInfo compatInfo) {
+        mAssets = assets;
+        mMetrics.setToDefaults();
+        updateConfiguration(config, metrics, compatInfo);
+        mAssets.ensureStringBlocks();
+    }
+
+    AssetManager getAssets() {
+        return mAssets;
+    }
+
+    DisplayMetrics getDisplayMetrics() {
+        if (DEBUG_CONFIG) Slog.v(TAG, "Returning DisplayMetrics: " + mMetrics.widthPixels
+                + "x" + mMetrics.heightPixels + " " + mMetrics.density);
+        return mMetrics;
+    }
+
+    Configuration getConfiguration() {
+        return mConfiguration;
+    }
+
+    Configuration[] getSizeConfigurations() {
+        return mAssets.getSizeConfigurations();
+    }
+
+    CompatibilityInfo getCompatibilityInfo() {
+        return mCompatibilityInfo;
+    }
+
+    private PluralRules getPluralRule() {
+        synchronized (sSync) {
+            if (mPluralRule == null) {
+                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
+            }
+            return mPluralRule;
+        }
+    }
+
+    void getValue(@AnyRes int id, TypedValue outValue, boolean resolveRefs)
+            throws NotFoundException {
+        boolean found = mAssets.getResourceValue(id, 0, outValue, resolveRefs);
+        if (found) {
+            return;
+        }
+        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+    }
+
+    void getValueForDensity(@AnyRes int id, int density, TypedValue outValue,
+                            boolean resolveRefs) throws NotFoundException {
+        boolean found = mAssets.getResourceValue(id, density, outValue, resolveRefs);
+        if (found) {
+            return;
+        }
+        throw new NotFoundException("Resource ID #0x" + Integer.toHexString(id));
+    }
+
+    void getValue(String name, TypedValue outValue, boolean resolveRefs)
+            throws NotFoundException {
+        int id = getIdentifier(name, "string", null);
+        if (id != 0) {
+            getValue(id, outValue, resolveRefs);
+            return;
+        }
+        throw new NotFoundException("String resource name " + name);
+    }
+
+    int getIdentifier(String name, String defType, String defPackage) {
+        if (name == null) {
+            throw new NullPointerException("name is null");
+        }
+        try {
+            return Integer.parseInt(name);
+        } catch (Exception e) {
+            // Ignore
+        }
+        return mAssets.getResourceIdentifier(name, defType, defPackage);
+    }
+
+    @NonNull
+    String getResourceName(@AnyRes int resid) throws NotFoundException {
+        String str = mAssets.getResourceName(resid);
+        if (str != null) return str;
+        throw new NotFoundException("Unable to find resource ID #0x"
+                + Integer.toHexString(resid));
+    }
+
+    @NonNull
+    String getResourcePackageName(@AnyRes int resid) throws NotFoundException {
+        String str = mAssets.getResourcePackageName(resid);
+        if (str != null) return str;
+        throw new NotFoundException("Unable to find resource ID #0x"
+                + Integer.toHexString(resid));
+    }
+
+    @NonNull
+    String getResourceTypeName(@AnyRes int resid) throws NotFoundException {
+        String str = mAssets.getResourceTypeName(resid);
+        if (str != null) return str;
+        throw new NotFoundException("Unable to find resource ID #0x"
+                + Integer.toHexString(resid));
+    }
+
+    @NonNull
+    String getResourceEntryName(@AnyRes int resid) throws NotFoundException {
+        String str = mAssets.getResourceEntryName(resid);
+        if (str != null) return str;
+        throw new NotFoundException("Unable to find resource ID #0x"
+                + Integer.toHexString(resid));
+    }
+
+    @NonNull
+    CharSequence getQuantityText(@PluralsRes int id, int quantity) throws NotFoundException {
+        PluralRules rule = getPluralRule();
+        CharSequence res = mAssets.getResourceBagText(id,
+                attrForQuantityCode(rule.select(quantity)));
+        if (res != null) {
+            return res;
+        }
+        res = mAssets.getResourceBagText(id, ID_OTHER);
+        if (res != null) {
+            return res;
+        }
+        throw new NotFoundException("Plural resource ID #0x" + Integer.toHexString(id)
+                + " quantity=" + quantity
+                + " item=" + rule.select(quantity));
+    }
+
+    private static int attrForQuantityCode(String quantityCode) {
+        switch (quantityCode) {
+            case PluralRules.KEYWORD_ZERO: return 0x01000005;
+            case PluralRules.KEYWORD_ONE:  return 0x01000006;
+            case PluralRules.KEYWORD_TWO:  return 0x01000007;
+            case PluralRules.KEYWORD_FEW:  return 0x01000008;
+            case PluralRules.KEYWORD_MANY: return 0x01000009;
+            default:                       return ID_OTHER;
+        }
+    }
+
+    @NonNull
+    AssetFileDescriptor openRawResourceFd(@RawRes int id, TypedValue tempValue)
+            throws NotFoundException {
+        getValue(id, tempValue, true);
+        try {
+            return mAssets.openNonAssetFd(tempValue.assetCookie, tempValue.string.toString());
+        } catch (Exception e) {
+            throw new NotFoundException("File " + tempValue.string.toString() + " from drawable "
+                    + "resource ID #0x" + Integer.toHexString(id), e);
+        }
+    }
+
+    @NonNull
+    InputStream openRawResource(@RawRes int id, TypedValue value) throws NotFoundException {
+        getValue(id, value, true);
+        try {
+            return mAssets.openNonAsset(value.assetCookie, value.string.toString(),
+                    AssetManager.ACCESS_STREAMING);
+        } catch (Exception e) {
+            NotFoundException rnf = new NotFoundException("File " + value.string.toString() +
+                    " from drawable resource ID #0x" + Integer.toHexString(id));
+            rnf.initCause(e);
+            throw rnf;
+        }
+    }
+
+    ConfigurationBoundResourceCache<Animator> getAnimatorCache() {
+        return mAnimatorCache;
+    }
+
+    ConfigurationBoundResourceCache<StateListAnimator> getStateListAnimatorCache() {
+        return mStateListAnimatorCache;
+    }
+
+    void updateConfiguration(Configuration config, DisplayMetrics metrics,
+                             CompatibilityInfo compat) {
+        synchronized (mAccessLock) {
+            if (false) {
+                Slog.i(TAG, "**** Updating config of " + this + ": old config is "
+                        + mConfiguration + " old compat is " + mCompatibilityInfo);
+                Slog.i(TAG, "**** Updating config of " + this + ": new config is "
+                        + config + " new compat is " + compat);
+            }
+            if (compat != null) {
+                mCompatibilityInfo = compat;
+            }
+            if (metrics != null) {
+                mMetrics.setTo(metrics);
+            }
+            // NOTE: We should re-arrange this code to create a Display
+            // with the CompatibilityInfo that is used everywhere we deal
+            // with the display in relation to this app, rather than
+            // doing the conversion here.  This impl should be okay because
+            // we make sure to return a compatible display in the places
+            // where there are public APIs to retrieve the display...  but
+            // it would be cleaner and more maintainble to just be
+            // consistently dealing with a compatible display everywhere in
+            // the framework.
+            mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
+
+            final int configChanges = calcConfigChanges(config);
+
+            LocaleList locales = mConfiguration.getLocales();
+            if (locales.isEmpty()) {
+                locales = LocaleList.getAdjustedDefault();
+                mConfiguration.setLocales(locales);
+            }
+            if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
+                mMetrics.densityDpi = mConfiguration.densityDpi;
+                mMetrics.density = mConfiguration.densityDpi * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+            }
+            mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
+
+            final int width, height;
+            if (mMetrics.widthPixels >= mMetrics.heightPixels) {
+                width = mMetrics.widthPixels;
+                height = mMetrics.heightPixels;
+            } else {
+                //noinspection SuspiciousNameCombination
+                width = mMetrics.heightPixels;
+                //noinspection SuspiciousNameCombination
+                height = mMetrics.widthPixels;
+            }
+
+            final int keyboardHidden;
+            if (mConfiguration.keyboardHidden == Configuration.KEYBOARDHIDDEN_NO
+                    && mConfiguration.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_YES) {
+                keyboardHidden = Configuration.KEYBOARDHIDDEN_SOFT;
+            } else {
+                keyboardHidden = mConfiguration.keyboardHidden;
+            }
+
+            mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
+                    adjustLanguageTag(locales.get(0).toLanguageTag()),
+                    mConfiguration.orientation,
+                    mConfiguration.touchscreen,
+                    mConfiguration.densityDpi, mConfiguration.keyboard,
+                    keyboardHidden, mConfiguration.navigation, width, height,
+                    mConfiguration.smallestScreenWidthDp,
+                    mConfiguration.screenWidthDp, mConfiguration.screenHeightDp,
+                    mConfiguration.screenLayout, mConfiguration.uiMode,
+                    Build.VERSION.RESOURCES_SDK_INT);
+
+            if (DEBUG_CONFIG) {
+                Slog.i(TAG, "**** Updating config of " + this + ": final config is "
+                        + mConfiguration + " final compat is " + mCompatibilityInfo);
+            }
+
+            mDrawableCache.onConfigurationChange(configChanges);
+            mColorDrawableCache.onConfigurationChange(configChanges);
+            mComplexColorCache.onConfigurationChange(configChanges);
+            mAnimatorCache.onConfigurationChange(configChanges);
+            mStateListAnimatorCache.onConfigurationChange(configChanges);
+
+            flushLayoutCache();
+        }
+        synchronized (sSync) {
+            if (mPluralRule != null) {
+                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().get(0));
+            }
+        }
+    }
+
+    /**
+     * Called by ConfigurationBoundResourceCacheTest via reflection.
+     */
+    private int calcConfigChanges(Configuration config) {
+        int configChanges = 0xfffffff;
+        if (config != null) {
+            mTmpConfig.setTo(config);
+            int density = config.densityDpi;
+            if (density == Configuration.DENSITY_DPI_UNDEFINED) {
+                density = mMetrics.noncompatDensityDpi;
+            }
+
+            mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
+
+            if (mTmpConfig.getLocales().isEmpty()) {
+                mTmpConfig.setLocales(LocaleList.getDefault());
+            }
+            configChanges = mConfiguration.updateFrom(mTmpConfig);
+            configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
+        }
+        return configChanges;
+    }
+
+    /**
+     * {@code Locale.toLanguageTag} will transform the obsolete (and deprecated)
+     * language codes "in", "ji" and "iw" to "id", "yi" and "he" respectively.
+     *
+     * All released versions of android prior to "L" used the deprecated language
+     * tags, so we will need to support them for backwards compatibility.
+     *
+     * Note that this conversion needs to take place *after* the call to
+     * {@code toLanguageTag} because that will convert all the deprecated codes to
+     * the new ones, even if they're set manually.
+     */
+    private static String adjustLanguageTag(String languageTag) {
+        final int separator = languageTag.indexOf('-');
+        final String language;
+        final String remainder;
+
+        if (separator == -1) {
+            language = languageTag;
+            remainder = "";
+        } else {
+            language = languageTag.substring(0, separator);
+            remainder = languageTag.substring(separator);
+        }
+
+        return Locale.adjustLanguageCode(language) + remainder;
+    }
+
+    /**
+     * Call this to remove all cached loaded layout resources from the
+     * Resources object.  Only intended for use with performance testing
+     * tools.
+     */
+    public void flushLayoutCache() {
+        synchronized (mCachedXmlBlocks) {
+            Arrays.fill(mCachedXmlBlockCookies, 0);
+            Arrays.fill(mCachedXmlBlockFiles, null);
+
+            final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+            for (int i = 0; i < XML_BLOCK_CACHE_SIZE; i++) {
+                final XmlBlock oldBlock = cachedXmlBlocks[i];
+                if (oldBlock != null) {
+                    oldBlock.close();
+                }
+            }
+            Arrays.fill(cachedXmlBlocks, null);
+        }
+    }
+
+    @Nullable
+    Drawable loadDrawable(Resources wrapper, TypedValue value, int id, Resources.Theme theme,
+                          boolean useCache) throws NotFoundException {
+        try {
+            if (TRACE_FOR_PRELOAD) {
+                // Log only framework resources
+                if ((id >>> 24) == 0x1) {
+                    final String name = getResourceName(id);
+                    if (name != null) {
+                        Log.d("PreloadDrawable", name);
+                    }
+                }
+            }
+
+            final boolean isColorDrawable;
+            final DrawableCache caches;
+            final long key;
+            if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+                    && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+                isColorDrawable = true;
+                caches = mColorDrawableCache;
+                key = value.data;
+            } else {
+                isColorDrawable = false;
+                caches = mDrawableCache;
+                key = (((long) value.assetCookie) << 32) | value.data;
+            }
+
+            // First, check whether we have a cached version of this drawable
+            // that was inflated against the specified theme. Skip the cache if
+            // we're currently preloading or we're not using the cache.
+            if (!mPreloading && useCache) {
+                final Drawable cachedDrawable = caches.getInstance(key, wrapper, theme);
+                if (cachedDrawable != null) {
+                    return cachedDrawable;
+                }
+            }
+
+            // Next, check preloaded drawables. Preloaded drawables may contain
+            // unresolved theme attributes.
+            final Drawable.ConstantState cs;
+            if (isColorDrawable) {
+                cs = sPreloadedColorDrawables.get(key);
+            } else {
+                cs = sPreloadedDrawables[mConfiguration.getLayoutDirection()].get(key);
+            }
+
+            Drawable dr;
+            if (cs != null) {
+                dr = cs.newDrawable(wrapper);
+            } else if (isColorDrawable) {
+                dr = new ColorDrawable(value.data);
+            } else {
+                dr = loadDrawableForCookie(wrapper, value, id, null);
+            }
+
+            // Determine if the drawable has unresolved theme attributes. If it
+            // does, we'll need to apply a theme and store it in a theme-specific
+            // cache.
+            final boolean canApplyTheme = dr != null && dr.canApplyTheme();
+            if (canApplyTheme && theme != null) {
+                dr = dr.mutate();
+                dr.applyTheme(theme);
+                dr.clearMutated();
+            }
+
+            // If we were able to obtain a drawable, store it in the appropriate
+            // cache: preload, not themed, null theme, or theme-specific. Don't
+            // pollute the cache with drawables loaded from a foreign density.
+            if (dr != null && useCache) {
+                dr.setChangingConfigurations(value.changingConfigurations);
+                cacheDrawable(value, isColorDrawable, caches, theme, canApplyTheme, key, dr);
+            }
+
+            return dr;
+        } catch (Exception e) {
+            String name;
+            try {
+                name = getResourceName(id);
+            } catch (NotFoundException e2) {
+                name = "(missing name)";
+            }
+
+            // The target drawable might fail to load for any number of
+            // reasons, but we always want to include the resource name.
+            // Since the client already expects this method to throw a
+            // NotFoundException, just throw one of those.
+            final NotFoundException nfe = new NotFoundException("Drawable " + name
+                    + " with resource ID #0x" + Integer.toHexString(id), e);
+            nfe.setStackTrace(new StackTraceElement[0]);
+            throw nfe;
+        }
+    }
+
+    private void cacheDrawable(TypedValue value, boolean isColorDrawable, DrawableCache caches,
+                               Resources.Theme theme, boolean usesTheme, long key, Drawable dr) {
+        final Drawable.ConstantState cs = dr.getConstantState();
+        if (cs == null) {
+            return;
+        }
+
+        if (mPreloading) {
+            final int changingConfigs = cs.getChangingConfigurations();
+            if (isColorDrawable) {
+                if (verifyPreloadConfig(changingConfigs, 0, value.resourceId, "drawable")) {
+                    sPreloadedColorDrawables.put(key, cs);
+                }
+            } else {
+                if (verifyPreloadConfig(
+                        changingConfigs, LAYOUT_DIR_CONFIG, value.resourceId, "drawable")) {
+                    if ((changingConfigs & LAYOUT_DIR_CONFIG) == 0) {
+                        // If this resource does not vary based on layout direction,
+                        // we can put it in all of the preload maps.
+                        sPreloadedDrawables[0].put(key, cs);
+                        sPreloadedDrawables[1].put(key, cs);
+                    } else {
+                        // Otherwise, only in the layout dir we loaded it for.
+                        sPreloadedDrawables[mConfiguration.getLayoutDirection()].put(key, cs);
+                    }
+                }
+            }
+        } else {
+            synchronized (mAccessLock) {
+                caches.put(key, theme, cs, usesTheme);
+            }
+        }
+    }
+
+    private boolean verifyPreloadConfig(int changingConfigurations, int allowVarying,
+                                        int resourceId, String name) {
+        // We allow preloading of resources even if they vary by font scale (which
+        // doesn't impact resource selection) or density (which we handle specially by
+        // simply turning off all preloading), as well as any other configs specified
+        // by the caller.
+        if (((changingConfigurations&~(ActivityInfo.CONFIG_FONT_SCALE |
+                ActivityInfo.CONFIG_DENSITY)) & ~allowVarying) != 0) {
+            String resName;
+            try {
+                resName = getResourceName(resourceId);
+            } catch (NotFoundException e) {
+                resName = "?";
+            }
+            // This should never happen in production, so we should log a
+            // warning even if we're not debugging.
+            Log.w(TAG, "Preloaded " + name + " resource #0x"
+                    + Integer.toHexString(resourceId)
+                    + " (" + resName + ") that varies with configuration!!");
+            return false;
+        }
+        if (TRACE_FOR_PRELOAD) {
+            String resName;
+            try {
+                resName = getResourceName(resourceId);
+            } catch (NotFoundException e) {
+                resName = "?";
+            }
+            Log.w(TAG, "Preloading " + name + " resource #0x"
+                    + Integer.toHexString(resourceId)
+                    + " (" + resName + ")");
+        }
+        return true;
+    }
+
+    /**
+     * Loads a drawable from XML or resources stream.
+     */
+    private Drawable loadDrawableForCookie(Resources wrapper, TypedValue value, int id,
+                                           Resources.Theme theme) {
+        if (value.string == null) {
+            throw new NotFoundException("Resource \"" + getResourceName(id) + "\" ("
+                    + Integer.toHexString(id) + ") is not a Drawable (color or path): " + value);
+        }
+
+        final String file = value.string.toString();
+
+        if (TRACE_FOR_MISS_PRELOAD) {
+            // Log only framework resources
+            if ((id >>> 24) == 0x1) {
+                final String name = getResourceName(id);
+                if (name != null) {
+                    Log.d(TAG, "Loading framework drawable #" + Integer.toHexString(id)
+                            + ": " + name + " at " + file);
+                }
+            }
+        }
+
+        if (DEBUG_LOAD) {
+            Log.v(TAG, "Loading drawable for cookie " + value.assetCookie + ": " + file);
+        }
+
+        final Drawable dr;
+
+        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+        try {
+            if (file.endsWith(".xml")) {
+                final XmlResourceParser rp = loadXmlResourceParser(
+                        file, id, value.assetCookie, "drawable");
+                dr = Drawable.createFromXml(wrapper, rp, theme);
+                rp.close();
+            } else {
+                final InputStream is = mAssets.openNonAsset(
+                        value.assetCookie, file, AssetManager.ACCESS_STREAMING);
+                dr = Drawable.createFromResourceStream(wrapper, value, is, file, null);
+                is.close();
+            }
+        } catch (Exception e) {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+            final NotFoundException rnf = new NotFoundException(
+                    "File " + file + " from drawable resource ID #0x" + Integer.toHexString(id));
+            rnf.initCause(e);
+            throw rnf;
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+
+        return dr;
+    }
+
+    /**
+     * Given the value and id, we can get the XML filename as in value.data, based on that, we
+     * first try to load CSL from the cache. If not found, try to get from the constant state.
+     * Last, parse the XML and generate the CSL.
+     */
+    private ComplexColor loadComplexColorFromName(Resources wrapper, Resources.Theme theme,
+                                                  TypedValue value, int id) {
+        final long key = (((long) value.assetCookie) << 32) | value.data;
+        final ConfigurationBoundResourceCache<ComplexColor> cache = mComplexColorCache;
+        ComplexColor complexColor = cache.getInstance(key, wrapper, theme);
+        if (complexColor != null) {
+            return complexColor;
+        }
+
+        final android.content.res.ConstantState<ComplexColor> factory =
+                sPreloadedComplexColors.get(key);
+
+        if (factory != null) {
+            complexColor = factory.newInstance(wrapper, theme);
+        }
+        if (complexColor == null) {
+            complexColor = loadComplexColorForCookie(wrapper, value, id, theme);
+        }
+
+        if (complexColor != null) {
+            if (mPreloading) {
+                if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+                        "color")) {
+                    sPreloadedComplexColors.put(key, complexColor.getConstantState());
+                }
+            } else {
+                cache.put(key, theme, complexColor.getConstantState());
+            }
+        }
+        return complexColor;
+    }
+
+    @Nullable
+    ComplexColor loadComplexColor(Resources wrapper, @NonNull TypedValue value, int id,
+                                  Resources.Theme theme) {
+        if (TRACE_FOR_PRELOAD) {
+            // Log only framework resources
+            if ((id >>> 24) == 0x1) {
+                final String name = getResourceName(id);
+                if (name != null) android.util.Log.d("loadComplexColor", name);
+            }
+        }
+
+        final long key = (((long) value.assetCookie) << 32) | value.data;
+
+        // Handle inline color definitions.
+        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+            return getColorStateListFromInt(value, key);
+        }
+
+        final String file = value.string.toString();
+
+        ComplexColor complexColor;
+        if (file.endsWith(".xml")) {
+            try {
+                complexColor = loadComplexColorFromName(wrapper, theme, value, id);
+            } catch (Exception e) {
+                final NotFoundException rnf = new NotFoundException(
+                        "File " + file + " from complex color resource ID #0x"
+                                + Integer.toHexString(id));
+                rnf.initCause(e);
+                throw rnf;
+            }
+        } else {
+            throw new NotFoundException(
+                    "File " + file + " from drawable resource ID #0x"
+                            + Integer.toHexString(id) + ": .xml extension required");
+        }
+
+        return complexColor;
+    }
+
+    @Nullable
+    ColorStateList loadColorStateList(Resources wrapper, TypedValue value, int id,
+                                      Resources.Theme theme)
+            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);
+            }
+        }
+
+        final long key = (((long) value.assetCookie) << 32) | value.data;
+
+        // Handle inline color definitions.
+        if (value.type >= TypedValue.TYPE_FIRST_COLOR_INT
+                && value.type <= TypedValue.TYPE_LAST_COLOR_INT) {
+            return getColorStateListFromInt(value, key);
+        }
+
+        ComplexColor complexColor = loadComplexColorFromName(wrapper, theme, value, id);
+        if (complexColor != null && complexColor instanceof ColorStateList) {
+            return (ColorStateList) complexColor;
+        }
+
+        throw new NotFoundException(
+                "Can't find ColorStateList from drawable resource ID #0x"
+                        + Integer.toHexString(id));
+    }
+
+    @NonNull
+    private ColorStateList getColorStateListFromInt(@NonNull TypedValue value, long key) {
+        ColorStateList csl;
+        final android.content.res.ConstantState<ComplexColor> factory =
+                sPreloadedComplexColors.get(key);
+        if (factory != null) {
+            return (ColorStateList) factory.newInstance();
+        }
+
+        csl = ColorStateList.valueOf(value.data);
+
+        if (mPreloading) {
+            if (verifyPreloadConfig(value.changingConfigurations, 0, value.resourceId,
+                    "color")) {
+                sPreloadedComplexColors.put(key, csl.getConstantState());
+            }
+        }
+
+        return csl;
+    }
+
+    /**
+     * Load a ComplexColor based on the XML file content. The result can be a GradientColor or
+     * ColorStateList. Note that pure color will be wrapped into a ColorStateList.
+     *
+     * We deferred the parser creation to this function b/c we need to differentiate b/t gradient
+     * and selector tag.
+     *
+     * @return a ComplexColor (GradientColor or ColorStateList) based on the XML file content.
+     */
+    @Nullable
+    private ComplexColor loadComplexColorForCookie(Resources wrapper, TypedValue value, int id,
+                                                   Resources.Theme theme) {
+        if (value.string == null) {
+            throw new UnsupportedOperationException(
+                    "Can't convert to ComplexColor: type=0x" + value.type);
+        }
+
+        final String file = value.string.toString();
+
+        if (TRACE_FOR_MISS_PRELOAD) {
+            // Log only framework resources
+            if ((id >>> 24) == 0x1) {
+                final String name = getResourceName(id);
+                if (name != null) {
+                    Log.d(TAG, "Loading framework ComplexColor #" + Integer.toHexString(id)
+                            + ": " + name + " at " + file);
+                }
+            }
+        }
+
+        if (DEBUG_LOAD) {
+            Log.v(TAG, "Loading ComplexColor for cookie " + value.assetCookie + ": " + file);
+        }
+
+        ComplexColor complexColor = null;
+
+        Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, file);
+        if (file.endsWith(".xml")) {
+            try {
+                final XmlResourceParser parser = loadXmlResourceParser(
+                        file, id, value.assetCookie, "ComplexColor");
+
+                final AttributeSet attrs = Xml.asAttributeSet(parser);
+                int type;
+                while ((type = parser.next()) != XmlPullParser.START_TAG
+                        && type != XmlPullParser.END_DOCUMENT) {
+                    // Seek parser to start tag.
+                }
+                if (type != XmlPullParser.START_TAG) {
+                    throw new XmlPullParserException("No start tag found");
+                }
+
+                final String name = parser.getName();
+                if (name.equals("gradient")) {
+                    complexColor = GradientColor.createFromXmlInner(wrapper, parser, attrs, theme);
+                } else if (name.equals("selector")) {
+                    complexColor = ColorStateList.createFromXmlInner(wrapper, parser, attrs, theme);
+                }
+                parser.close();
+            } catch (Exception e) {
+                Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+                final NotFoundException rnf = new NotFoundException(
+                        "File " + file + " from ComplexColor resource ID #0x"
+                                + Integer.toHexString(id));
+                rnf.initCause(e);
+                throw rnf;
+            }
+        } else {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+            throw new NotFoundException(
+                    "File " + file + " from drawable resource ID #0x"
+                            + Integer.toHexString(id) + ": .xml extension required");
+        }
+        Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+
+        return complexColor;
+    }
+
+    /**
+     * Loads an XML parser for the specified file.
+     *
+     * @param file the path for the XML file to parse
+     * @param id the resource identifier for the file
+     * @param assetCookie the asset cookie for the file
+     * @param type the type of resource (used for logging)
+     * @return a parser for the specified XML file
+     * @throws NotFoundException if the file could not be loaded
+     */
+    @NonNull
+    XmlResourceParser loadXmlResourceParser(@NonNull String file, @AnyRes int id,
+                                            int assetCookie, @NonNull String type)
+            throws NotFoundException {
+        if (id != 0) {
+            try {
+                synchronized (mCachedXmlBlocks) {
+                    final int[] cachedXmlBlockCookies = mCachedXmlBlockCookies;
+                    final String[] cachedXmlBlockFiles = mCachedXmlBlockFiles;
+                    final XmlBlock[] cachedXmlBlocks = mCachedXmlBlocks;
+                    // First see if this block is in our cache.
+                    final int num = cachedXmlBlockFiles.length;
+                    for (int i = 0; i < num; i++) {
+                        if (cachedXmlBlockCookies[i] == assetCookie && cachedXmlBlockFiles[i] != null
+                                && cachedXmlBlockFiles[i].equals(file)) {
+                            return cachedXmlBlocks[i].newParser();
+                        }
+                    }
+
+                    // Not in the cache, create a new block and put it at
+                    // the next slot in the cache.
+                    final XmlBlock block = mAssets.openXmlBlockAsset(assetCookie, file);
+                    if (block != null) {
+                        final int pos = (mLastCachedXmlBlockIndex + 1) % num;
+                        mLastCachedXmlBlockIndex = pos;
+                        final XmlBlock oldBlock = cachedXmlBlocks[pos];
+                        if (oldBlock != null) {
+                            oldBlock.close();
+                        }
+                        cachedXmlBlockCookies[pos] = assetCookie;
+                        cachedXmlBlockFiles[pos] = file;
+                        cachedXmlBlocks[pos] = block;
+                        return block.newParser();
+                    }
+                }
+            } catch (Exception e) {
+                final NotFoundException rnf = new NotFoundException("File " + file
+                        + " from xml type " + type + " resource ID #0x" + Integer.toHexString(id));
+                rnf.initCause(e);
+                throw rnf;
+            }
+        }
+
+        throw new NotFoundException("File " + file + " from xml type " + type + " resource ID #0x"
+                + Integer.toHexString(id));
+    }
+
+    /**
+     * Start preloading of resource data using this Resources object.  Only
+     * for use by the zygote process for loading common system resources.
+     * {@hide}
+     */
+    public final void startPreloading() {
+        synchronized (sSync) {
+            if (sPreloaded) {
+                throw new IllegalStateException("Resources already preloaded");
+            }
+            sPreloaded = true;
+            mPreloading = true;
+            mConfiguration.densityDpi = DisplayMetrics.DENSITY_DEVICE;
+            updateConfiguration(null, null, null);
+        }
+    }
+
+    /**
+     * Called by zygote when it is done preloading resources, to change back
+     * to normal Resources operation.
+     */
+    void finishPreloading() {
+        if (mPreloading) {
+            mPreloading = false;
+            flushLayoutCache();
+        }
+    }
+
+    LongSparseArray<Drawable.ConstantState> getPreloadedDrawables() {
+        return sPreloadedDrawables[0];
+    }
+
+    ThemeImpl newThemeImpl() {
+        return new ThemeImpl();
+    }
+
+    public class ThemeImpl {
+        /**
+         * Unique key for the series of styles applied to this theme.
+         */
+        private final Resources.ThemeKey mKey = new Resources.ThemeKey();
+
+        @SuppressWarnings("hiding")
+        private final AssetManager mAssets;
+        private final long mTheme;
+
+        /**
+         * Resource identifier for the theme.
+         */
+        private int mThemeResId = 0;
+
+        /*package*/ ThemeImpl() {
+            mAssets = ResourcesImpl.this.mAssets;
+            mTheme = mAssets.createTheme();
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            super.finalize();
+            mAssets.releaseTheme(mTheme);
+        }
+
+        /*package*/ Resources.ThemeKey getKey() {
+            return mKey;
+        }
+
+        /*package*/ long getNativeTheme() {
+            return mTheme;
+        }
+
+        /*package*/ int getAppliedStyleResId() {
+            return mThemeResId;
+        }
+
+        void applyStyle(int resId, boolean force) {
+            synchronized (mKey) {
+                AssetManager.applyThemeStyle(mTheme, resId, force);
+
+                mThemeResId = resId;
+                mKey.append(resId, force);
+            }
+        }
+
+        void setTo(ThemeImpl other) {
+            synchronized (mKey) {
+                synchronized (other.mKey) {
+                    AssetManager.copyTheme(mTheme, other.mTheme);
+
+                    mThemeResId = other.mThemeResId;
+                    mKey.setTo(other.getKey());
+                }
+            }
+        }
+
+        @NonNull
+        TypedArray obtainStyledAttributes(@NonNull Resources.Theme wrapper,
+                                          AttributeSet set,
+                                          @StyleableRes int[] attrs,
+                                          @AttrRes int defStyleAttr,
+                                          @StyleRes int defStyleRes) {
+            synchronized (mKey) {
+                final int len = attrs.length;
+                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
+
+                // XXX note that for now we only work with compiled XML files.
+                // To support generic XML files we will need to manually parse
+                // out the attributes from the XML file (applying type information
+                // contained in the resources and such).
+                final XmlBlock.Parser parser = (XmlBlock.Parser) set;
+                AssetManager.applyStyle(mTheme, defStyleAttr, defStyleRes,
+                        parser != null ? parser.mParseState : 0,
+                        attrs, array.mData, array.mIndices);
+                array.mTheme = wrapper;
+                array.mXml = parser;
+
+                return array;
+            }
+        }
+
+        @NonNull
+        TypedArray resolveAttributes(@NonNull Resources.Theme wrapper,
+                                     @NonNull int[] values,
+                                     @NonNull int[] attrs) {
+            synchronized (mKey) {
+                final int len = attrs.length;
+                if (values == null || len != values.length) {
+                    throw new IllegalArgumentException(
+                            "Base attribute values must the same length as attrs");
+                }
+
+                final TypedArray array = TypedArray.obtain(wrapper.getResources(), len);
+                AssetManager.resolveAttrs(mTheme, 0, 0, values, attrs, array.mData, array.mIndices);
+                array.mTheme = wrapper;
+                array.mXml = null;
+                return array;
+            }
+        }
+
+        boolean resolveAttribute(int resid, TypedValue outValue, boolean resolveRefs) {
+            synchronized (mKey) {
+                return mAssets.getThemeValue(mTheme, resid, outValue, resolveRefs);
+            }
+        }
+
+        int[] getAllAttributes() {
+            return mAssets.getStyleAttributes(getAppliedStyleResId());
+        }
+
+        int getChangingConfigurations() {
+            synchronized (mKey) {
+                final int nativeChangingConfig =
+                        AssetManager.getThemeChangingConfigurations(mTheme);
+                return ActivityInfo.activityInfoConfigNativeToJava(nativeChangingConfig);
+            }
+        }
+
+        public void dump(int priority, String tag, String prefix) {
+            synchronized (mKey) {
+                AssetManager.dumpTheme(mTheme, priority, tag, prefix);
+            }
+        }
+
+        String[] getTheme() {
+            synchronized (mKey) {
+                final int N = mKey.mCount;
+                final String[] themes = new String[N * 2];
+                for (int i = 0, j = N - 1; i < themes.length; i += 2, --j) {
+                    final int resId = mKey.mResId[j];
+                    final boolean forced = mKey.mForce[j];
+                    try {
+                        themes[i] = getResourceName(resId);
+                    } catch (NotFoundException e) {
+                        themes[i] = Integer.toHexString(i);
+                    }
+                    themes[i + 1] = forced ? "forced" : "not forced";
+                }
+                return themes;
+            }
+        }
+
+        /**
+         * Rebases the theme against the parent Resource object's current
+         * configuration by re-applying the styles passed to
+         * {@link #applyStyle(int, boolean)}.
+         */
+        void rebase() {
+            synchronized (mKey) {
+                AssetManager.clearTheme(mTheme);
+
+                // Reapply the same styles in the same order.
+                for (int i = 0; i < mKey.mCount; i++) {
+                    final int resId = mKey.mResId[i];
+                    final boolean force = mKey.mForce[i];
+                    AssetManager.applyThemeStyle(mTheme, resId, force);
+                }
+            }
+        }
+    }
+}
index da49b64..022bdfb 100644 (file)
@@ -1206,8 +1206,8 @@ public class TypedArray {
 
     /*package*/ TypedArray(Resources resources, int[] data, int[] indices, int len) {
         mResources = resources;
-        mMetrics = mResources.mMetrics;
-        mAssets = mResources.mAssets;
+        mMetrics = mResources.getDisplayMetrics();
+        mAssets = mResources.getAssets();
         mData = data;
         mIndices = indices;
         mLength = len;
index 6d29212..9fa1c3f 100644 (file)
@@ -60,8 +60,8 @@ public final class ConsumerIrManager {
         try {
             return mService.hasIrEmitter();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -84,7 +84,7 @@ public final class ConsumerIrManager {
         try {
             mService.transmit(mPackageName, carrierFrequency, pattern);
         } catch (RemoteException e) {
-            Log.w(TAG, "failed to transmit.", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -149,8 +149,7 @@ public final class ConsumerIrManager {
             }
             return range;
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
-
 }
diff --git a/core/java/android/hardware/ICameraService.aidl b/core/java/android/hardware/ICameraService.aidl
deleted file mode 100644 (file)
index 0b165cd..0000000
+++ /dev/null
@@ -1,89 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware;
-
-import android.hardware.ICamera;
-import android.hardware.ICameraClient;
-import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.ICameraDeviceCallbacks;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.utils.BinderHolder;
-import android.hardware.ICameraServiceListener;
-import android.hardware.CameraInfo;
-
-/**
- * Binder interface for the native camera service running in mediaserver.
- *
- * @hide
- */
-interface ICameraService
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/ICameraService.h
-     */
-    int getNumberOfCameras(int type);
-
-    // rest of 'int' return values in this file are actually status_t
-
-    int getCameraInfo(int cameraId, out CameraInfo info);
-
-    int connect(ICameraClient client, int cameraId,
-                    String opPackageName,
-                    int clientUid,
-                    // Container for an ICamera object
-                    out BinderHolder device);
-
-    int connectDevice(ICameraDeviceCallbacks callbacks, int cameraId,
-                              String opPackageName,
-                              int clientUid,
-                              // Container for an ICameraDeviceUser object
-                              out BinderHolder device);
-
-    int addListener(ICameraServiceListener listener);
-    int removeListener(ICameraServiceListener listener);
-
-    int getCameraCharacteristics(int cameraId, out CameraMetadataNative info);
-
-    /**
-     * The java stubs for this method are not intended to be used.  Please use
-     * the native stub in frameworks/av/include/camera/ICameraService.h instead.
-     * The BinderHolder output is being used as a placeholder, and will not be
-     * well-formatted in the generated java method.
-     */
-    int getCameraVendorTagDescriptor(out BinderHolder desc);
-
-    // Writes the camera1 parameters into a single-element array.
-    int getLegacyParameters(int cameraId, out String[] parameters);
-    // Determines if a particular API version is supported; see ICameraService.h for version defines
-    int supportsCameraApi(int cameraId, int apiVersion);
-
-    int connectLegacy(ICameraClient client, int cameraId,
-                    int halVersion,
-                    String opPackageName,
-                    int clientUid,
-                    // Container for an ICamera object
-                    out BinderHolder device);
-
-    int setTorchMode(String CameraId, boolean enabled, IBinder clientBinder);
-
-    /**
-     * Notify the camera service of a system event.  Should only be called from system_server.
-     *
-     * Callers require the android.permission.CAMERA_SEND_SYSTEM_EVENTS permission.
-     */
-    oneway void notifySystemEvent(int eventId, in int[] args);
-}
index 0d859fb..0c059ba 100644 (file)
@@ -18,28 +18,33 @@ package android.hardware;
 
 /**
  * Used for receiving notifications from the SensorManager when
- * sensor values have changed.
+ * there is new sensor data.
  */
 public interface SensorEventListener {
 
     /**
-     * Called when sensor values have changed.
+     * Called when there is a new sensor event.  Note that "on changed"
+     * is somewhat of a misnomer, as this will also be called if we have a
+     * new reading from a sensor with the exact same sensor values (but a
+     * newer timestamp).
+     *
      * <p>See {@link android.hardware.SensorManager SensorManager}
      * for details on possible sensor types.
      * <p>See also {@link android.hardware.SensorEvent SensorEvent}.
-     * 
+     *
      * <p><b>NOTE:</b> The application doesn't own the
      * {@link android.hardware.SensorEvent event}
      * object passed as a parameter and therefore cannot hold on to it.
      * The object may be part of an internal pool and may be reused by
      * the framework.
      *
-     * @param event the {@link android.hardware.SensorEvent SensorEvent}. 
+     * @param event the {@link android.hardware.SensorEvent SensorEvent}.
      */
     public void onSensorChanged(SensorEvent event);
 
     /**
-     * Called when the accuracy of the registered sensor has changed.
+     * Called when the accuracy of the registered sensor has changed.  Unlike
+     * onSensorChanged(), this is only called when this accuracy value changes.
      *
      * <p>See the SENSOR_STATUS_* constants in
      * {@link android.hardware.SensorManager SensorManager} for details.
index f0b17c3..5684aa5 100644 (file)
@@ -46,7 +46,7 @@ import java.util.List;
  * is an example of a trigger sensor.
  * </p>
  * <pre class="prettyprint">
- * public class SensorActivity extends Activity, implements SensorEventListener {
+ * public class SensorActivity extends Activity implements SensorEventListener {
  *     private final SensorManager mSensorManager;
  *     private final Sensor mAccelerometer;
  *
index e0680bf..83f7649 100644 (file)
  * limitations under the License.
  */
 
-
 package android.hardware;
 
 import android.content.Context;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteException;
-import android.util.Log;
 
 import java.io.IOException;
 
@@ -50,8 +48,7 @@ public class SerialManager {
         try {
             return mService.getSerialPorts();
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getSerialPorts", e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -77,8 +74,7 @@ public class SerialManager {
                 throw new IOException("Could not open serial port " + name);
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "exception in UsbManager.openDevice", e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 }
index 933ce0d..f9b659c 100644 (file)
@@ -114,12 +114,12 @@ public class CameraAccessException extends AndroidException {
     }
 
     public CameraAccessException(@AccessError int problem, String message) {
-        super(message);
+        super(getCombinedMessage(problem, message));
         mReason = problem;
     }
 
     public CameraAccessException(@AccessError int problem, String message, Throwable cause) {
-        super(message, cause);
+        super(getCombinedMessage(problem, message), cause);
         mReason = problem;
     }
 
@@ -151,4 +151,37 @@ public class CameraAccessException extends AndroidException {
         }
         return null;
     }
+
+    private static String getCombinedMessage(@AccessError int problem, String message) {
+        String problemString = getProblemString(problem);
+        return String.format("%s (%d): %s", problemString, problem, message);
+    }
+
+    private static String getProblemString(int problem) {
+        String problemString;
+        switch (problem) {
+            case CAMERA_IN_USE:
+                problemString = "CAMERA_IN_USE";
+                break;
+            case MAX_CAMERAS_IN_USE:
+                problemString = "MAX_CAMERAS_IN_USE";
+                break;
+            case CAMERA_DISCONNECTED:
+                problemString = "CAMERA_DISCONNECTED";
+                break;
+            case CAMERA_DISABLED:
+                problemString = "CAMERA_DISABLED";
+                break;
+            case CAMERA_ERROR:
+                problemString = "CAMERA_ERROR";
+                break;
+            case CAMERA_DEPRECATED_HAL:
+                problemString = "CAMERA_DEPRECATED_HAL";
+                break;
+            default:
+                problemString = "<UNKNOWN ERROR>";
+        }
+        return problemString;
+    }
+
 }
index 51796eb..b3c8e3b 100644 (file)
@@ -26,15 +26,14 @@ import android.hardware.CameraInfo;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.legacy.CameraDeviceUserShim;
 import android.hardware.camera2.legacy.LegacyMetadataMapper;
-import android.hardware.camera2.utils.CameraServiceBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.hardware.camera2.utils.BinderHolder;
 import android.os.IBinder;
 import android.os.Binder;
+import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.ArrayMap;
 
@@ -240,25 +239,19 @@ public final class CameraManager {
                 if (!supportsCamera2ApiLocked(cameraId)) {
                     // Legacy backwards compatibility path; build static info from the camera
                     // parameters
-                    String[] outParameters = new String[1];
+                    String parameters = cameraService.getLegacyParameters(id);
 
-                    cameraService.getLegacyParameters(id, /*out*/outParameters);
-                    String parameters = outParameters[0];
-
-                    CameraInfo info = new CameraInfo();
-                    cameraService.getCameraInfo(id, /*out*/info);
+                    CameraInfo info = cameraService.getCameraInfo(id);
 
                     characteristics = LegacyMetadataMapper.createCharacteristics(parameters, info);
                 } else {
                     // Normal path: Get the camera characteristics directly from the camera service
-                    CameraMetadataNative info = new CameraMetadataNative();
-
-                    cameraService.getCameraCharacteristics(id, info);
+                    CameraMetadataNative info = cameraService.getCameraCharacteristics(id);
 
                     characteristics = new CameraCharacteristics(info);
                 }
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
+            } catch (ServiceSpecificException e) {
+                throwAsPublicException(e);
             } catch (RemoteException e) {
                 // Camera service died - act as if the camera was disconnected
                 throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
@@ -292,85 +285,83 @@ public final class CameraManager {
             throws CameraAccessException {
         CameraCharacteristics characteristics = getCameraCharacteristics(cameraId);
         CameraDevice device = null;
-        try {
 
-            synchronized (mLock) {
+        synchronized (mLock) {
 
-                ICameraDeviceUser cameraUser = null;
+            ICameraDeviceUser cameraUser = null;
 
-                android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
-                        new android.hardware.camera2.impl.CameraDeviceImpl(
-                                cameraId,
-                                callback,
-                                handler,
-                                characteristics);
+            android.hardware.camera2.impl.CameraDeviceImpl deviceImpl =
+                    new android.hardware.camera2.impl.CameraDeviceImpl(
+                        cameraId,
+                        callback,
+                        handler,
+                        characteristics);
 
-                BinderHolder holder = new BinderHolder();
+            ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
 
-                ICameraDeviceCallbacks callbacks = deviceImpl.getCallbacks();
-                int id = Integer.parseInt(cameraId);
-                try {
-                    if (supportsCamera2ApiLocked(cameraId)) {
-                        // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
-                        ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
-                        if (cameraService == null) {
-                            throw new CameraRuntimeException(
-                                CameraAccessException.CAMERA_DISCONNECTED,
-                                "Camera service is currently unavailable");
-                        }
-                        cameraService.connectDevice(callbacks, id,
-                                mContext.getOpPackageName(), USE_CALLING_UID, holder);
-                        cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
-                    } else {
-                        // Use legacy camera implementation for HAL1 devices
-                        Log.i(TAG, "Using legacy camera HAL.");
-                        cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
+            int id;
+            try {
+                id = Integer.parseInt(cameraId);
+            } catch (NumberFormatException e) {
+                throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
+                        + cameraId);
+            }
+
+            try {
+                if (supportsCamera2ApiLocked(cameraId)) {
+                    // Use cameraservice's cameradeviceclient implementation for HAL3.2+ devices
+                    ICameraService cameraService = CameraManagerGlobal.get().getCameraService();
+                    if (cameraService == null) {
+                        throw new ServiceSpecificException(
+                            ICameraService.ERROR_DISCONNECTED,
+                            "Camera service is currently unavailable");
                     }
-                } catch (CameraRuntimeException e) {
-                    if (e.getReason() == CameraAccessException.CAMERA_DEPRECATED_HAL) {
-                        throw new AssertionError("Should've gone down the shim path");
-                    } else if (e.getReason() == CameraAccessException.CAMERA_IN_USE ||
-                            e.getReason() == CameraAccessException.MAX_CAMERAS_IN_USE ||
-                            e.getReason() == CameraAccessException.CAMERA_DISABLED ||
-                            e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
-                            e.getReason() == CameraAccessException.CAMERA_ERROR) {
-                        // Received one of the known connection errors
-                        // The remote camera device cannot be connected to, so
-                        // set the local camera to the startup error state
-                        deviceImpl.setRemoteFailure(e);
-
-                        if (e.getReason() == CameraAccessException.CAMERA_DISABLED ||
-                                e.getReason() == CameraAccessException.CAMERA_DISCONNECTED ||
-                                e.getReason() == CameraAccessException.CAMERA_IN_USE) {
-                            // Per API docs, these failures call onError and throw
-                            throw e.asChecked();
-                        }
-                    } else {
-                        // Unexpected failure - rethrow
-                        throw e;
+                    cameraUser = cameraService.connectDevice(callbacks, id,
+                            mContext.getOpPackageName(), USE_CALLING_UID);
+                } else {
+                    // Use legacy camera implementation for HAL1 devices
+                    Log.i(TAG, "Using legacy camera HAL.");
+                    cameraUser = CameraDeviceUserShim.connectBinderShim(callbacks, id);
+                }
+            } catch (ServiceSpecificException e) {
+                if (e.errorCode == ICameraService.ERROR_DEPRECATED_HAL) {
+                    throw new AssertionError("Should've gone down the shim path");
+                } else if (e.errorCode == ICameraService.ERROR_CAMERA_IN_USE ||
+                        e.errorCode == ICameraService.ERROR_MAX_CAMERAS_IN_USE ||
+                        e.errorCode == ICameraService.ERROR_DISABLED ||
+                        e.errorCode == ICameraService.ERROR_DISCONNECTED ||
+                        e.errorCode == ICameraService.ERROR_INVALID_OPERATION) {
+                    // Received one of the known connection errors
+                    // The remote camera device cannot be connected to, so
+                    // set the local camera to the startup error state
+                    deviceImpl.setRemoteFailure(e);
+
+                    if (e.errorCode == ICameraService.ERROR_DISABLED ||
+                            e.errorCode == ICameraService.ERROR_DISCONNECTED ||
+                            e.errorCode == ICameraService.ERROR_CAMERA_IN_USE) {
+                        // Per API docs, these failures call onError and throw
+                        throwAsPublicException(e);
                     }
-                } catch (RemoteException e) {
-                    // Camera service died - act as if it's a CAMERA_DISCONNECTED case
-                    CameraRuntimeException ce = new CameraRuntimeException(
-                        CameraAccessException.CAMERA_DISCONNECTED,
-                        "Camera service is currently unavailable", e);
-                    deviceImpl.setRemoteFailure(ce);
-                    throw ce.asChecked();
+                } else {
+                    // Unexpected failure - rethrow
+                    throwAsPublicException(e);
                 }
-
-                // TODO: factor out callback to be non-nested, then move setter to constructor
-                // For now, calling setRemoteDevice will fire initial
-                // onOpened/onUnconfigured callbacks.
-                deviceImpl.setRemoteDevice(cameraUser);
-                device = deviceImpl;
+            } catch (RemoteException e) {
+                // Camera service died - act as if it's a CAMERA_DISCONNECTED case
+                ServiceSpecificException sse = new ServiceSpecificException(
+                    ICameraService.ERROR_DISCONNECTED,
+                    "Camera service is currently unavailable");
+                deviceImpl.setRemoteFailure(sse);
+                throwAsPublicException(sse);
             }
 
-        } catch (NumberFormatException e) {
-            throw new IllegalArgumentException("Expected cameraId to be numeric, but it was: "
-                    + cameraId);
-        } catch (CameraRuntimeException e) {
-            throw e.asChecked();
+            // TODO: factor out callback to be non-nested, then move setter to constructor
+            // For now, calling setRemoteDevice will fire initial
+            // onOpened/onUnconfigured callbacks.
+            deviceImpl.setRemoteDevice(cameraUser);
+            device = deviceImpl;
         }
+
         return device;
     }
 
@@ -602,6 +593,56 @@ public final class CameraManager {
     }
 
     /**
+     * Convert ServiceSpecificExceptions and Binder RemoteExceptions from camera binder interfaces
+     * into the correct public exceptions.
+     *
+     * @hide
+     */
+    public static void throwAsPublicException(Throwable t) throws CameraAccessException {
+        if (t instanceof ServiceSpecificException) {
+            ServiceSpecificException e = (ServiceSpecificException) t;
+            int reason = CameraAccessException.CAMERA_ERROR;
+            switch(e.errorCode) {
+                case ICameraService.ERROR_DISCONNECTED:
+                    reason = CameraAccessException.CAMERA_DISCONNECTED;
+                    break;
+                case ICameraService.ERROR_DISABLED:
+                    reason = CameraAccessException.CAMERA_DISABLED;
+                    break;
+                case ICameraService.ERROR_CAMERA_IN_USE:
+                    reason = CameraAccessException.CAMERA_IN_USE;
+                    break;
+                case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
+                    reason = CameraAccessException.MAX_CAMERAS_IN_USE;
+                    break;
+                case ICameraService.ERROR_DEPRECATED_HAL:
+                    reason = CameraAccessException.CAMERA_DEPRECATED_HAL;
+                    break;
+                case ICameraService.ERROR_ILLEGAL_ARGUMENT:
+                case ICameraService.ERROR_ALREADY_EXISTS:
+                    throw new IllegalArgumentException(e.getMessage(), e);
+                case ICameraService.ERROR_PERMISSION_DENIED:
+                    throw new SecurityException(e.getMessage(), e);
+                case ICameraService.ERROR_TIMED_OUT:
+                case ICameraService.ERROR_INVALID_OPERATION:
+                default:
+                    reason = CameraAccessException.CAMERA_ERROR;
+            }
+            throw new CameraAccessException(reason, e.getMessage(), e);
+        } else if (t instanceof DeadObjectException) {
+            throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
+                    "Camera service has died unexpectedly",
+                    t);
+        } else if (t instanceof RemoteException) {
+            throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
+                    " which should never happen.", t);
+        } else if (t instanceof RuntimeException) {
+            RuntimeException e = (RuntimeException) t;
+            throw e;
+        }
+    }
+
+    /**
      * Return or create the list of currently connected camera devices.
      *
      * <p>In case of errors connecting to the camera service, will return an empty list.</p>
@@ -619,34 +660,32 @@ public final class CameraManager {
 
             try {
                 numCameras = cameraService.getNumberOfCameras(CAMERA_TYPE_ALL);
-            } catch(CameraRuntimeException e) {
-                throw e.asChecked();
+            } catch(ServiceSpecificException e) {
+                throwAsPublicException(e);
             } catch (RemoteException e) {
                 // camera service just died - if no camera service, then no devices
                 return deviceIdList;
             }
 
-            CameraMetadataNative info = new CameraMetadataNative();
             for (int i = 0; i < numCameras; ++i) {
                 // Non-removable cameras use integers starting at 0 for their
                 // identifiers
                 boolean isDeviceSupported = false;
                 try {
-                    cameraService.getCameraCharacteristics(i, info);
+                    CameraMetadataNative info = cameraService.getCameraCharacteristics(i);
                     if (!info.isEmpty()) {
                         isDeviceSupported = true;
                     } else {
                         throw new AssertionError("Expected to get non-empty characteristics");
                     }
-                } catch(IllegalArgumentException  e) {
-                    // Got a BAD_VALUE from service, meaning that this
-                    // device is not supported.
-                } catch(CameraRuntimeException e) {
+                } catch(ServiceSpecificException e) {
                     // DISCONNECTED means that the HAL reported an low-level error getting the
-                    // device info; skip listing the device.  Other errors,
+                    // device info; ILLEGAL_ARGUMENT means that this devices is not supported.
+                    // Skip listing the device.  Other errors,
                     // propagate exception onward
-                    if (e.getReason() != CameraAccessException.CAMERA_DISCONNECTED) {
-                        throw e.asChecked();
+                    if (e.errorCode != ICameraService.ERROR_DISCONNECTED ||
+                            e.errorCode != ICameraService.ERROR_ILLEGAL_ARGUMENT) {
+                        throwAsPublicException(e);
                     }
                 } catch(RemoteException e) {
                     // Camera service died - no devices to list
@@ -699,17 +738,7 @@ public final class CameraManager {
             // If no camera service, no support
             if (cameraService == null) return false;
 
-            int res = cameraService.supportsCameraApi(id, apiVersion);
-
-            if (res != CameraServiceBinderDecorator.NO_ERROR) {
-                throw new AssertionError("Unexpected value " + res);
-            }
-            return true;
-        } catch (CameraRuntimeException e) {
-            if (e.getReason() != CameraAccessException.CAMERA_DEPRECATED_HAL) {
-                throw e;
-            }
-            // API level is not supported
+            return cameraService.supportsCameraApi(id, apiVersion);
         } catch (RemoteException e) {
             // Camera service is now down, no support for any API level
         }
@@ -737,21 +766,6 @@ public final class CameraManager {
          */
         private static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
 
-        // Keep up-to-date with ICameraServiceListener.h
-
-        // Device physically unplugged
-        public static final int STATUS_NOT_PRESENT = 0;
-        // Device physically has been plugged in
-        // and the camera can be used exclusively
-        public static final int STATUS_PRESENT = 1;
-        // Device physically has been plugged in
-        // but it will not be connect-able until enumeration is complete
-        public static final int STATUS_ENUMERATING = 2;
-        // Camera is in use by another app and cannot be used exclusively
-        public static final int STATUS_NOT_AVAILABLE = 0x80000000;
-
-        // End enums shared with ICameraServiceListener.h
-
         // Camera ID -> Status map
         private final ArrayMap<String, Integer> mDeviceStatus = new ArrayMap<String, Integer>();
 
@@ -759,17 +773,6 @@ public final class CameraManager {
         private final ArrayMap<AvailabilityCallback, Handler> mCallbackMap =
             new ArrayMap<AvailabilityCallback, Handler>();
 
-        // Keep up-to-date with ICameraServiceListener.h
-
-        // torch mode has become not available to set via setTorchMode().
-        public static final int TORCH_STATUS_NOT_AVAILABLE = 0;
-        // torch mode is off and available to be turned on via setTorchMode().
-        public static final int TORCH_STATUS_AVAILABLE_OFF = 1;
-        // torch mode is on and available to be turned off via setTorchMode().
-        public static final int TORCH_STATUS_AVAILABLE_ON = 2;
-
-        // End enums shared with ICameraServiceListener.h
-
         // torch client binder to set the torch mode with.
         private Binder mTorchClientBinder = new Binder();
 
@@ -839,29 +842,20 @@ public final class CameraManager {
                 return;
             }
 
-            ICameraService cameraServiceRaw = ICameraService.Stub.asInterface(cameraServiceBinder);
-
-            /**
-             * Wrap the camera service in a decorator which automatically translates return codes
-             * into exceptions.
-             */
-            ICameraService cameraService =
-                CameraServiceBinderDecorator.newInstance(cameraServiceRaw);
+            ICameraService cameraService = ICameraService.Stub.asInterface(cameraServiceBinder);
 
             try {
-                CameraServiceBinderDecorator.throwOnError(
-                        CameraMetadataNative.nativeSetupGlobalVendorTagDescriptor());
-            } catch (CameraRuntimeException e) {
-                handleRecoverableSetupErrors(e, "Failed to set up vendor tags");
+                CameraMetadataNative.setupGlobalVendorTagDescriptor();
+            } catch (ServiceSpecificException e) {
+                handleRecoverableSetupErrors(e);
             }
 
             try {
                 cameraService.addListener(this);
                 mCameraService = cameraService;
-            } catch(CameraRuntimeException e) {
+            } catch(ServiceSpecificException e) {
                 // Unexpected failure
-                throw new IllegalStateException("Failed to register a camera service listener",
-                        e.asChecked());
+                throw new IllegalStateException("Failed to register a camera service listener", e);
             } catch (RemoteException e) {
                 // Camera service is now down, leave mCameraService as null
             }
@@ -881,16 +875,9 @@ public final class CameraManager {
                 }
 
                 try {
-                    int status = cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
-                } catch(CameraRuntimeException e) {
-                    int problem = e.getReason();
-                    switch (problem) {
-                        case CameraAccessException.CAMERA_ERROR:
-                            throw new IllegalArgumentException(
-                                    "the camera device doesn't have a flash unit.");
-                        default:
-                            throw e.asChecked();
-                    }
+                    cameraService.setTorchMode(cameraId, enabled, mTorchClientBinder);
+                } catch(ServiceSpecificException e) {
+                    throwAsPublicException(e);
                 } catch (RemoteException e) {
                     throw new CameraAccessException(CameraAccessException.CAMERA_DISCONNECTED,
                             "Camera service is currently unavailable");
@@ -898,21 +885,19 @@ public final class CameraManager {
             }
         }
 
-        private void handleRecoverableSetupErrors(CameraRuntimeException e, String msg) {
-            int problem = e.getReason();
-            switch (problem) {
-                case CameraAccessException.CAMERA_DISCONNECTED:
-                    String errorMsg = CameraAccessException.getDefaultMessage(problem);
-                    Log.w(TAG, msg + ": " + errorMsg);
+        private void handleRecoverableSetupErrors(ServiceSpecificException e) {
+            switch (e.errorCode) {
+                case ICameraService.ERROR_DISCONNECTED:
+                    Log.w(TAG, e.getMessage());
                     break;
                 default:
-                    throw new IllegalStateException(msg, e.asChecked());
+                    throw new IllegalStateException(e);
             }
         }
 
         private boolean isAvailable(int status) {
             switch (status) {
-                case STATUS_PRESENT:
+                case ICameraServiceListener.STATUS_PRESENT:
                     return true;
                 default:
                     return false;
@@ -921,10 +906,10 @@ public final class CameraManager {
 
         private boolean validStatus(int status) {
             switch (status) {
-                case STATUS_NOT_PRESENT:
-                case STATUS_PRESENT:
-                case STATUS_ENUMERATING:
-                case STATUS_NOT_AVAILABLE:
+                case ICameraServiceListener.STATUS_NOT_PRESENT:
+                case ICameraServiceListener.STATUS_PRESENT:
+                case ICameraServiceListener.STATUS_ENUMERATING:
+                case ICameraServiceListener.STATUS_NOT_AVAILABLE:
                     return true;
                 default:
                     return false;
@@ -933,9 +918,9 @@ public final class CameraManager {
 
         private boolean validTorchStatus(int status) {
             switch (status) {
-                case TORCH_STATUS_NOT_AVAILABLE:
-                case TORCH_STATUS_AVAILABLE_ON:
-                case TORCH_STATUS_AVAILABLE_OFF:
+                case ICameraServiceListener.TORCH_STATUS_NOT_AVAILABLE:
+                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
+                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF:
                     return true;
                 default:
                     return false;
@@ -966,14 +951,14 @@ public final class CameraManager {
         private void postSingleTorchUpdate(final TorchCallback callback, final Handler handler,
                 final String id, final int status) {
             switch(status) {
-                case TORCH_STATUS_AVAILABLE_ON:
-                case TORCH_STATUS_AVAILABLE_OFF:
+                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON:
+                case ICameraServiceListener.TORCH_STATUS_AVAILABLE_OFF:
                     handler.post(
                             new Runnable() {
                                 @Override
                                 public void run() {
                                     callback.onTorchModeChanged(id, status ==
-                                            TORCH_STATUS_AVAILABLE_ON);
+                                            ICameraServiceListener.TORCH_STATUS_AVAILABLE_ON);
                                 }
                             });
                     break;
@@ -1220,11 +1205,12 @@ public final class CameraManager {
                 // and torch statuses will be updated.
                 for (int i = 0; i < mDeviceStatus.size(); i++) {
                     String cameraId = mDeviceStatus.keyAt(i);
-                    onStatusChangedLocked(STATUS_NOT_PRESENT, cameraId);
+                    onStatusChangedLocked(ICameraServiceListener.STATUS_NOT_PRESENT, cameraId);
                 }
                 for (int i = 0; i < mTorchStatus.size(); i++) {
                     String cameraId = mTorchStatus.keyAt(i);
-                    onTorchStatusChangedLocked(TORCH_STATUS_NOT_AVAILABLE, cameraId);
+                    onTorchStatusChangedLocked(ICameraServiceListener.TORCH_STATUS_NOT_AVAILABLE,
+                            cameraId);
                 }
 
                 scheduleCameraServiceReconnectionLocked();
index 57a080b..9478dc0 100644 (file)
@@ -137,6 +137,11 @@ public final class DngCreator implements AutoCloseable {
             throw new IllegalArgumentException("Orientation " + orientation +
                     " is not a valid EXIF orientation value");
         }
+        // ExifInterface and TIFF/EP spec differ on definition of
+        // "Unknown" orientation; other values map directly
+        if (orientation == ExifInterface.ORIENTATION_UNDEFINED) {
+            orientation = TAG_ORIENTATION_UNKNOWN;
+        }
         nativeSetOrientation(orientation);
         return this;
     }
@@ -443,7 +448,7 @@ public final class DngCreator implements AutoCloseable {
     private static final String GPS_LONG_REF_WEST = "W";
 
     private static final String GPS_DATE_FORMAT_STR = "yyyy:MM:dd";
-    private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd kk:mm:ss";
+    private static final String TIFF_DATETIME_FORMAT = "yyyy:MM:dd HH:mm:ss";
     private static final DateFormat sExifGPSDateStamp = new SimpleDateFormat(GPS_DATE_FORMAT_STR);
     private static final DateFormat sDateTimeStampFormat =
             new SimpleDateFormat(TIFF_DATETIME_FORMAT);
@@ -458,6 +463,9 @@ public final class DngCreator implements AutoCloseable {
     private static final int DEFAULT_PIXEL_STRIDE = 2; // bytes per sample
     private static final int BYTES_PER_RGB_PIX = 3; // byts per pixel
 
+    // TIFF tag values needed to map between public API and TIFF spec
+    private static final int TAG_ORIENTATION_UNKNOWN = 9;
+
     /**
      * Offset, rowStride, and pixelStride are given in bytes.  Height and width are given in pixels.
      */
diff --git a/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl b/core/java/android/hardware/camera2/ICameraDeviceCallbacks.aidl
deleted file mode 100644 (file)
index 151c918..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.impl.CaptureResultExtras;
-
-/** @hide */
-interface ICameraDeviceCallbacks
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceCallbacks.h
-     */
-
-    oneway void onDeviceError(int errorCode, in CaptureResultExtras resultExtras);
-    oneway void onDeviceIdle();
-    oneway void onCaptureStarted(in CaptureResultExtras resultExtras, long timestamp);
-    oneway void onResultReceived(in CameraMetadataNative result,
-                                 in CaptureResultExtras resultExtras);
-    oneway void onPrepared(int streamId);
-}
diff --git a/core/java/android/hardware/camera2/ICameraDeviceUser.aidl b/core/java/android/hardware/camera2/ICameraDeviceUser.aidl
deleted file mode 100644 (file)
index c9c9abc..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2;
-
-import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.utils.LongParcelable;
-import android.view.Surface;
-
-/** @hide */
-interface ICameraDeviceUser
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/camera2/ICameraDeviceUser.h and
-     * frameworks/base/core/java/android/hardware/camera2/legacy/CameraDeviceUserShim.java
-     */
-    void disconnect();
-
-    // ints here are status_t
-
-    // non-negative value is the requestId. negative value is status_t
-    int submitRequest(in CaptureRequest request, boolean streaming,
-                      out LongParcelable lastFrameNumber);
-
-    int submitRequestList(in List<CaptureRequest> requestList, boolean streaming,
-                          out LongParcelable lastFrameNumber);
-
-    int cancelRequest(int requestId, out LongParcelable lastFrameNumber);
-
-    /**
-     * Begin the device configuration.
-     *
-     * <p>
-     * beginConfigure must be called before any call to deleteStream, createStream,
-     * or endConfigure.  It is not valid to call this when the device is not idle.
-     * <p>
-     */
-    int beginConfigure();
-
-    /**
-     * End the device configuration.
-     *
-     * <p>
-     * endConfigure must be called after stream configuration is complete (i.e. after
-     * a call to beginConfigure and subsequent createStream/deleteStream calls).  This
-     * must be called before any requests can be submitted.
-     * <p>
-     */
-    int endConfigure(boolean isConstrainedHighSpeed);
-
-    int deleteStream(int streamId);
-
-    // non-negative value is the stream ID. negative value is status_t
-    int createStream(in OutputConfiguration outputConfiguration);
-
-    /**
-     * Create an input stream
-     *
-     * <p>Create an input stream of width, height, and format</p>
-     *
-     * @param width Width of the input buffers
-     * @param height Height of the input buffers
-     * @param format Format of the input buffers. One of HAL_PIXEL_FORMAT_*.
-     *
-     * @return stream ID if it's a non-negative value. status_t if it's a negative value.
-     */
-    int createInputStream(int width, int height, int format);
-
-    /**
-     * Get the surface of the input stream.
-     *
-     * <p>It's valid to call this method only after a stream configuration is completed
-     * successfully and the stream configuration includes a input stream.</p>
-     *
-     * @param surface An output argument for the surface of the input stream buffer queue.
-     */
-    int getInputSurface(out Surface surface);
-
-    int createDefaultRequest(int templateId, out CameraMetadataNative request);
-
-    int getCameraInfo(out CameraMetadataNative info);
-
-    int waitUntilIdle();
-
-    int flush(out LongParcelable lastFrameNumber);
-
-    int prepare(int streamId);
-
-    int tearDown(int streamId);
-
-    int prepare2(int maxCount, int streamId);
-}
index 3aba0d1..00dd780 100644 (file)
@@ -33,14 +33,14 @@ import android.hardware.camera2.params.InputConfiguration;
 import android.hardware.camera2.params.OutputConfiguration;
 import android.hardware.camera2.params.ReprocessFormatsMap;
 import android.hardware.camera2.params.StreamConfigurationMap;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.hardware.camera2.utils.SurfaceUtils;
+import android.hardware.ICameraService;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.Range;
 import android.util.Size;
@@ -70,7 +70,7 @@ public class CameraDeviceImpl extends CameraDevice {
     private static final int REQUEST_ID_NONE = -1;
 
     // TODO: guard every function with if (!mRemoteDevice) check (if it was closed)
-    private ICameraDeviceUser mRemoteDevice;
+    private ICameraDeviceUserWrapper mRemoteDevice;
 
     // Lock to synchronize cross-thread access to device public interface
     final Object mInterfaceLock = new Object(); // access from this class and Session only!
@@ -267,7 +267,7 @@ public class CameraDeviceImpl extends CameraDevice {
             // If setRemoteFailure already called, do nothing
             if (mInError) return;
 
-            mRemoteDevice = CameraBinderDecorator.newInstance(remoteDevice);
+            mRemoteDevice = new ICameraDeviceUserWrapper(remoteDevice);
 
             mDeviceHandler.post(mCallOnOpened);
             mDeviceHandler.post(mCallOnUnconfigured);
@@ -280,28 +280,29 @@ public class CameraDeviceImpl extends CameraDevice {
      * <p>This places the camera device in the error state and informs the callback.
      * Use in place of setRemoteDevice() when startup fails.</p>
      */
-    public void setRemoteFailure(final CameraRuntimeException failure) {
+    public void setRemoteFailure(final ServiceSpecificException failure) {
         int failureCode = StateCallback.ERROR_CAMERA_DEVICE;
         boolean failureIsError = true;
 
-        switch (failure.getReason()) {
-            case CameraAccessException.CAMERA_IN_USE:
+        switch (failure.errorCode) {
+            case ICameraService.ERROR_CAMERA_IN_USE:
                 failureCode = StateCallback.ERROR_CAMERA_IN_USE;
                 break;
-            case CameraAccessException.MAX_CAMERAS_IN_USE:
+            case ICameraService.ERROR_MAX_CAMERAS_IN_USE:
                 failureCode = StateCallback.ERROR_MAX_CAMERAS_IN_USE;
                 break;
-            case CameraAccessException.CAMERA_DISABLED:
+            case ICameraService.ERROR_DISABLED:
                 failureCode = StateCallback.ERROR_CAMERA_DISABLED;
                 break;
-            case CameraAccessException.CAMERA_DISCONNECTED:
+            case ICameraService.ERROR_DISCONNECTED:
                 failureIsError = false;
                 break;
-            case CameraAccessException.CAMERA_ERROR:
+            case ICameraService.ERROR_INVALID_OPERATION:
                 failureCode = StateCallback.ERROR_CAMERA_DEVICE;
                 break;
             default:
-                Log.wtf(TAG, "Unknown failure in opening camera device: " + failure.getReason());
+                Log.e(TAG, "Unexpected failure in opening camera device: " + failure.errorCode +
+                        failure.getMessage());
                 break;
         }
         final int code = failureCode;
@@ -430,27 +431,20 @@ public class CameraDeviceImpl extends CameraDevice {
                     }
                 }
 
-                try {
-                    mRemoteDevice.endConfigure(isConstrainedHighSpeed);
-                }
-                catch (IllegalArgumentException e) {
-                    // OK. camera service can reject stream config if it's not supported by HAL
-                    // This is only the result of a programmer misusing the camera2 api.
-                    Log.w(TAG, "Stream configuration failed");
-                    return false;
-                }
+                mRemoteDevice.endConfigure(isConstrainedHighSpeed);
 
                 success = true;
-            } catch (CameraRuntimeException e) {
-                if (e.getReason() == CAMERA_IN_USE) {
+            } catch (IllegalArgumentException e) {
+                // OK. camera service can reject stream config if it's not supported by HAL
+                // This is only the result of a programmer misusing the camera2 api.
+                Log.w(TAG, "Stream configuration failed due to: " + e.getMessage());
+                return false;
+            } catch (CameraAccessException e) {
+                if (e.getReason() == CameraAccessException.CAMERA_IN_USE) {
                     throw new IllegalStateException("The camera is currently busy." +
-                            " You must wait until the previous operation completes.");
+                            " You must wait until the previous operation completes.", e);
                 }
-
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return false;
+                throw e;
             } finally {
                 if (success && outputs.size() > 0) {
                     mDeviceHandler.post(mCallOnIdle);
@@ -594,12 +588,7 @@ public class CameraDeviceImpl extends CameraDevice {
                 configureSuccess = configureStreamsChecked(inputConfig, outputConfigurations,
                         isConstrainedHighSpeed);
                 if (configureSuccess == true && inputConfig != null) {
-                    input = new Surface();
-                    try {
-                        mRemoteDevice.getInputSurface(/*out*/input);
-                    } catch (CameraRuntimeException e) {
-                        e.asChecked();
-                    }
+                    input = mRemoteDevice.getInputSurface();
                 }
             } catch (CameraAccessException e) {
                 configureSuccess = false;
@@ -608,9 +597,6 @@ public class CameraDeviceImpl extends CameraDevice {
                 if (DEBUG) {
                     Log.v(TAG, "createCaptureSession - failed with exception ", e);
                 }
-            } catch (RemoteException e) {
-                // impossible
-                return;
             }
 
             List<Surface> outSurfaces = new ArrayList<>(outputConfigurations.size());
@@ -655,16 +641,9 @@ public class CameraDeviceImpl extends CameraDevice {
         synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
 
-            CameraMetadataNative templatedRequest = new CameraMetadataNative();
+            CameraMetadataNative templatedRequest = null;
 
-            try {
-                mRemoteDevice.createDefaultRequest(templateType, /*out*/templatedRequest);
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return null;
-            }
+            templatedRequest = mRemoteDevice.createDefaultRequest(templateType);
 
             CaptureRequest.Builder builder = new CaptureRequest.Builder(
                     templatedRequest, /*reprocess*/false, CameraCaptureSession.SESSION_ID_NONE);
@@ -701,14 +680,8 @@ public class CameraDeviceImpl extends CameraDevice {
             if (streamId == -1) {
                 throw new IllegalArgumentException("Surface is not part of this session");
             }
-            try {
-                mRemoteDevice.prepare(streamId);
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return;
-            }
+
+            mRemoteDevice.prepare(streamId);
         }
     }
 
@@ -728,14 +701,8 @@ public class CameraDeviceImpl extends CameraDevice {
             if (streamId == -1) {
                 throw new IllegalArgumentException("Surface is not part of this session");
             }
-            try {
-                mRemoteDevice.prepare2(maxCount, streamId);
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return;
-            }
+
+            mRemoteDevice.prepare2(maxCount, streamId);
         }
     }
 
@@ -753,14 +720,8 @@ public class CameraDeviceImpl extends CameraDevice {
             if (streamId == -1) {
                 throw new IllegalArgumentException("Surface is not part of this session");
             }
-            try {
-                mRemoteDevice.tearDown(streamId);
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return;
-            }
+
+            mRemoteDevice.tearDown(streamId);
         }
     }
 
@@ -875,45 +836,37 @@ public class CameraDeviceImpl extends CameraDevice {
 
         synchronized(mInterfaceLock) {
             checkIfCameraClosedOrInError();
-            int requestId;
-
             if (repeating) {
                 stopRepeating();
             }
 
-            LongParcelable lastFrameNumberRef = new LongParcelable();
-            try {
-                requestId = mRemoteDevice.submitRequestList(requestList, repeating,
-                        /*out*/lastFrameNumberRef);
-                if (DEBUG) {
-                    Log.v(TAG, "last frame number " + lastFrameNumberRef.getNumber());
-                }
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return -1;
+            SubmitInfo requestInfo;
+
+            CaptureRequest[] requestArray = requestList.toArray(new CaptureRequest[requestList.size()]);
+            requestInfo = mRemoteDevice.submitRequestList(requestArray, repeating);
+            if (DEBUG) {
+                Log.v(TAG, "last frame number " + requestInfo.getLastFrameNumber());
             }
 
             if (callback != null) {
-                mCaptureCallbackMap.put(requestId, new CaptureCallbackHolder(callback,
-                        requestList, handler, repeating, mNextSessionId - 1));
+                mCaptureCallbackMap.put(requestInfo.getRequestId(),
+                        new CaptureCallbackHolder(
+                            callback, requestList, handler, repeating, mNextSessionId - 1));
             } else {
                 if (DEBUG) {
-                    Log.d(TAG, "Listen for request " + requestId + " is null");
+                    Log.d(TAG, "Listen for request " + requestInfo.getRequestId() + " is null");
                 }
             }
 
-            long lastFrameNumber = lastFrameNumberRef.getNumber();
-
             if (repeating) {
                 if (mRepeatingRequestId != REQUEST_ID_NONE) {
-                    checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
+                    checkEarlyTriggerSequenceComplete(mRepeatingRequestId,
+                            requestInfo.getLastFrameNumber());
                 }
-                mRepeatingRequestId = requestId;
+                mRepeatingRequestId = requestInfo.getRequestId();
             } else {
-                mRequestLastFrameNumbersList.add(new RequestLastFrameNumbersHolder(requestList,
-                        requestId, lastFrameNumber));
+                mRequestLastFrameNumbersList.add(
+                    new RequestLastFrameNumbersHolder(requestList, requestInfo));
             }
 
             if (mIdle) {
@@ -921,7 +874,7 @@ public class CameraDeviceImpl extends CameraDevice {
             }
             mIdle = false;
 
-            return requestId;
+            return requestInfo.getRequestId();
         }
     }
 
@@ -949,19 +902,9 @@ public class CameraDeviceImpl extends CameraDevice {
                 int requestId = mRepeatingRequestId;
                 mRepeatingRequestId = REQUEST_ID_NONE;
 
-                try {
-                    LongParcelable lastFrameNumberRef = new LongParcelable();
-                    mRemoteDevice.cancelRequest(requestId, /*out*/lastFrameNumberRef);
-                    long lastFrameNumber = lastFrameNumberRef.getNumber();
-
-                    checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
+                long lastFrameNumber = mRemoteDevice.cancelRequest(requestId);
 
-                } catch (CameraRuntimeException e) {
-                    throw e.asChecked();
-                } catch (RemoteException e) {
-                    // impossible
-                    return;
-                }
+                checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber);
             }
         }
     }
@@ -974,14 +917,8 @@ public class CameraDeviceImpl extends CameraDevice {
             if (mRepeatingRequestId != REQUEST_ID_NONE) {
                 throw new IllegalStateException("Active repeating request ongoing");
             }
-            try {
-                mRemoteDevice.waitUntilIdle();
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return;
-            }
+
+            mRemoteDevice.waitUntilIdle();
         }
     }
 
@@ -997,19 +934,11 @@ public class CameraDeviceImpl extends CameraDevice {
                 mDeviceHandler.post(mCallOnIdle);
                 return;
             }
-            try {
-                LongParcelable lastFrameNumberRef = new LongParcelable();
-                mRemoteDevice.flush(/*out*/lastFrameNumberRef);
-                if (mRepeatingRequestId != REQUEST_ID_NONE) {
-                    long lastFrameNumber = lastFrameNumberRef.getNumber();
-                    checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
-                    mRepeatingRequestId = REQUEST_ID_NONE;
-                }
-            } catch (CameraRuntimeException e) {
-                throw e.asChecked();
-            } catch (RemoteException e) {
-                // impossible
-                return;
+
+            long lastFrameNumber = mRemoteDevice.flush();
+            if (mRepeatingRequestId != REQUEST_ID_NONE) {
+                checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber);
+                mRepeatingRequestId = REQUEST_ID_NONE;
             }
         }
     }
@@ -1021,14 +950,8 @@ public class CameraDeviceImpl extends CameraDevice {
                 return;
             }
 
-            try {
-                if (mRemoteDevice != null) {
-                    mRemoteDevice.disconnect();
-                }
-            } catch (CameraRuntimeException e) {
-                Log.e(TAG, "Exception while closing: ", e.asChecked());
-            } catch (RemoteException e) {
-                // impossible
+            if (mRemoteDevice != null) {
+                mRemoteDevice.disconnect();
             }
 
             // Only want to fire the onClosed callback once;
@@ -1297,14 +1220,14 @@ public class CameraDeviceImpl extends CameraDevice {
          * Create a request-last-frame-numbers holder with a list of requests, request ID, and
          * the last frame number returned by camera service.
          */
-        public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, int requestId,
-                long lastFrameNumber) {
+        public RequestLastFrameNumbersHolder(List<CaptureRequest> requestList, SubmitInfo requestInfo) {
             long lastRegularFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
             long lastReprocessFrameNumber = CaptureCallback.NO_FRAMES_CAPTURED;
-            long frameNumber = lastFrameNumber;
+            long frameNumber = requestInfo.getLastFrameNumber();
 
-            if (lastFrameNumber < requestList.size() - 1) {
-                throw new IllegalArgumentException("lastFrameNumber: " + lastFrameNumber +
+            if (requestInfo.getLastFrameNumber() < requestList.size() - 1) {
+                throw new IllegalArgumentException(
+                        "lastFrameNumber: " + requestInfo.getLastFrameNumber() +
                         " should be at least " + (requestList.size() - 1) + " for the number of " +
                         " requests in the list: " + requestList.size());
             }
@@ -1330,7 +1253,7 @@ public class CameraDeviceImpl extends CameraDevice {
 
             mLastRegularFrameNumber = lastRegularFrameNumber;
             mLastReprocessFrameNumber = lastReprocessFrameNumber;
-            mRequestId = requestId;
+            mRequestId = requestInfo.getRequestId();
         }
 
         /**
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl b/core/java/android/hardware/camera2/impl/CameraMetadataNative.aidl
deleted file mode 100644 (file)
index 4a89129..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.impl;
-
-/** @hide */
-parcelable CameraMetadataNative;
index 12a2910..79eac26 100644 (file)
@@ -58,6 +58,7 @@ import android.location.Location;
 import android.location.LocationManager;
 import android.os.Parcelable;
 import android.os.Parcel;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.Size;
 
@@ -363,13 +364,24 @@ public class CameraMetadataNative implements Parcelable {
      * Set the global client-side vendor tag descriptor to allow use of vendor
      * tags in camera applications.
      *
-     * @return int A native status_t value corresponding to one of the
-     * {@link CameraBinderDecorator} integer constants.
-     * @see CameraBinderDecorator#throwOnError
-     *
+     * @throws ServiceSpecificException
      * @hide
      */
-    public static native int nativeSetupGlobalVendorTagDescriptor();
+    public static void setupGlobalVendorTagDescriptor() throws ServiceSpecificException {
+        int err = nativeSetupGlobalVendorTagDescriptor();
+        if (err != 0) {
+            throw new ServiceSpecificException(err, "Failure to set up global vendor tags");
+        }
+    }
+
+    /**
+     * Set the global client-side vendor tag descriptor to allow use of vendor
+     * tags in camera applications.
+     *
+     * @return int An error code corresponding to one of the
+     * {@link ICameraService} error constants, or 0 on success.
+     */
+    private static native int nativeSetupGlobalVendorTagDescriptor();
 
     /**
      * Set a camera metadata field to a value. The field definitions can be
diff --git a/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl b/core/java/android/hardware/camera2/impl/CaptureResultExtras.aidl
deleted file mode 100644 (file)
index ebc812a..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.impl;
-
-/** @hide */
-parcelable CaptureResultExtras;
diff --git a/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java b/core/java/android/hardware/camera2/impl/ICameraDeviceUserWrapper.java
new file mode 100644 (file)
index 0000000..ddc3fd1
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.impl;
+
+import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
+import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
+import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
+import static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
+import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
+import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
+
+import android.hardware.ICameraService;
+import android.hardware.camera2.CameraManager;
+import android.hardware.camera2.CameraAccessException;
+import android.hardware.camera2.CaptureRequest;
+import android.hardware.camera2.ICameraDeviceUser;
+import android.hardware.camera2.impl.CameraMetadataNative;
+import android.hardware.camera2.params.OutputConfiguration;
+import android.hardware.camera2.utils.SubmitInfo;
+import android.os.RemoteException;
+import android.view.Surface;
+
+/**
+ * A wrapper around ICameraDeviceUser.
+ *
+ * Mainly used to convert ServiceSpecificExceptions to the correct
+ * checked / unchecked exception.
+ *
+ * @hide
+ */
+public class ICameraDeviceUserWrapper {
+
+    private final ICameraDeviceUser mRemoteDevice;
+
+    public ICameraDeviceUserWrapper(ICameraDeviceUser remoteDevice) {
+        if (remoteDevice == null) {
+            throw new NullPointerException("Remote device may not be null");
+        }
+        mRemoteDevice = remoteDevice;
+    }
+
+    public void disconnect()  {
+        try {
+            mRemoteDevice.disconnect();
+        } catch (RemoteException t) {
+            // ignore binder errors for disconnect
+        }
+    }
+
+    public SubmitInfo submitRequest(CaptureRequest request, boolean streaming)
+            throws CameraAccessException  {
+        try {
+            return mRemoteDevice.submitRequest(request, streaming);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean streaming)
+            throws CameraAccessException {
+        try {
+            return mRemoteDevice.submitRequestList(requestList, streaming);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public long cancelRequest(int requestId) throws CameraAccessException {
+        try {
+            return mRemoteDevice.cancelRequest(requestId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void beginConfigure() throws CameraAccessException {
+        try {
+            mRemoteDevice.beginConfigure();
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void endConfigure(boolean isConstrainedHighSpeed) throws CameraAccessException {
+        try {
+            mRemoteDevice.endConfigure(isConstrainedHighSpeed);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void deleteStream(int streamId) throws CameraAccessException {
+        try {
+            mRemoteDevice.deleteStream(streamId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public int createStream(OutputConfiguration outputConfiguration)
+            throws CameraAccessException {
+        try {
+            return mRemoteDevice.createStream(outputConfiguration);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public int createInputStream(int width, int height, int format) throws CameraAccessException {
+        try {
+            return mRemoteDevice.createInputStream(width, height, format);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public Surface getInputSurface() throws CameraAccessException {
+        try {
+            return mRemoteDevice.getInputSurface();
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public CameraMetadataNative createDefaultRequest(int templateId) throws CameraAccessException {
+        try {
+            return mRemoteDevice.createDefaultRequest(templateId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public CameraMetadataNative getCameraInfo() throws CameraAccessException {
+        try {
+            return mRemoteDevice.getCameraInfo();
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void waitUntilIdle() throws CameraAccessException {
+        try {
+            mRemoteDevice.waitUntilIdle();
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public long flush() throws CameraAccessException {
+        try {
+            return mRemoteDevice.flush();
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void prepare(int streamId) throws CameraAccessException {
+        try {
+            mRemoteDevice.prepare(streamId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void tearDown(int streamId) throws CameraAccessException {
+        try {
+            mRemoteDevice.tearDown(streamId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+    public void prepare2(int maxCount, int streamId) throws CameraAccessException {
+        try {
+            mRemoteDevice.prepare2(maxCount, streamId);
+        } catch (Throwable t) {
+            CameraManager.throwAsPublicException(t);
+            throw new UnsupportedOperationException("Unexpected exception", t);
+        }
+    }
+
+
+}
index e7b3682..23efe15 100644 (file)
@@ -35,10 +35,10 @@ public class BurstHolder {
      *
      * @param requestId id of the burst request.
      * @param repeating true if this burst is repeating.
-     * @param requests a {@link List} of {@link CaptureRequest}s in this burst.
+     * @param requests the array of {@link CaptureRequest}s for this burst.
      * @param jpegSurfaceIds a {@link Collection} of IDs for the surfaces that have jpeg outputs.
      */
-    public BurstHolder(int requestId, boolean repeating, List<CaptureRequest> requests,
+    public BurstHolder(int requestId, boolean repeating, CaptureRequest[] requests,
                        Collection<Long> jpegSurfaceIds) {
         mRequestBuilders = new ArrayList<>();
         int i = 0;
index 798c941..d01c275 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.hardware.camera2.legacy;
 
+import android.hardware.ICameraService;
 import android.hardware.Camera;
 import android.hardware.Camera.CameraInfo;
 import android.hardware.camera2.CameraAccessException;
@@ -23,12 +24,10 @@ import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
-import android.hardware.camera2.utils.LongParcelable;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.os.ConditionVariable;
 import android.os.IBinder;
 import android.os.Looper;
@@ -36,6 +35,7 @@ import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Message;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.Surface;
@@ -93,7 +93,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
 
     private static int translateErrorsFromCamera1(int errorCode) {
         if (errorCode == -EACCES) {
-            return CameraBinderDecorator.PERMISSION_DENIED;
+            return ICameraService.ERROR_PERMISSION_DENIED;
         }
 
         return errorCode;
@@ -173,7 +173,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
          *
          * @return int error code
          *
-         * @throws CameraRuntimeException if the camera open times out with ({@code CAMERA_ERROR})
+         * @throws ServiceSpecificException if the camera open times out with ({@code CAMERA_ERROR})
          */
         public int waitForOpen(int timeoutMs) {
             // Block until the camera is open asynchronously
@@ -186,7 +186,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
                     Log.e(TAG, "connectBinderShim - Failed to release camera after timeout ", e);
                 }
 
-                throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION);
             }
 
             return mInitErrors;
@@ -344,7 +344,7 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
         Camera legacyCamera = init.getCamera();
 
         // Check errors old HAL initialization
-        CameraBinderDecorator.throwOnError(initErrors);
+        LegacyExceptionUtils.throwOnServiceError(initErrors);
 
         // Disable shutter sounds (this will work unconditionally) for api2 clients
         legacyCamera.disableShutterSound();
@@ -356,8 +356,8 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
         try {
             legacyParameters = legacyCamera.getParameters();
         } catch (RuntimeException e) {
-            throw new CameraRuntimeException(CameraAccessException.CAMERA_ERROR,
-                    "Unable to get initial parameters", e);
+            throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION,
+                    "Unable to get initial parameters: " + e.getMessage());
         }
 
         CameraCharacteristics characteristics =
@@ -386,101 +386,106 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
     }
 
     @Override
-    public int submitRequest(CaptureRequest request, boolean streaming,
-                             /*out*/LongParcelable lastFrameNumber) {
+    public SubmitInfo submitRequest(CaptureRequest request, boolean streaming) {
         if (DEBUG) {
             Log.d(TAG, "submitRequest called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot submit request, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot submit request, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot submit request, configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot submit request, configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
         }
-        return mLegacyDevice.submitRequest(request, streaming, lastFrameNumber);
+        return mLegacyDevice.submitRequest(request, streaming);
     }
 
     @Override
-    public int submitRequestList(List<CaptureRequest> request, boolean streaming,
-                                 /*out*/LongParcelable lastFrameNumber) {
+    public SubmitInfo submitRequestList(CaptureRequest[] request, boolean streaming) {
         if (DEBUG) {
             Log.d(TAG, "submitRequestList called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot submit request list, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot submit request list, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot submit request, configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot submit request, configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
         }
-        return mLegacyDevice.submitRequestList(request, streaming, lastFrameNumber);
+        return mLegacyDevice.submitRequestList(request, streaming);
     }
 
     @Override
-    public int cancelRequest(int requestId, /*out*/LongParcelable lastFrameNumber) {
+    public long cancelRequest(int requestId) {
         if (DEBUG) {
             Log.d(TAG, "cancelRequest called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot cancel request, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot cancel request, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot cancel request, configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot cancel request, configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
         }
-        long lastFrame = mLegacyDevice.cancelRequest(requestId);
-        lastFrameNumber.setNumber(lastFrame);
-        return CameraBinderDecorator.NO_ERROR;
+        return mLegacyDevice.cancelRequest(requestId);
     }
 
     @Override
-    public int beginConfigure() {
+    public void beginConfigure() {
         if (DEBUG) {
             Log.d(TAG, "beginConfigure called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot begin configure, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot begin configure, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot begin configure, configuration change already in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot begin configure, configuration change already in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
             mConfiguring = true;
         }
-        return CameraBinderDecorator.NO_ERROR;
     }
 
     @Override
-    public int endConfigure(boolean isConstrainedHighSpeed) {
+    public void endConfigure(boolean isConstrainedHighSpeed) {
         if (DEBUG) {
             Log.d(TAG, "endConfigure called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot end configure, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot end configure, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         ArrayList<Surface> surfaces = null;
         synchronized(mConfigureLock) {
             if (!mConfiguring) {
-                Log.e(TAG, "Cannot end configure, no configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot end configure, no configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
             int numSurfaces = mSurfaces.size();
             if (numSurfaces > 0) {
@@ -491,32 +496,34 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
             }
             mConfiguring = false;
         }
-        return mLegacyDevice.configureOutputs(surfaces);
+        mLegacyDevice.configureOutputs(surfaces);
     }
 
     @Override
-    public int deleteStream(int streamId) {
+    public void deleteStream(int streamId) {
         if (DEBUG) {
             Log.d(TAG, "deleteStream called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot delete stream, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot delete stream, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (!mConfiguring) {
-                Log.e(TAG, "Cannot delete stream, beginConfigure hasn't been called yet.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot delete stream, no configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
             int index = mSurfaces.indexOfKey(streamId);
             if (index < 0) {
-                Log.e(TAG, "Cannot delete stream, stream id " + streamId + " doesn't exist.");
-                return CameraBinderDecorator.BAD_VALUE;
+                String err = "Cannot delete stream, stream id " + streamId + " doesn't exist.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
             }
             mSurfaces.removeAt(index);
         }
-        return CameraBinderDecorator.NO_ERROR;
     }
 
     @Override
@@ -525,18 +532,21 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
             Log.d(TAG, "createStream called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot create stream, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot create stream, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (!mConfiguring) {
-                Log.e(TAG, "Cannot create stream, beginConfigure hasn't been called yet.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot create stream, beginConfigure hasn't been called yet.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
             if (outputConfiguration.getRotation() != OutputConfiguration.ROTATION_0) {
-                Log.e(TAG, "Cannot create stream, stream rotation is not supported.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot create stream, stream rotation is not supported.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
             }
             int id = ++mSurfaceIdCounter;
             mSurfaces.put(id, outputConfiguration.getSurface());
@@ -546,24 +556,27 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
 
     @Override
     public int createInputStream(int width, int height, int format) {
-        Log.e(TAG, "creating input stream is not supported on legacy devices");
-        return CameraBinderDecorator.INVALID_OPERATION;
+        String err = "Creating input stream is not supported on legacy devices";
+        Log.e(TAG, err);
+        throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
     }
 
     @Override
-    public int getInputSurface(/*out*/ Surface surface) {
-        Log.e(TAG, "getting input surface is not supported on legacy devices");
-        return CameraBinderDecorator.INVALID_OPERATION;
+    public Surface getInputSurface() {
+        String err = "Getting input surface is not supported on legacy devices";
+        Log.e(TAG, err);
+        throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
     }
 
     @Override
-    public int createDefaultRequest(int templateId, /*out*/CameraMetadataNative request) {
+    public CameraMetadataNative createDefaultRequest(int templateId) {
         if (DEBUG) {
             Log.d(TAG, "createDefaultRequest called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot create default request, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot create default request, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         CameraMetadataNative template;
@@ -571,99 +584,96 @@ public class CameraDeviceUserShim implements ICameraDeviceUser {
             template =
                     LegacyMetadataMapper.createRequestTemplate(mCameraCharacteristics, templateId);
         } catch (IllegalArgumentException e) {
-            Log.e(TAG, "createDefaultRequest - invalid templateId specified");
-            return CameraBinderDecorator.BAD_VALUE;
+            String err = "createDefaultRequest - invalid templateId specified";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_ILLEGAL_ARGUMENT, err);
         }
 
-        request.swap(template);
-        return CameraBinderDecorator.NO_ERROR;
+        return template;
     }
 
     @Override
-    public int getCameraInfo(/*out*/CameraMetadataNative info) {
+    public CameraMetadataNative getCameraInfo() {
         if (DEBUG) {
             Log.d(TAG, "getCameraInfo called.");
         }
         // TODO: implement getCameraInfo.
         Log.e(TAG, "getCameraInfo unimplemented.");
-        return CameraBinderDecorator.NO_ERROR;
+        return null;
     }
 
     @Override
-    public int waitUntilIdle() throws RemoteException {
+    public void waitUntilIdle() throws RemoteException {
         if (DEBUG) {
             Log.d(TAG, "waitUntilIdle called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot wait until idle, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot wait until idle, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot wait until idle, configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot wait until idle, configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
         }
         mLegacyDevice.waitUntilIdle();
-        return CameraBinderDecorator.NO_ERROR;
     }
 
     @Override
-    public int flush(/*out*/LongParcelable lastFrameNumber) {
+    public long flush() {
         if (DEBUG) {
             Log.d(TAG, "flush called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot flush, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot flush, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         synchronized(mConfigureLock) {
             if (mConfiguring) {
-                Log.e(TAG, "Cannot flush, configuration change in progress.");
-                return CameraBinderDecorator.INVALID_OPERATION;
+                String err = "Cannot flush, configuration change in progress.";
+                Log.e(TAG, err);
+                throw new ServiceSpecificException(ICameraService.ERROR_INVALID_OPERATION, err);
             }
         }
-        long lastFrame = mLegacyDevice.flush();
-        if (lastFrameNumber != null) {
-            lastFrameNumber.setNumber(lastFrame);
-        }
-        return CameraBinderDecorator.NO_ERROR;
+        return mLegacyDevice.flush();
     }
 
-    public int prepare(int streamId) {
+    public void prepare(int streamId) {
         if (DEBUG) {
             Log.d(TAG, "prepare called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot prepare stream, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot prepare stream, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         // LEGACY doesn't support actual prepare, just signal success right away
         mCameraCallbacks.onPrepared(streamId);
-
-        return CameraBinderDecorator.NO_ERROR;
     }
 
-    public int prepare2(int maxCount, int streamId) {
+    public void prepare2(int maxCount, int streamId) {
         // We don't support this in LEGACY mode.
-        return prepare(streamId);
+        prepare(streamId);
     }
 
-    public int tearDown(int streamId) {
+    public void tearDown(int streamId) {
         if (DEBUG) {
             Log.d(TAG, "tearDown called.");
         }
         if (mLegacyDevice.isClosed()) {
-            Log.e(TAG, "Cannot tear down stream, device has been closed.");
-            return -ENODEV;
+            String err = "Cannot tear down stream, device has been closed.";
+            Log.e(TAG, err);
+            throw new ServiceSpecificException(ICameraService.ERROR_DISCONNECTED, err);
         }
 
         // LEGACY doesn't support actual teardown, so just a no-op
-
-        return CameraBinderDecorator.NO_ERROR;
     }
 
     @Override
index fddfbde..4c4adea 100644 (file)
@@ -26,14 +26,13 @@ import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.params.StreamConfigurationMap;
 import android.hardware.camera2.utils.ArrayUtils;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.hardware.camera2.impl.CameraMetadataNative;
-import android.hardware.camera2.utils.CameraRuntimeException;
 import android.os.ConditionVariable;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Size;
@@ -45,7 +44,6 @@ import java.util.Collection;
 import java.util.List;
 
 import static android.hardware.camera2.legacy.LegacyExceptionUtils.*;
-import static android.hardware.camera2.utils.CameraBinderDecorator.*;
 import static com.android.internal.util.Preconditions.*;
 
 /**
@@ -357,9 +355,9 @@ public class LegacyCameraDevice implements AutoCloseable {
         if (success) {
             mConfiguredSurfaces = outputs != null ? new ArrayList<>(outputs) : null;
         } else {
-            return CameraBinderDecorator.INVALID_OPERATION;
+            return LegacyExceptionUtils.INVALID_OPERATION;
         }
-        return CameraBinderDecorator.NO_ERROR;
+        return LegacyExceptionUtils.NO_ERROR;
     }
 
     /**
@@ -367,17 +365,16 @@ public class LegacyCameraDevice implements AutoCloseable {
      *
      * @param requestList a list of capture requests to execute.
      * @param repeating {@code true} if this burst is repeating.
-     * @param frameNumber an output argument that contains either the frame number of the last frame
-     *                    that will be returned for this request, or the frame number of the last
-     *                    frame that will be returned for the current repeating request if this
-     *                    burst is set to be repeating.
-     * @return the request id.
+     * @return the submission info, including the new request id, and the last frame number, which
+     *   contains either the frame number of the last frame that will be returned for this request,
+     *   or the frame number of the last frame that will be returned for the current repeating
+     *   request if this burst is set to be repeating.
      */
-    public int submitRequestList(List<CaptureRequest> requestList, boolean repeating,
-            /*out*/LongParcelable frameNumber) {
-        if (requestList == null || requestList.isEmpty()) {
+    public SubmitInfo submitRequestList(CaptureRequest[] requestList, boolean repeating) {
+        if (requestList == null || requestList.length == 0) {
             Log.e(TAG, "submitRequestList - Empty/null requests are not allowed");
-            return BAD_VALUE;
+            throw new ServiceSpecificException(BAD_VALUE,
+                    "submitRequestList - Empty/null requests are not allowed");
         }
 
         List<Long> surfaceIds = (mConfiguredSurfaces == null) ? new ArrayList<Long>() :
@@ -388,28 +385,33 @@ public class LegacyCameraDevice implements AutoCloseable {
             if (request.getTargets().isEmpty()) {
                 Log.e(TAG, "submitRequestList - "
                         + "Each request must have at least one Surface target");
-                return BAD_VALUE;
+                throw new ServiceSpecificException(BAD_VALUE,
+                        "submitRequestList - "
+                        + "Each request must have at least one Surface target");
             }
 
             for (Surface surface : request.getTargets()) {
                 if (surface == null) {
                     Log.e(TAG, "submitRequestList - Null Surface targets are not allowed");
-                    return BAD_VALUE;
+                    throw new ServiceSpecificException(BAD_VALUE,
+                            "submitRequestList - Null Surface targets are not allowed");
                 } else if (mConfiguredSurfaces == null) {
                     Log.e(TAG, "submitRequestList - must configure " +
                             " device with valid surfaces before submitting requests");
-                    return INVALID_OPERATION;
+                    throw new ServiceSpecificException(INVALID_OPERATION,
+                            "submitRequestList - must configure " +
+                            " device with valid surfaces before submitting requests");
                 } else if (!containsSurfaceId(surface, surfaceIds)) {
                     Log.e(TAG, "submitRequestList - cannot use a surface that wasn't configured");
-                    return BAD_VALUE;
+                    throw new ServiceSpecificException(BAD_VALUE,
+                            "submitRequestList - cannot use a surface that wasn't configured");
                 }
             }
         }
 
         // TODO: further validation of request here
         mIdle.close();
-        return mRequestThreadManager.submitCaptureRequests(requestList, repeating,
-                frameNumber);
+        return mRequestThreadManager.submitCaptureRequests(requestList, repeating);
     }
 
     /**
@@ -417,17 +419,14 @@ public class LegacyCameraDevice implements AutoCloseable {
      *
      * @param request the capture request to execute.
      * @param repeating {@code true} if this request is repeating.
-     * @param frameNumber an output argument that contains either the frame number of the last frame
-     *                    that will be returned for this request, or the frame number of the last
-     *                    frame that will be returned for the current repeating request if this
-     *                    request is set to be repeating.
-     * @return the request id.
+     * @return the submission info, including the new request id, and the last frame number, which
+     *   contains either the frame number of the last frame that will be returned for this request,
+     *   or the frame number of the last frame that will be returned for the current repeating
+     *   request if this burst is set to be repeating.
      */
-    public int submitRequest(CaptureRequest request, boolean repeating,
-            /*out*/LongParcelable frameNumber) {
-        ArrayList<CaptureRequest> requestList = new ArrayList<CaptureRequest>();
-        requestList.add(request);
-        return submitRequestList(requestList, repeating, frameNumber);
+    public SubmitInfo submitRequest(CaptureRequest request, boolean repeating) {
+        CaptureRequest[] requestList = { request };
+        return submitRequestList(requestList, repeating);
     }
 
     /**
@@ -493,7 +492,7 @@ public class LegacyCameraDevice implements AutoCloseable {
     protected void finalize() throws Throwable {
         try {
             close();
-        } catch (CameraRuntimeException e) {
+        } catch (ServiceSpecificException e) {
             Log.e(TAG, "Got error while trying to finalize, ignoring: " + e.getMessage());
         } finally {
             super.finalize();
@@ -615,14 +614,16 @@ public class LegacyCameraDevice implements AutoCloseable {
         return LegacyExceptionUtils.throwOnError(nativeDetectSurfaceDataspace(surface));
     }
 
-    static void configureSurface(Surface surface, int width, int height,
-                                 int pixelFormat) throws BufferQueueAbandonedException {
+    static void connectSurface(Surface surface) throws BufferQueueAbandonedException {
         checkNotNull(surface);
-        checkArgumentPositive(width, "width must be positive.");
-        checkArgumentPositive(height, "height must be positive.");
 
-        LegacyExceptionUtils.throwOnError(nativeConfigureSurface(surface, width, height,
-                pixelFormat));
+        LegacyExceptionUtils.throwOnError(nativeConnectSurface(surface));
+    }
+
+    static void disconnectSurface(Surface surface) throws BufferQueueAbandonedException {
+        if (surface == null) return;
+
+        LegacyExceptionUtils.throwOnError(nativeDisconnectSurface(surface));
     }
 
     static void produceFrame(Surface surface, byte[] pixelBuffer, int width,
@@ -717,8 +718,7 @@ public class LegacyCameraDevice implements AutoCloseable {
     private static native int nativeDetectSurfaceDimens(Surface surface,
             /*out*/int[/*2*/] dimens);
 
-    private static native int nativeConfigureSurface(Surface surface, int width, int height,
-                                                        int pixelFormat);
+    private static native int nativeConnectSurface(Surface surface);
 
     private static native int nativeProduceFrame(Surface surface, byte[] pixelBuffer, int width,
                                                     int height, int pixelFormat);
@@ -741,5 +741,7 @@ public class LegacyCameraDevice implements AutoCloseable {
 
     private static native int nativeSetScalingMode(Surface surface, int scalingMode);
 
+    private static native int nativeDisconnectSurface(Surface surface);
+
     static native int nativeGetJpegFooterSize();
 }
index 4501e81..93d6001 100644 (file)
 
 package android.hardware.camera2.legacy;
 
-import android.hardware.camera2.utils.CameraBinderDecorator;
+import android.hardware.ICameraService;
+import android.os.ServiceSpecificException;
 import android.util.AndroidException;
 
-import static android.system.OsConstants.ENODEV;
+import static android.system.OsConstants.*;
 
 /**
  * Utility class containing exception handling used solely by the compatibility mode shim.
@@ -27,6 +28,14 @@ import static android.system.OsConstants.ENODEV;
 public class LegacyExceptionUtils {
     private static final String TAG = "LegacyExceptionUtils";
 
+    public static final int NO_ERROR = 0;
+    public static final int PERMISSION_DENIED = -EPERM;
+    public static final int ALREADY_EXISTS = -EEXIST;
+    public static final int BAD_VALUE = -EINVAL;
+    public static final int DEAD_OBJECT = -ENOSYS;
+    public static final int INVALID_OPERATION = -EPIPE;
+    public static final int TIMED_OUT = -ETIMEDOUT;
+
     /**
      * Checked exception thrown when a BufferQueue has been abandoned by its consumer.
      */
@@ -58,8 +67,8 @@ public class LegacyExceptionUtils {
      * @return {@code errorFlag} if the value was non-negative, throws otherwise.
      */
     public static int throwOnError(int errorFlag) throws BufferQueueAbandonedException {
-        if (errorFlag == CameraBinderDecorator.NO_ERROR) {
-            return CameraBinderDecorator.NO_ERROR;
+        if (errorFlag == NO_ERROR) {
+            return NO_ERROR;
         } else if (errorFlag == -ENODEV) {
             throw new BufferQueueAbandonedException();
         }
@@ -70,6 +79,59 @@ public class LegacyExceptionUtils {
         return errorFlag;
     }
 
+    /**
+     * Throw error codes returned by the camera service as exceptions.
+     *
+     * @param errorFlag error to throw as an exception.
+     */
+    public static void throwOnServiceError(int errorFlag) {
+        int errorCode = ICameraService.ERROR_INVALID_OPERATION;
+        String errorMsg;
+
+        if (errorFlag >= NO_ERROR) {
+            return;
+        } else if (errorFlag == PERMISSION_DENIED) {
+            errorCode = ICameraService.ERROR_PERMISSION_DENIED;
+            errorMsg = "Lacking privileges to access camera service";
+        } else if (errorFlag == ALREADY_EXISTS) {
+            // This should be handled at the call site. Typically this isn't bad,
+            // just means we tried to do an operation that already completed.
+            return;
+        } else if (errorFlag == BAD_VALUE) {
+            errorCode = ICameraService.ERROR_ILLEGAL_ARGUMENT;
+            errorMsg = "Bad argument passed to camera service";
+        } else if (errorFlag == DEAD_OBJECT) {
+            errorCode = ICameraService.ERROR_DISCONNECTED;
+            errorMsg = "Camera service not available";
+        } else if (errorFlag == TIMED_OUT) {
+            errorCode = ICameraService.ERROR_INVALID_OPERATION;
+            errorMsg = "Operation timed out in camera service";
+        } else if (errorFlag == -EACCES) {
+            errorCode = ICameraService.ERROR_DISABLED;
+            errorMsg = "Camera disabled by policy";
+        } else if (errorFlag == -EBUSY) {
+            errorCode = ICameraService.ERROR_CAMERA_IN_USE;
+            errorMsg = "Camera already in use";
+        } else if (errorFlag == -EUSERS) {
+            errorCode = ICameraService.ERROR_MAX_CAMERAS_IN_USE;
+            errorMsg = "Maximum number of cameras in use";
+        } else if (errorFlag == -ENODEV) {
+            errorCode = ICameraService.ERROR_DISCONNECTED;
+            errorMsg = "Camera device not available";
+        } else if (errorFlag == -EOPNOTSUPP) {
+            errorCode = ICameraService.ERROR_DEPRECATED_HAL;
+            errorMsg = "Deprecated camera HAL does not support this";
+        } else if (errorFlag == INVALID_OPERATION) {
+            errorCode = ICameraService.ERROR_INVALID_OPERATION;
+            errorMsg = "Illegal state encountered in camera service.";
+        } else {
+            errorCode = ICameraService.ERROR_INVALID_OPERATION;
+            errorMsg = "Unknown camera device error " + errorFlag;
+        }
+
+        throw new ServiceSpecificException(errorCode, errorMsg);
+    }
+
     private LegacyExceptionUtils() {
         throw new AssertionError();
     }
index c995029..8f252a1 100644 (file)
@@ -16,7 +16,7 @@
 package android.hardware.camera2.legacy;
 
 import android.hardware.camera2.CaptureRequest;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.util.Log;
 import android.util.Pair;
 
@@ -111,31 +111,29 @@ public class RequestQueue {
      *
      * @param requests the burst of requests to add to the queue.
      * @param repeating true if the burst is repeating.
-     * @param frameNumber an output argument that contains either the frame number of the last frame
-     *                    that will be returned for this request, or the frame number of the last
-     *                    frame that will be returned for the current repeating request if this
-     *                    burst is set to be repeating.
-     * @return the request id.
+     * @return the submission info, including the new request id, and the last frame number, which
+     *   contains either the frame number of the last frame that will be returned for this request,
+     *   or the frame number of the last frame that will be returned for the current repeating
+     *   request if this burst is set to be repeating.
      */
-    public synchronized int submit(List<CaptureRequest> requests, boolean repeating,
-            /*out*/LongParcelable frameNumber) {
+    public synchronized SubmitInfo submit(CaptureRequest[] requests, boolean repeating) {
         int requestId = mCurrentRequestId++;
         BurstHolder burst = new BurstHolder(requestId, repeating, requests, mJpegSurfaceIds);
-        long ret = INVALID_FRAME;
+        long lastFrame = INVALID_FRAME;
         if (burst.isRepeating()) {
             Log.i(TAG, "Repeating capture request set.");
             if (mRepeatingRequest != null) {
-                ret = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
+                lastFrame = (mCurrentRepeatingFrameNumber == INVALID_FRAME) ? INVALID_FRAME :
                         mCurrentRepeatingFrameNumber - 1;
             }
             mCurrentRepeatingFrameNumber = INVALID_FRAME;
             mRepeatingRequest = burst;
         } else {
             mRequestQueue.offer(burst);
-            ret = calculateLastFrame(burst.getRequestId());
+            lastFrame = calculateLastFrame(burst.getRequestId());
         }
-        frameNumber.setNumber(ret);
-        return requestId;
+        SubmitInfo info = new SubmitInfo(requestId, lastFrame);
+        return info;
     }
 
     private long calculateLastFrame(int requestId) {
index 4866598..e8ce3ec 100644 (file)
@@ -21,7 +21,7 @@ import android.hardware.Camera;
 import android.hardware.camera2.CameraCharacteristics;
 import android.hardware.camera2.CaptureRequest;
 import android.hardware.camera2.impl.CameraDeviceImpl;
-import android.hardware.camera2.utils.LongParcelable;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.hardware.camera2.utils.SizeAreaComparator;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.os.ConditionVariable;
@@ -365,6 +365,14 @@ public class RequestThreadManager {
             mGLThreadManager.waitUntilIdle();
         }
         resetJpegSurfaceFormats(mCallbackOutputs);
+
+        for (Surface s : mCallbackOutputs) {
+            try {
+                LegacyCameraDevice.disconnectSurface(s);
+            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+                Log.w(TAG, "Surface abandoned, skipping...", e);
+            }
+        }
         mPreviewOutputs.clear();
         mCallbackOutputs.clear();
         mJpegSurfaceIds.clear();
@@ -392,6 +400,10 @@ public class RequestThreadManager {
                             mJpegSurfaceIds.add(LegacyCameraDevice.getSurfaceId(s));
                             mCallbackOutputs.add(s);
                             callbackOutputSizes.add(outSize);
+
+                            // LegacyCameraDevice is the producer of JPEG output surfaces
+                            // so LegacyCameraDevice needs to connect to the surfaces.
+                            LegacyCameraDevice.connectSurface(s);
                             break;
                         default:
                             LegacyCameraDevice.setScalingMode(s, LegacyCameraDevice.
@@ -1008,21 +1020,19 @@ public class RequestThreadManager {
      *
      * @param requests the burst of requests to add to the queue.
      * @param repeating true if the burst is repeating.
-     * @param frameNumber an output argument that contains either the frame number of the last frame
-     *                    that will be returned for this request, or the frame number of the last
-     *                    frame that will be returned for the current repeating request if this
-     *                    burst is set to be repeating.
-     * @return the request id.
+     * @return the submission info, including the new request id, and the last frame number, which
+     *   contains either the frame number of the last frame that will be returned for this request,
+     *   or the frame number of the last frame that will be returned for the current repeating
+     *   request if this burst is set to be repeating.
      */
-    public int submitCaptureRequests(List<CaptureRequest> requests, boolean repeating,
-            /*out*/LongParcelable frameNumber) {
+    public SubmitInfo submitCaptureRequests(CaptureRequest[] requests, boolean repeating) {
         Handler handler = mRequestThread.waitAndGetHandler();
-        int ret;
+        SubmitInfo info;
         synchronized (mIdleLock) {
-            ret = mRequestQueue.submit(requests, repeating, frameNumber);
+            info = mRequestQueue.submit(requests, repeating);
             handler.sendEmptyMessage(MSG_SUBMIT_CAPTURE_REQUEST);
         }
-        return ret;
+        return info;
     }
 
     /**
index bc80fc1..70bc2fd 100644 (file)
@@ -401,6 +401,13 @@ public class SurfaceTextureRenderer {
 
     private void clearState() {
         mSurfaces.clear();
+        for (EGLSurfaceHolder holder : mConversionSurfaces) {
+            try {
+                LegacyCameraDevice.disconnectSurface(holder.surface);
+            } catch (LegacyExceptionUtils.BufferQueueAbandonedException e) {
+                Log.w(TAG, "Surface abandoned, skipping...", e);
+            }
+        }
         mConversionSurfaces.clear();
         mPBufferPixels = null;
         if (mSurfaceTexture != null) {
@@ -631,6 +638,9 @@ public class SurfaceTextureRenderer {
                 holder.height = surfaceSize.getHeight();
                 if (LegacyCameraDevice.needsConversion(s)) {
                     mConversionSurfaces.add(holder);
+                    // LegacyCameraDevice is the producer of surfaces if it's not handled by EGL,
+                    // so LegacyCameraDevice needs to connect to the surfaces.
+                    LegacyCameraDevice.connectSurface(s);
                 } else {
                     mSurfaces.add(holder);
                 }
index 4407e55..cd0c474 100644 (file)
@@ -21,11 +21,11 @@ import android.annotation.SystemApi;
 import android.hardware.camera2.CameraDevice;
 import android.hardware.camera2.utils.HashCodeHelpers;
 import android.hardware.camera2.utils.SurfaceUtils;
+import android.os.Parcel;
+import android.os.Parcelable;
 import android.util.Log;
 import android.util.Size;
 import android.view.Surface;
-import android.os.Parcel;
-import android.os.Parcelable;
 
 import static com.android.internal.util.Preconditions.*;
 
diff --git a/core/java/android/hardware/camera2/params/VendorTagDescriptor.java b/core/java/android/hardware/camera2/params/VendorTagDescriptor.java
new file mode 100644 (file)
index 0000000..ea424e5
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.camera2.params;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.Log;
+
+/**
+ * A class for describing the vendor tags declared by a camera HAL module.
+ * Generally only used by the native side of
+ * android.hardware.camera2.impl.CameraMetadataNative
+ *
+ * @hide
+ */
+public final class VendorTagDescriptor implements Parcelable {
+
+    private VendorTagDescriptor(Parcel source) {
+    }
+
+    public static final Parcelable.Creator<VendorTagDescriptor> CREATOR =
+            new Parcelable.Creator<VendorTagDescriptor>() {
+        @Override
+        public VendorTagDescriptor createFromParcel(Parcel source) {
+            try {
+                VendorTagDescriptor vendorDescriptor = new VendorTagDescriptor(source);
+                return vendorDescriptor;
+            } catch (Exception e) {
+                Log.e(TAG, "Exception creating VendorTagDescriptor from parcel", e);
+                return null;
+            }
+        }
+
+        @Override
+        public VendorTagDescriptor[] newArray(int size) {
+            return new VendorTagDescriptor[size];
+        }
+    };
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (dest == null) {
+            throw new IllegalArgumentException("dest must not be null");
+        }
+    }
+
+    private static final String TAG = "VendorTagDescriptor";
+}
diff --git a/core/java/android/hardware/camera2/utils/BinderHolder.aidl b/core/java/android/hardware/camera2/utils/BinderHolder.aidl
deleted file mode 100644 (file)
index f39d645..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-/** @hide */
-parcelable BinderHolder;
diff --git a/core/java/android/hardware/camera2/utils/BinderHolder.java b/core/java/android/hardware/camera2/utils/BinderHolder.java
deleted file mode 100644 (file)
index 9eea390..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.os.IBinder;
-
-/**
- * @hide
- */
-public class BinderHolder implements Parcelable {
-    private IBinder mBinder = null;
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongBinder(mBinder);
-    }
-
-    public void readFromParcel(Parcel src) {
-        mBinder = src.readStrongBinder();
-    }
-
-    public static final Parcelable.Creator<BinderHolder> CREATOR =
-             new Parcelable.Creator<BinderHolder>() {
-         @Override
-         public BinderHolder createFromParcel(Parcel in) {
-             return new BinderHolder(in);
-         }
-
-         @Override
-         public BinderHolder[] newArray(int size) {
-             return new BinderHolder[size];
-         }
-    };
-
-    public IBinder getBinder() {
-        return mBinder;
-    }
-
-    public void setBinder(IBinder binder) {
-        mBinder = binder;
-    }
-
-    public BinderHolder() {}
-
-    public BinderHolder(IBinder binder) {
-        mBinder = binder;
-    }
-
-    private BinderHolder(Parcel in) {
-        mBinder = in.readStrongBinder();
-    }
-}
-
diff --git a/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraBinderDecorator.java
deleted file mode 100644 (file)
index 162edc9..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-import static android.hardware.camera2.CameraAccessException.CAMERA_DISABLED;
-import static android.hardware.camera2.CameraAccessException.CAMERA_DISCONNECTED;
-import static android.hardware.camera2.CameraAccessException.CAMERA_IN_USE;
-import static android.hardware.camera2.CameraAccessException.CAMERA_ERROR;
-import static android.hardware.camera2.CameraAccessException.MAX_CAMERAS_IN_USE;
-import static android.hardware.camera2.CameraAccessException.CAMERA_DEPRECATED_HAL;
-import static android.system.OsConstants.*;
-
-import android.os.DeadObjectException;
-import android.os.RemoteException;
-
-import java.lang.reflect.Method;
-
-/**
- * Translate camera device status_t return values into exceptions.
- *
- * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
- * @hide
- */
-public class CameraBinderDecorator {
-
-    public static final int NO_ERROR = 0;
-    public static final int PERMISSION_DENIED = -EPERM;
-    public static final int ALREADY_EXISTS = -EEXIST;
-    public static final int BAD_VALUE = -EINVAL;
-    public static final int DEAD_OBJECT = -ENOSYS;
-    public static final int INVALID_OPERATION = -EPIPE;
-    public static final int TIMED_OUT = -ETIMEDOUT;
-
-    /**
-     * TODO: add as error codes in Errors.h
-     * - POLICY_PROHIBITS
-     * - RESOURCE_BUSY
-     * - NO_SUCH_DEVICE
-     * - NOT_SUPPORTED
-     * - TOO_MANY_USERS
-     */
-
-    static class CameraBinderDecoratorListener implements Decorator.DecoratorListener {
-
-        @Override
-        public void onBeforeInvocation(Method m, Object[] args) {
-        }
-
-        @Override
-        public void onAfterInvocation(Method m, Object[] args, Object result) {
-            // int return type => status_t => convert to exception
-            if (m.getReturnType() == Integer.TYPE) {
-                int returnValue = (Integer) result;
-                throwOnError(returnValue);
-            }
-        }
-
-        @Override
-        public boolean onCatchException(Method m, Object[] args, Throwable t) {
-
-            if (t instanceof DeadObjectException) {
-                throw new CameraRuntimeException(CAMERA_DISCONNECTED,
-                        "Process hosting the camera service has died unexpectedly",
-                        t);
-            } else if (t instanceof RemoteException) {
-                throw new UnsupportedOperationException("An unknown RemoteException was thrown" +
-                        " which should never happen.", t);
-            }
-
-            return false;
-        }
-
-        @Override
-        public void onFinally(Method m, Object[] args) {
-        }
-
-    }
-
-    /**
-     * Throw error codes returned by the camera service as exceptions.
-     *
-     * @param errorFlag error to throw as an exception.
-     */
-    public static void throwOnError(int errorFlag) {
-        if (errorFlag == NO_ERROR) {
-            return;
-        } else if (errorFlag == PERMISSION_DENIED) {
-            throw new SecurityException("Lacking privileges to access camera service");
-        } else if (errorFlag == ALREADY_EXISTS) {
-            // This should be handled at the call site. Typically this isn't bad,
-            // just means we tried to do an operation that already completed.
-            return;
-        } else if (errorFlag == BAD_VALUE) {
-            throw new IllegalArgumentException("Bad argument passed to camera service");
-        } else if (errorFlag == DEAD_OBJECT) {
-            throw new CameraRuntimeException(CAMERA_DISCONNECTED);
-        } else if (errorFlag == TIMED_OUT) {
-            throw new CameraRuntimeException(CAMERA_ERROR,
-                    "Operation timed out in camera service");
-        } else if (errorFlag == -EACCES) {
-            throw new CameraRuntimeException(CAMERA_DISABLED);
-        } else if (errorFlag == -EBUSY) {
-            throw new CameraRuntimeException(CAMERA_IN_USE);
-        } else if (errorFlag == -EUSERS) {
-            throw new CameraRuntimeException(MAX_CAMERAS_IN_USE);
-        } else if (errorFlag == -ENODEV) {
-            throw new CameraRuntimeException(CAMERA_DISCONNECTED);
-        } else if (errorFlag == -EOPNOTSUPP) {
-            throw new CameraRuntimeException(CAMERA_DEPRECATED_HAL);
-        } else if (errorFlag == INVALID_OPERATION) {
-            throw new CameraRuntimeException(CAMERA_ERROR,
-                    "Illegal state encountered in camera service.");
-        }
-
-        /**
-         * Trap the rest of the negative return values. If we have known
-         * error codes i.e. ALREADY_EXISTS that aren't really runtime
-         * errors, then add them to the top switch statement
-         */
-        if (errorFlag < 0) {
-            throw new CameraRuntimeException(CAMERA_ERROR,
-                    String.format("Unknown camera device error %d", errorFlag));
-        }
-    }
-
-    /**
-     * <p>
-     * Wraps the type T with a proxy that will check 'status_t' return codes
-     * from the native side of the camera service, and throw Java exceptions
-     * automatically based on the code.
-     * </p>
-     * <p>
-     * In addition it also rewrites binder's RemoteException into either a
-     * CameraAccessException or an UnsupportedOperationException.
-     * </p>
-     * <p>
-     * As a result of calling any method on the proxy, RemoteException is
-     * guaranteed never to be thrown.
-     * </p>
-     *
-     * @param obj object that will serve as the target for all method calls
-     * @param <T> the type of the element you want to wrap. This must be an interface.
-     * @return a proxy that will intercept all invocations to obj
-     */
-    public static <T> T newInstance(T obj) {
-        return Decorator.<T> newInstance(obj, new CameraBinderDecoratorListener());
-    }
-}
diff --git a/core/java/android/hardware/camera2/utils/CameraRuntimeException.java b/core/java/android/hardware/camera2/utils/CameraRuntimeException.java
deleted file mode 100644 (file)
index 9ed88a9..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-package android.hardware.camera2.utils;
-
-import android.hardware.camera2.CameraAccessException;
-
-/**
- * @hide
- */
-public class CameraRuntimeException extends RuntimeException {
-
-    private final int mReason;
-    private String mMessage;
-    private Throwable mCause;
-
-    public final int getReason() {
-        return mReason;
-    }
-
-    public CameraRuntimeException(int problem) {
-        super();
-        mReason = problem;
-    }
-
-    public CameraRuntimeException(int problem, String message) {
-        super(message);
-        mReason = problem;
-        mMessage = message;
-    }
-
-    public CameraRuntimeException(int problem, String message, Throwable cause) {
-        super(message, cause);
-        mReason = problem;
-        mMessage = message;
-        mCause = cause;
-    }
-
-    public CameraRuntimeException(int problem, Throwable cause) {
-        super(cause);
-        mReason = problem;
-        mCause = cause;
-    }
-
-    /**
-     * Recreate this exception as the CameraAccessException equivalent.
-     * @return CameraAccessException
-     */
-    public CameraAccessException asChecked() {
-        CameraAccessException e;
-
-        if (mMessage != null && mCause != null) {
-            e = new CameraAccessException(mReason, mMessage, mCause);
-        } else if (mMessage != null) {
-            e = new CameraAccessException(mReason, mMessage);
-        } else if (mCause != null) {
-            e = new CameraAccessException(mReason, mCause);
-        } else {
-            e = new CameraAccessException(mReason);
-        }
-        // throw and catch, so java has a chance to fill out the stack trace
-        e.setStackTrace(this.getStackTrace());
-
-        return e;
-    }
-}
diff --git a/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java b/core/java/android/hardware/camera2/utils/CameraServiceBinderDecorator.java
deleted file mode 100644 (file)
index c1fb6b1..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-import android.os.DeadObjectException;
-import android.os.RemoteException;
-import android.util.Log;
-
-import java.lang.reflect.Method;
-
-/**
- * Translate camera service status_t return values into exceptions.
- *
- * @see android.hardware.camera2.utils.CameraBinderDecorator#newInstance
- * @hide
- */
-public class CameraServiceBinderDecorator extends CameraBinderDecorator {
-
-    private static final String TAG = "CameraServiceBinderDecorator";
-
-    static class CameraServiceBinderDecoratorListener
-            extends CameraBinderDecorator.CameraBinderDecoratorListener {
-
-        // Pass through remote exceptions, unlike CameraBinderDecorator
-        @Override
-        public boolean onCatchException(Method m, Object[] args, Throwable t) {
-
-            if (t instanceof DeadObjectException) {
-                // Can sometimes happen (camera service died)
-                // Pass on silently
-            } else if (t instanceof RemoteException) {
-                // Some other kind of remote exception - this is not normal, so let's at least
-                // note it before moving on
-                Log.e(TAG, "Unexpected RemoteException from camera service call.", t);
-            }
-            // All other exceptions also get sent onward
-            return false;
-        }
-
-    }
-
-    /**
-     * <p>
-     * Wraps the type T with a proxy that will check 'status_t' return codes
-     * from the native side of the camera service, and throw Java exceptions
-     * automatically based on the code.
-     * </p>
-     *
-     * @param obj object that will serve as the target for all method calls
-     * @param <T> the type of the element you want to wrap. This must be an interface.
-     * @return a proxy that will intercept all invocations to obj
-     */
-    public static <T> T newInstance(T obj) {
-        return Decorator.<T> newInstance(obj, new CameraServiceBinderDecoratorListener());
-    }
-}
diff --git a/core/java/android/hardware/camera2/utils/Decorator.java b/core/java/android/hardware/camera2/utils/Decorator.java
deleted file mode 100644 (file)
index 5826497..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-
-package android.hardware.camera2.utils;
-
-import java.lang.reflect.*;
-
-/**
- * This is an implementation of the 'decorator' design pattern using Java's proxy mechanism.
- *
- * @see android.hardware.camera2.utils.Decorator#newInstance
- *
- * @hide
- */
-public class Decorator<T> implements InvocationHandler {
-
-    public interface DecoratorListener {
-        /**
-         * This method is called before the target method is invoked
-         * @param args arguments to target method
-         * @param m Method being called
-         */
-        void onBeforeInvocation(Method m, Object[] args);
-        /**
-         * This function is called after the target method is invoked
-         * if there were no uncaught exceptions
-         * @param args arguments to target method
-         * @param m Method being called
-         * @param result return value of target method
-         */
-        void onAfterInvocation(Method m, Object[] args, Object result);
-        /**
-         * This method is called only if there was an exception thrown by the target method
-         * during its invocation.
-         *
-         * @param args arguments to target method
-         * @param m Method being called
-         * @param t Throwable that was thrown
-         * @return false to rethrow exception, true if the exception was handled
-         */
-        boolean onCatchException(Method m, Object[] args, Throwable t);
-        /**
-         * This is called after the target method is invoked, regardless of whether or not
-         * there were any exceptions.
-         * @param args arguments to target method
-         * @param m Method being called
-         */
-        void onFinally(Method m, Object[] args);
-    }
-
-    private final T mObject;
-    private final DecoratorListener mListener;
-
-    /**
-     * Create a decorator wrapping the specified object's method calls.
-     *
-     * @param obj the object whose method calls you want to intercept
-     * @param listener the decorator handler for intercepted method calls
-     * @param <T> the type of the element you want to wrap. This must be an interface.
-     * @return a wrapped interface-compatible T
-     */
-    @SuppressWarnings("unchecked")
-    public static<T> T newInstance(T obj, DecoratorListener listener) {
-        return (T)java.lang.reflect.Proxy.newProxyInstance(
-                obj.getClass().getClassLoader(),
-                obj.getClass().getInterfaces(),
-                new Decorator<T>(obj, listener));
-    }
-
-    private Decorator(T obj, DecoratorListener listener) {
-        this.mObject = obj;
-        this.mListener = listener;
-    }
-
-    @Override
-    public Object invoke(Object proxy, Method m, Object[] args)
-            throws Throwable
-    {
-        Object result = null;
-        try {
-            mListener.onBeforeInvocation(m, args);
-            result = m.invoke(mObject, args);
-            mListener.onAfterInvocation(m, args, result);
-        } catch (InvocationTargetException e) {
-            Throwable t = e.getTargetException();
-            if (!mListener.onCatchException(m, args, t)) {
-                throw t;
-            }
-        } finally {
-            mListener.onFinally(m, args);
-        }
-        return result;
-    }
-}
diff --git a/core/java/android/hardware/camera2/utils/LongParcelable.aidl b/core/java/android/hardware/camera2/utils/LongParcelable.aidl
deleted file mode 100644 (file)
index 98ad1b2..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.hardware.camera2.utils;
-
-/** @hide */
-parcelable LongParcelable;
diff --git a/core/java/android/hardware/camera2/utils/SubmitInfo.java b/core/java/android/hardware/camera2/utils/SubmitInfo.java
new file mode 100644 (file)
index 0000000..d1692b5
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package android.hardware.camera2.utils;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.hardware.camera2.ICameraDeviceUser;
+
+/**
+ * The status information returned for a successful capture request submission.
+ *
+ * Includes the request ID for the newly submitted capture request, and the
+ * last frame number of either the previous repeating request (for repeating
+ * requests), or of the request(s) just submitted (for single-shot capture).
+ *
+ * @hide
+ */
+public class SubmitInfo implements Parcelable {
+
+    private int mRequestId;
+    private long mLastFrameNumber;
+
+    public SubmitInfo() {
+        mRequestId = -1;
+        mLastFrameNumber = ICameraDeviceUser.NO_IN_FLIGHT_REPEATING_FRAMES;
+    }
+
+    public SubmitInfo(int requestId, long lastFrameNumber) {
+        mRequestId = requestId;
+        mLastFrameNumber = lastFrameNumber;
+    }
+
+    public static final Parcelable.Creator<SubmitInfo> CREATOR =
+            new Parcelable.Creator<SubmitInfo>() {
+        @Override
+        public SubmitInfo createFromParcel(Parcel in) {
+            return new SubmitInfo(in);
+        }
+
+        @Override
+        public SubmitInfo[] newArray(int size) {
+            return new SubmitInfo[size];
+        }
+    };
+
+    private SubmitInfo(Parcel in) {
+        readFromParcel(in);
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(mRequestId);
+        dest.writeLong(mLastFrameNumber);
+    }
+
+    public void readFromParcel(Parcel in) {
+        mRequestId = in.readInt();
+        mLastFrameNumber = in.readLong();
+    }
+
+    /**
+     * Return the request ID for the submitted capture request/burst.
+     *
+     * This is used to track the completion status of the requested captures,
+     * and to cancel repeating requests.
+     */
+    public int getRequestId() {
+        return mRequestId;
+    }
+
+    /**
+     * Return the last frame number for the submitted capture request/burst.
+     *
+     * For a repeating request, this is the last frame number of the _prior_
+     * repeating request, to indicate when to fire the sequence completion callback
+     * for the prior repeating request.
+     *
+     * For a single-shot capture, this is the last frame number of _this_
+     * burst, to indicate when to fire the sequence completion callback for the request itself.
+     *
+     * For a repeating request, may be NO_IN_FLIGHT_REPEATING_FRAMES, if no
+     * instances of a prior repeating request were actually issued to the camera device.
+     */
+    public long getLastFrameNumber() {
+        return mLastFrameNumber;
+    }
+
+}
index abd02f0..b8088f3 100644 (file)
@@ -540,7 +540,7 @@ public class FingerprintManager {
         if (mService != null) try {
             result = mService.preEnroll(mToken);
         } catch (RemoteException e) {
-            Log.w(TAG, "Remote exception in enroll: ", e);
+            throw e.rethrowFromSystemServer();
         }
         return result;
     }
@@ -555,7 +555,7 @@ public class FingerprintManager {
         if (mService != null) try {
             result = mService.postEnroll(mToken);
         } catch (RemoteException e) {
-            Log.w(TAG, "Remote exception in post enroll: ", e);
+            throw e.rethrowFromSystemServer();
         }
         return result;
     }
@@ -571,7 +571,7 @@ public class FingerprintManager {
         if (mService != null) try {
             mService.setActiveUser(userId);
         } catch (RemoteException e) {
-            Log.w(TAG, "Remote exception in setActiveUser: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -614,7 +614,7 @@ public class FingerprintManager {
             try {
                 mService.rename(fpId, userId, newName);
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in rename(): ", e);
+                throw e.rethrowFromSystemServer();
             }
         } else {
             Log.w(TAG, "rename(): Service not connected!");
@@ -632,7 +632,7 @@ public class FingerprintManager {
         if (mService != null) try {
             return mService.getEnrolledFingerprints(userId, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+            throw e.rethrowFromSystemServer();
         }
         return null;
     }
@@ -659,7 +659,7 @@ public class FingerprintManager {
             return mService.hasEnrolledFingerprints(
                     UserHandle.myUserId(), mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+            throw e.rethrowFromSystemServer();
         }
         return false;
     }
@@ -674,7 +674,7 @@ public class FingerprintManager {
         if (mService != null) try {
             return mService.hasEnrolledFingerprints(userId, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.v(TAG, "Remote exception in getEnrolledFingerprints: ", e);
+            throw e.rethrowFromSystemServer();
         }
         return false;
     }
@@ -691,7 +691,7 @@ public class FingerprintManager {
                 long deviceId = 0; /* TODO: plumb hardware id to FPMS */
                 return mService.isHardwareDetected(deviceId, mContext.getOpPackageName());
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in isFingerprintHardwareDetected(): ", e);
+                throw e.rethrowFromSystemServer();
             }
         } else {
             Log.w(TAG, "isFingerprintHardwareDetected(): Service not connected!");
@@ -710,7 +710,7 @@ public class FingerprintManager {
             try {
                 return mService.getAuthenticatorId(mContext.getOpPackageName());
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in getAuthenticatorId(): ", e);
+                throw e.rethrowFromSystemServer();
             }
         } else {
             Log.w(TAG, "getAuthenticatorId(): Service not connected!");
@@ -730,7 +730,7 @@ public class FingerprintManager {
             try {
                 mService.resetTimeout(token);
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in resetTimeout(): ", e);
+                throw e.rethrowFromSystemServer();
             }
         } else {
             Log.w(TAG, "resetTimeout(): Service not connected!");
@@ -765,7 +765,7 @@ public class FingerprintManager {
                     }
                 });
             } catch (RemoteException e) {
-                Log.v(TAG, "Remote exception in addLockoutResetCallback(): ", e);
+                throw e.rethrowFromSystemServer();
             }
         } else {
             Log.w(TAG, "addLockoutResetCallback(): Service not connected!");
@@ -881,8 +881,7 @@ public class FingerprintManager {
         try {
             return ActivityManagerNative.getDefault().getCurrentUser().id;
         } catch (RemoteException e) {
-            Log.w(TAG, "Failed to get current user id\n");
-            return UserHandle.USER_NULL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -890,7 +889,7 @@ public class FingerprintManager {
         if (mService != null) try {
             mService.cancelEnrollment(mToken);
         } catch (RemoteException e) {
-            if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -898,7 +897,7 @@ public class FingerprintManager {
         if (mService != null) try {
             mService.cancelAuthentication(mToken, mContext.getOpPackageName());
         } catch (RemoteException e) {
-            if (DEBUG) Log.w(TAG, "Remote exception while canceling enrollment");
+            throw e.rethrowFromSystemServer();
         }
     }
 
index 6effc0d..ff87b67 100644 (file)
@@ -267,7 +267,7 @@ public final class HdmiControlManager {
             try {
                 types = mService.getSupportedTypes();
             } catch (RemoteException e) {
-                // Do nothing.
+                throw e.rethrowFromSystemServer();
             }
         }
         mHasTvDevice = hasDeviceType(types, HdmiDeviceInfo.DEVICE_TV);
@@ -403,7 +403,7 @@ public final class HdmiControlManager {
         try {
             mService.addHotplugEventListener(wrappedListener);
         } catch (RemoteException e) {
-            Log.e(TAG, "failed to add hotplug event listener: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -425,7 +425,7 @@ public final class HdmiControlManager {
         try {
             mService.removeHotplugEventListener(wrappedListener);
         } catch (RemoteException e) {
-            Log.e(TAG, "failed to remove hotplug event listener: ", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
index cbe3412..fbac58c 100644 (file)
@@ -252,7 +252,7 @@ public final class InputManager {
                 try {
                     inputDevice = mIm.getInputDevice(id);
                 } catch (RemoteException ex) {
-                    throw new RuntimeException("Could not get input device information.", ex);
+                    throw ex.rethrowFromSystemServer();
                 }
                 if (inputDevice != null) {
                     mInputDevices.setValueAt(index, inputDevice);
@@ -284,7 +284,7 @@ public final class InputManager {
                     try {
                         inputDevice = mIm.getInputDevice(id);
                     } catch (RemoteException ex) {
-                        // Ignore the problem for the purposes of this method.
+                        throw ex.rethrowFromSystemServer();
                     }
                     if (inputDevice == null) {
                         continue;
@@ -384,8 +384,7 @@ public final class InputManager {
         try {
             return mIm.isInTabletMode();
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get tablet mode state", ex);
-            return SWITCH_STATE_UNKNOWN;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -439,7 +438,7 @@ public final class InputManager {
         try {
             mIm.registerTabletModeChangedListener(listener);
         } catch (RemoteException ex) {
-            throw new RuntimeException("Could not register tablet mode changed listener", ex);
+            throw ex.rethrowFromSystemServer();
         }
         mTabletModeChangedListener = listener;
         mOnTabletModeChangedListeners = new ArrayList<>();
@@ -471,8 +470,7 @@ public final class InputManager {
         try {
             return mIm.getKeyboardLayouts();
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get list of keyboard layout informations.", ex);
-            return new KeyboardLayout[0];
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -494,8 +492,7 @@ public final class InputManager {
         try {
             return mIm.getKeyboardLayoutsForInputDevice(identifier);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get list of keyboard layouts for input device.", ex);
-            return new KeyboardLayout[0];
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -516,8 +513,7 @@ public final class InputManager {
         try {
             return mIm.getKeyboardLayout(keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get keyboard layout information.", ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -534,8 +530,7 @@ public final class InputManager {
         try {
             return mIm.getCurrentKeyboardLayoutForInputDevice(identifier);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get current keyboard layout for input device.", ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -565,7 +560,7 @@ public final class InputManager {
             mIm.setCurrentKeyboardLayoutForInputDevice(identifier,
                     keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set current keyboard layout for input device.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -585,8 +580,7 @@ public final class InputManager {
         try {
             return mIm.getEnabledKeyboardLayoutsForInputDevice(identifier);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get keyboard layouts for input device.", ex);
-            return ArrayUtils.emptyArray(String.class);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -614,7 +608,7 @@ public final class InputManager {
         try {
             mIm.addKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not add keyboard layout for input device.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -642,7 +636,7 @@ public final class InputManager {
         try {
             mIm.removeKeyboardLayoutForInputDevice(identifier, keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not remove keyboard layout for input device.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -664,8 +658,7 @@ public final class InputManager {
             return mIm.getKeyboardLayoutForInputDevice(
                     identifier, inputMethodInfo, inputMethodSubtype);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set keyboard layout.", ex);
-            return null;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -687,7 +680,7 @@ public final class InputManager {
             mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
                     inputMethodSubtype, keyboardLayoutDescriptor);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set keyboard layout.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -704,8 +697,7 @@ public final class InputManager {
         try {
             return mIm.getTouchCalibrationForInputDevice(inputDeviceDescriptor, surfaceRotation);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not get calibration matrix for input device.", ex);
-            return TouchCalibration.IDENTITY;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -726,7 +718,7 @@ public final class InputManager {
         try {
             mIm.setTouchCalibrationForInputDevice(inputDeviceDescriptor, surfaceRotation, calibration);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set calibration matrix for input device.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -793,7 +785,7 @@ public final class InputManager {
         try {
             mIm.tryPointerSpeed(speed);
         } catch (RemoteException ex) {
-            Log.w(TAG, "Could not set temporary pointer speed.", ex);
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -831,7 +823,7 @@ public final class InputManager {
         try {
             mIm.hasKeys(id, InputDevice.SOURCE_ANY, keyCodes, ret);
         } catch (RemoteException e) {
-            // no fallback; just return the empty array
+            throw e.rethrowFromSystemServer();
         }
         return ret;
     }
@@ -871,7 +863,7 @@ public final class InputManager {
         try {
             return mIm.injectInputEvent(event, mode);
         } catch (RemoteException ex) {
-            return false;
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -887,7 +879,7 @@ public final class InputManager {
         try {
             mIm.setPointerIconShape(iconId);
         } catch (RemoteException ex) {
-            // Do nothing.
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -896,7 +888,7 @@ public final class InputManager {
         try {
             mIm.setCustomPointerIcon(icon);
         } catch (RemoteException ex) {
-            // Do nothing.
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -914,7 +906,7 @@ public final class InputManager {
         try {
             mIm.setPointerIconDetached(detached);
         } catch (RemoteException ex) {
-            // Do nothing.
+            throw ex.rethrowFromSystemServer();
         }
     }
 
@@ -924,8 +916,7 @@ public final class InputManager {
             try {
                 mIm.registerInputDevicesChangedListener(listener);
             } catch (RemoteException ex) {
-                throw new RuntimeException(
-                        "Could not get register input device changed listener", ex);
+                throw ex.rethrowFromSystemServer();
             }
             mInputDevicesChangedListener = listener;
         }
@@ -935,7 +926,7 @@ public final class InputManager {
             try {
                 ids = mIm.getInputDeviceIds();
             } catch (RemoteException ex) {
-                throw new RuntimeException("Could not get input device ids.", ex);
+                throw ex.rethrowFromSystemServer();
             }
 
             mInputDevices = new SparseArray<InputDevice>();
@@ -1175,7 +1166,7 @@ public final class InputManager {
             try {
                 mIm.vibrate(mDeviceId, pattern, repeat, mToken);
             } catch (RemoteException ex) {
-                Log.w(TAG, "Failed to vibrate.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
 
@@ -1184,7 +1175,7 @@ public final class InputManager {
             try {
                 mIm.cancelVibrate(mDeviceId, mToken);
             } catch (RemoteException ex) {
-                Log.w(TAG, "Failed to cancel vibration.", ex);
+                throw ex.rethrowFromSystemServer();
             }
         }
     }
index cc2b764..b635088 100644 (file)
@@ -689,12 +689,19 @@ public class SoundTrigger {
                 return false;
             if (triggerInData != other.triggerInData)
                 return false;
-            if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate())
-                return false;
-            if (captureFormat.getEncoding() != other.captureFormat.getEncoding())
-                return false;
-            if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask())
-                return false;
+            if (captureFormat == null) {
+                if (other.captureFormat != null)
+                    return false;
+            } else {
+                if (other.captureFormat == null)
+                    return false;
+                if (captureFormat.getSampleRate() != other.captureFormat.getSampleRate())
+                    return false;
+                if (captureFormat.getEncoding() != other.captureFormat.getEncoding())
+                    return false;
+                if (captureFormat.getChannelMask() != other.captureFormat.getChannelMask())
+                    return false;
+            }
             return true;
         }
 
@@ -1002,10 +1009,10 @@ public class SoundTrigger {
                 int encoding = in.readInt();
                 int channelMask = in.readInt();
                 captureFormat = (new AudioFormat.Builder())
-                        .setChannelMask(channelMask)
-                        .setEncoding(encoding)
-                        .setSampleRate(sampleRate)
-                        .build();
+                    .setChannelMask(channelMask)
+                    .setEncoding(encoding)
+                    .setSampleRate(sampleRate)
+                    .build();
             }
             byte[] data = in.readBlob();
             KeyphraseRecognitionExtra[] keyphraseExtras =
index 7004e97..5f1043b 100644 (file)
@@ -45,10 +45,12 @@ import android.provider.Settings;
 import android.telephony.SubscriptionManager;
 import android.util.ArrayMap;
 import android.util.Log;
+import android.util.SparseArray;
 
 import com.android.internal.telephony.ITelephony;
 import com.android.internal.telephony.PhoneConstants;
 import com.android.internal.util.Protocol;
+import com.android.internal.util.MessageUtils;
 
 import libcore.net.event.NetworkEventDispatcher;
 
@@ -79,6 +81,13 @@ import java.util.concurrent.atomic.AtomicInteger;
 public class ConnectivityManager {
     private static final String TAG = "ConnectivityManager";
 
+    private static final SparseArray<String> sMagicDecoderRing = MessageUtils.findMessageNames(
+            new Class[]{ConnectivityManager.class}, new String[]{"CALLBACK_"});
+
+    private static final String whatToString(int what) {
+        return sMagicDecoderRing.get(what, Integer.toString(what));
+    }
+
     /**
      * A change in network connectivity has occurred. A default connection has either
      * been established or lost. The NetworkInfo for the affected network is
@@ -733,7 +742,7 @@ public class ConnectivityManager {
         try {
             return mService.getActiveNetworkInfo();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -753,7 +762,7 @@ public class ConnectivityManager {
         try {
             return mService.getActiveNetwork();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -777,7 +786,7 @@ public class ConnectivityManager {
         try {
             return mService.setAlwaysOnVpnPackage(userId, vpnPackage);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -794,7 +803,7 @@ public class ConnectivityManager {
         try {
             return mService.getAlwaysOnVpnPackage(userId);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -815,7 +824,7 @@ public class ConnectivityManager {
         try {
             return mService.getActiveNetworkInfoForUid(uid);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -839,7 +848,7 @@ public class ConnectivityManager {
         try {
             return mService.getNetworkInfo(networkType);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -859,7 +868,7 @@ public class ConnectivityManager {
         try {
             return mService.getNetworkInfoForNetwork(network);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -880,7 +889,7 @@ public class ConnectivityManager {
         try {
             return mService.getAllNetworkInfo();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -900,7 +909,7 @@ public class ConnectivityManager {
         try {
             return mService.getNetworkForType(networkType);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -916,7 +925,7 @@ public class ConnectivityManager {
         try {
             return mService.getAllNetworks();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -929,7 +938,7 @@ public class ConnectivityManager {
         try {
             return mService.getDefaultNetworkCapabilitiesForUser(userId);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -948,7 +957,7 @@ public class ConnectivityManager {
         try {
             return mService.getActiveLinkProperties();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -972,7 +981,7 @@ public class ConnectivityManager {
         try {
             return mService.getLinkPropertiesForType(networkType);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -989,7 +998,7 @@ public class ConnectivityManager {
         try {
             return mService.getLinkProperties(network);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1006,7 +1015,7 @@ public class ConnectivityManager {
         try {
             return mService.getNetworkCapabilities(network);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1024,7 +1033,7 @@ public class ConnectivityManager {
         try {
             return mService.getCaptivePortalServerUrl();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1324,7 +1333,9 @@ public class ConnectivityManager {
         int type = legacyTypeForNetworkCapabilities(netCap);
         try {
             delay = mService.getRestoreDefaultNetworkDelay(type);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
         LegacyRequest l = new LegacyRequest();
         l.networkCapabilities = netCap;
         l.delay = delay;
@@ -1542,7 +1553,7 @@ public class ConnectivityManager {
         try {
             return mService.requestRouteToHostAddress(networkType, hostAddress.getAddress());
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1598,7 +1609,7 @@ public class ConnectivityManager {
         try {
             return mService.getActiveNetworkQuotaInfo();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1617,7 +1628,9 @@ public class ConnectivityManager {
                 Log.d("ConnectivityManager", "getMobileDataEnabled()- subId=" + subId
                         + " retVal=" + retVal);
                 return retVal;
-            } catch (RemoteException e) { }
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
+            }
         }
         Log.d("ConnectivityManager", "getMobileDataEnabled()- remote exception retVal=false");
         return false;
@@ -1678,6 +1691,7 @@ public class ConnectivityManager {
             getNetworkManagementService().registerNetworkActivityListener(rl);
             mNetworkActivityListeners.put(l, rl);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1695,6 +1709,7 @@ public class ConnectivityManager {
         try {
             getNetworkManagementService().unregisterNetworkActivityListener(rl);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1710,8 +1725,8 @@ public class ConnectivityManager {
         try {
             return getNetworkManagementService().isNetworkActive();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return false;
     }
 
     /**
@@ -1785,7 +1800,7 @@ public class ConnectivityManager {
         try {
             return mService.getTetherableIfaces();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1802,7 +1817,7 @@ public class ConnectivityManager {
         try {
             return mService.getTetheredIfaces();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1825,7 +1840,7 @@ public class ConnectivityManager {
         try {
             return mService.getTetheringErroredIfaces();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1839,7 +1854,7 @@ public class ConnectivityManager {
         try {
             return mService.getTetheredDhcpRanges();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1871,7 +1886,7 @@ public class ConnectivityManager {
         try {
             return mService.tether(iface);
         } catch (RemoteException e) {
-            return TETHER_ERROR_SERVICE_UNAVAIL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1897,7 +1912,7 @@ public class ConnectivityManager {
         try {
             return mService.untether(iface);
         } catch (RemoteException e) {
-            return TETHER_ERROR_SERVICE_UNAVAIL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1917,7 +1932,7 @@ public class ConnectivityManager {
         try {
             return mService.isTetheringSupported();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2005,7 +2020,7 @@ public class ConnectivityManager {
         try {
             mService.stopTethering(type);
         } catch (RemoteException e) {
-            Log.e(TAG, "Exception trying to stop tethering.", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2025,7 +2040,7 @@ public class ConnectivityManager {
         try {
             return mService.getTetherableUsbRegexs();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2045,7 +2060,7 @@ public class ConnectivityManager {
         try {
             return mService.getTetherableWifiRegexs();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2065,7 +2080,7 @@ public class ConnectivityManager {
         try {
             return mService.getTetherableBluetoothRegexs();
         } catch (RemoteException e) {
-            return new String[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2090,7 +2105,7 @@ public class ConnectivityManager {
         try {
             return mService.setUsbTethering(enable);
         } catch (RemoteException e) {
-            return TETHER_ERROR_SERVICE_UNAVAIL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2135,7 +2150,7 @@ public class ConnectivityManager {
         try {
             return mService.getLastTetherError(iface);
         } catch (RemoteException e) {
-            return TETHER_ERROR_SERVICE_UNAVAIL;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2153,6 +2168,7 @@ public class ConnectivityManager {
         try {
             mService.reportInetCondition(networkType, percentage);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2174,6 +2190,7 @@ public class ConnectivityManager {
             mService.reportNetworkConnectivity(network, true);
             mService.reportNetworkConnectivity(network, false);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2192,6 +2209,7 @@ public class ConnectivityManager {
         try {
             mService.reportNetworkConnectivity(network, hasConnectivity);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2211,6 +2229,7 @@ public class ConnectivityManager {
         try {
             mService.setGlobalProxy(p);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2225,7 +2244,7 @@ public class ConnectivityManager {
         try {
             return mService.getGlobalProxy();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2247,7 +2266,7 @@ public class ConnectivityManager {
         try {
             return mService.getProxyForNetwork(network);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2282,8 +2301,9 @@ public class ConnectivityManager {
     public boolean isNetworkSupported(int networkType) {
         try {
             return mService.isNetworkSupported(networkType);
-        } catch (RemoteException e) {}
-        return false;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -2303,7 +2323,7 @@ public class ConnectivityManager {
         try {
             return mService.isActiveNetworkMetered();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2320,7 +2340,7 @@ public class ConnectivityManager {
         try {
             return mService.updateLockdownVpn();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2339,6 +2359,7 @@ public class ConnectivityManager {
         try {
             timeOutMs = mService.checkMobileProvisioning(suggestedTimeOutMs);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
         return timeOutMs;
     }
@@ -2351,8 +2372,8 @@ public class ConnectivityManager {
         try {
             return mService.getMobileProvisioningUrl();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -2369,6 +2390,7 @@ public class ConnectivityManager {
         try {
             mService.setProvisioningNotificationVisible(visible, networkType, action);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2385,6 +2407,7 @@ public class ConnectivityManager {
         try {
             mService.setAirplaneMode(enable);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2392,14 +2415,18 @@ public class ConnectivityManager {
     public void registerNetworkFactory(Messenger messenger, String name) {
         try {
             mService.registerNetworkFactory(messenger, name);
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /** {@hide} */
     public void unregisterNetworkFactory(Messenger messenger) {
         try {
             mService.unregisterNetworkFactory(messenger);
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -2412,7 +2439,7 @@ public class ConnectivityManager {
         try {
             return mService.registerNetworkAgent(messenger, ni, lp, nc, score, misc);
         } catch (RemoteException e) {
-            return NETID_UNSET;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2563,9 +2590,11 @@ public class ConnectivityManager {
 
         @Override
         public void handleMessage(Message message) {
-            if (DBG) Log.d(TAG, "CM callback handler got msg " + message.what);
             NetworkRequest request = (NetworkRequest) getObject(message, NetworkRequest.class);
             Network network = (Network) getObject(message, Network.class);
+            if (DBG) {
+                Log.d(TAG, whatToString(message.what) + " for network " + network);
+            }
             switch (message.what) {
                 case CALLBACK_PRECHECK: {
                     NetworkCallback callback = getCallback(request, "PRECHECK");
@@ -2730,7 +2759,9 @@ public class ConnectivityManager {
                     sNetworkCallback.put(networkCallback.networkRequest, networkCallback);
                 }
             }
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
         if (networkCallback.networkRequest == null) decCallbackHandlerRefCount();
         return networkCallback.networkRequest;
     }
@@ -2893,7 +2924,9 @@ public class ConnectivityManager {
         checkPendingIntent(operation);
         try {
             mService.pendingRequestForNetwork(request.networkCapabilities, operation);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -2911,7 +2944,9 @@ public class ConnectivityManager {
         checkPendingIntent(operation);
         try {
             mService.releasePendingNetworkRequest(operation);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     private void checkPendingIntent(PendingIntent intent) {
@@ -2970,7 +3005,9 @@ public class ConnectivityManager {
         checkPendingIntent(operation);
         try {
             mService.pendingListenForNetwork(request.networkCapabilities, operation);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -2988,7 +3025,7 @@ public class ConnectivityManager {
         try {
             return mService.requestBandwidthUpdate(network);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3008,7 +3045,9 @@ public class ConnectivityManager {
         }
         try {
             mService.releaseNetworkRequest(networkCallback.networkRequest);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -3044,7 +3083,9 @@ public class ConnectivityManager {
     public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
         try {
             mService.setAcceptUnvalidated(network, accept, always);
-        } catch (RemoteException e) {}
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -3055,6 +3096,7 @@ public class ConnectivityManager {
         try {
             mService.factoryReset();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -3262,7 +3304,7 @@ public class ConnectivityManager {
         try {
             return getNetworkPolicyManager().getRestrictBackgroundByCaller();
         } catch (RemoteException e) {
-            return RESTRICT_BACKGROUND_STATUS_DISABLED;
+            throw e.rethrowFromSystemServer();
         }
     }
 }
index d040a85..098f1e6 100644 (file)
 
 package android.net;
 
-import android.annotation.SystemApi;
 import android.os.Parcel;
 import android.os.Parcelable;
 
-@SystemApi
-public class ConnectivityMetricsEvent implements Parcelable {
+/** {@hide} */
+public final class ConnectivityMetricsEvent implements Parcelable {
 
     /**  The time when this event was collected, as returned by System.currentTimeMillis(). */
     final public long timestamp;
index 5e96cc1..8526584 100644 (file)
@@ -29,7 +29,7 @@ import java.util.Objects;
  * If no {@code uid}s are set, callbacks are restricted to device-owners,
  * carrier-privileged apps, or system apps.
  */
-public class DataUsageRequest implements Parcelable {
+public final class DataUsageRequest implements Parcelable {
 
     /**
      * @hide
index f45737a..664b7b4 100644 (file)
@@ -87,8 +87,8 @@ public class EthernetManager {
     public IpConfiguration getConfiguration() {
         try {
             return mService.getConfiguration();
-        } catch (NullPointerException | RemoteException e) {
-            return new IpConfiguration();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -98,7 +98,8 @@ public class EthernetManager {
     public void setConfiguration(IpConfiguration config) {
         try {
             mService.setConfiguration(config);
-        } catch (NullPointerException | RemoteException e) {
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -109,8 +110,8 @@ public class EthernetManager {
     public boolean isAvailable() {
         try {
             return mService.isAvailable();
-        } catch (NullPointerException | RemoteException e) {
-            return false;
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -127,7 +128,8 @@ public class EthernetManager {
         if (mListeners.size() == 1) {
             try {
                 mService.addListener(mServiceListener);
-            } catch (NullPointerException | RemoteException e) {
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -145,7 +147,8 @@ public class EthernetManager {
         if (mListeners.isEmpty()) {
             try {
                 mService.removeListener(mServiceListener);
-            } catch (NullPointerException | RemoteException e) {
+            } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
     }
index 20c2168..9e360e1 100644 (file)
@@ -200,6 +200,14 @@ public abstract class NetworkAgent extends Handler {
      */
     public static final int CMD_PREVENT_AUTOMATIC_RECONNECT = BASE + 15;
 
+    /**
+     * Sent by ConnectivityService to the NetworkAgent to install an APF program in the network
+     * chipset for use to filter packets.
+     *
+     * obj = byte[] containing the APF program bytecode.
+     */
+    public static final int CMD_PUSH_APF_PROGRAM = BASE + 16;
+
     public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
             NetworkCapabilities nc, LinkProperties lp, int score) {
         this(looper, context, logTag, ni, nc, lp, score, null);
@@ -319,6 +327,10 @@ public abstract class NetworkAgent extends Handler {
                 preventAutomaticReconnect();
                 break;
             }
+            case CMD_PUSH_APF_PROGRAM: {
+                installPacketFilter((byte[]) msg.obj);
+                break;
+            }
         }
     }
 
@@ -494,6 +506,15 @@ public abstract class NetworkAgent extends Handler {
     protected void preventAutomaticReconnect() {
     }
 
+    /**
+     * Install a packet filter.
+     * @param filter an APF program to filter incoming packets.
+     * @return {@code true} if filter successfully installed, {@code false} otherwise.
+     */
+    protected boolean installPacketFilter(byte[] filter) {
+        return false;
+    }
+
     protected void log(String s) {
         Log.d(LOG_TAG, "NetworkAgent: " + s);
     }
index 5511a24..748699e 100644 (file)
@@ -56,6 +56,22 @@ public class NetworkMisc implements Parcelable {
      */
     public String subscriberId;
 
+    /**
+     * Version of APF instruction set supported for packet filtering. 0 indicates no support for
+     * packet filtering using APF programs.
+     */
+    public int apfVersionSupported;
+
+    /**
+     * Maximum size of APF program allowed.
+     */
+    public int maximumApfProgramSize;
+
+    /**
+     * Format of packets passed to APF filter. Should be one of ARPHRD_*
+     */
+    public int apfPacketFormat;
+
     public NetworkMisc() {
     }
 
@@ -65,6 +81,9 @@ public class NetworkMisc implements Parcelable {
             explicitlySelected = nm.explicitlySelected;
             acceptUnvalidated = nm.acceptUnvalidated;
             subscriberId = nm.subscriberId;
+            apfVersionSupported = nm.apfVersionSupported;
+            maximumApfProgramSize = nm.maximumApfProgramSize;
+            apfPacketFormat = nm.apfPacketFormat;
         }
     }
 
@@ -79,6 +98,9 @@ public class NetworkMisc implements Parcelable {
         out.writeInt(explicitlySelected ? 1 : 0);
         out.writeInt(acceptUnvalidated ? 1 : 0);
         out.writeString(subscriberId);
+        out.writeInt(apfVersionSupported);
+        out.writeInt(maximumApfProgramSize);
+        out.writeInt(apfPacketFormat);
     }
 
     public static final Creator<NetworkMisc> CREATOR = new Creator<NetworkMisc>() {
@@ -89,6 +111,9 @@ public class NetworkMisc implements Parcelable {
             networkMisc.explicitlySelected = in.readInt() != 0;
             networkMisc.acceptUnvalidated = in.readInt() != 0;
             networkMisc.subscriberId = in.readString();
+            networkMisc.apfVersionSupported = in.readInt();
+            networkMisc.maximumApfProgramSize = in.readInt();
+            networkMisc.apfPacketFormat = in.readInt();
             return networkMisc;
         }
 
index 94de933..8738424 100644 (file)
@@ -68,10 +68,12 @@ public class NetworkPolicyManager {
     public static final int FIREWALL_CHAIN_NONE = 0;
     public static final int FIREWALL_CHAIN_DOZABLE = 1;
     public static final int FIREWALL_CHAIN_STANDBY = 2;
+    public static final int FIREWALL_CHAIN_POWERSAVE = 3;
 
     public static final String FIREWALL_CHAIN_NAME_NONE = "none";
     public static final String FIREWALL_CHAIN_NAME_DOZABLE = "dozable";
     public static final String FIREWALL_CHAIN_NAME_STANDBY = "standby";
+    public static final String FIREWALL_CHAIN_NAME_POWERSAVE = "powersave";
 
     private static final boolean ALLOW_PLATFORM_APP_POLICY = true;
 
index b6fe68a..01c160f 100644 (file)
@@ -166,7 +166,7 @@ public class NetworkScoreManager {
         try {
             return mService.updateScores(networks);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -186,7 +186,7 @@ public class NetworkScoreManager {
         try {
             return mService.clearScores();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -206,7 +206,7 @@ public class NetworkScoreManager {
         try {
             return mService.setActiveScorer(packageName);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -221,6 +221,7 @@ public class NetworkScoreManager {
         try {
             mService.disableScoring();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -265,6 +266,7 @@ public class NetworkScoreManager {
         try {
             mService.registerNetworkScoreCache(networkType, scoreCache);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 }
index c6d919f..555032d 100644 (file)
@@ -62,6 +62,13 @@ public class NetworkUtils {
     public native static void attachDhcpFilter(FileDescriptor fd) throws SocketException;
 
     /**
+     * Attaches a socket filter that accepts ICMP6 router advertisement packets to the given socket.
+     * @param fd the socket's {@link FileDescriptor}.
+     * @param packetType the hardware address type, one of ARPHRD_*.
+     */
+    public native static void attachRaFilter(FileDescriptor fd, int packetType) throws SocketException;
+
+    /**
      * Binds the current process to the network designated by {@code netId}.  All sockets created
      * in the future (and not explicitly bound via a bound {@link SocketFactory} (see
      * {@link Network#getSocketFactory}) will be bound to this network.  Note that if this
index 377ed88..86bd502 100644 (file)
@@ -619,7 +619,9 @@ public final class NsdManager {
     public void setEnabled(boolean enabled) {
         try {
             mService.setEnabled(enabled);
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -632,7 +634,7 @@ public final class NsdManager {
         try {
             return mService.getMessenger();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 }
index 56cb250..e40ebf7 100644 (file)
@@ -221,7 +221,7 @@ public class BatteryManager {
         try {
             return mBatteryStats.isCharging();
         } catch (RemoteException e) {
-            return true;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -246,7 +246,7 @@ public class BatteryManager {
             else
                 ret = Long.MIN_VALUE;
         } catch (RemoteException e) {
-            ret = Long.MIN_VALUE;
+            throw e.rethrowFromSystemServer();
         }
 
         return ret;
index fb16150..f382241 100644 (file)
@@ -2160,6 +2160,14 @@ href="{@docRoot}guide/developing/tools/traceview.html">Traceview: A Graphical Lo
     public static native void dumpNativeBacktraceToFile(int pid, String file);
 
     /**
+     * Get description of unreachable native memory.
+     * @param limit the number of leaks to provide info on, 0 to only get a summary.
+     * @param contents true to include a hex dump of the contents of unreachable memory.
+     * @return the String containing a description of unreachable memory.
+     * @hide */
+    public static native String getUnreachableMemory(int limit, boolean contents);
+
+    /**
      * Return a String describing the calling method and location at a particular stack depth.
      * @param callStack the Thread stack
      * @param depth the depth of stack to return information for.
index 1085b1e..307bd2d 100644 (file)
@@ -258,6 +258,20 @@ public class Environment {
         return buildPath(getDataDirectory(), "misc_de", String.valueOf(userId));
     }
 
+    private static File getDataProfilesDeDirectory(int userId) {
+        return buildPath(getDataDirectory(), "misc", "profiles", "cur", String.valueOf(userId));
+    }
+
+    /** {@hide} */
+    public static File getDataProfilesDePackageDirectory(int userId, String packageName) {
+        return buildPath(getDataProfilesDeDirectory(userId), packageName);
+    }
+
+    /** {@hide} */
+    public static File getDataProfilesDeForeignDexDirectory(int userId) {
+        return buildPath(getDataProfilesDeDirectory(userId), "foreign-dex");
+    }
+
     /** {@hide} */
     public static File getDataAppDirectory(String volumeUuid) {
         return new File(getDataDirectory(volumeUuid), "app");
@@ -493,7 +507,7 @@ public class Environment {
      * </ul>
      * @hide
      */
-    private static final String[] STANDARD_DIRECTORIES = {
+    public static final String[] STANDARD_DIRECTORIES = {
             DIRECTORY_MUSIC,
             DIRECTORY_PODCASTS,
             DIRECTORY_RINGTONES,
index f48306a..9ca1dcd 100644 (file)
@@ -79,8 +79,7 @@ public class HardwarePropertiesManager {
             try {
                 return mService.getDeviceTemperatures(mContext.getOpPackageName(), type);
             } catch (RemoteException e) {
-                Log.w(TAG, "Could not get device temperatures", e);
-                return new float[0];
+                throw e.rethrowFromSystemServer();
             }
         default:
             Log.w(TAG, "Unknown device temperature type.");
@@ -100,8 +99,7 @@ public class HardwarePropertiesManager {
         try {
             return mService.getCpuUsages(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.w(TAG, "Could not get CPU usages", e);
-            return new CpuUsageInfo[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -117,8 +115,7 @@ public class HardwarePropertiesManager {
         try {
             return mService.getFanSpeeds(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            Log.w(TAG, "Could not get fan speeds", e);
-            return new float[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 }
index 369ec15..2a4507c 100644 (file)
@@ -620,6 +620,7 @@ public final class PowerManager {
         try {
             mService.userActivity(when, event, flags);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -671,6 +672,7 @@ public final class PowerManager {
         try {
             mService.goToSleep(time, reason, flags);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -697,6 +699,7 @@ public final class PowerManager {
         try {
             mService.wakeUp(time, "wakeUp", mContext.getOpPackageName());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -707,6 +710,7 @@ public final class PowerManager {
         try {
             mService.wakeUp(time, reason, mContext.getOpPackageName());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -735,6 +739,7 @@ public final class PowerManager {
         try {
             mService.nap(time);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -757,6 +762,7 @@ public final class PowerManager {
         try {
             mService.boostScreenBrightness(time);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -772,7 +778,7 @@ public final class PowerManager {
         try {
             return mService.isScreenBrightnessBoosted();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -790,6 +796,7 @@ public final class PowerManager {
         try {
             mService.setTemporaryScreenBrightnessSettingOverride(brightness);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -803,7 +810,7 @@ public final class PowerManager {
         try {
             return mService.isWakeLockLevelSupported(level);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -867,7 +874,7 @@ public final class PowerManager {
         try {
             return mService.isInteractive();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -884,6 +891,7 @@ public final class PowerManager {
         try {
             mService.reboot(false, reason, true);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -899,7 +907,7 @@ public final class PowerManager {
         try {
             return mService.isPowerSaveMode();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -916,7 +924,7 @@ public final class PowerManager {
         try {
             return mService.setPowerSaveMode(mode);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -936,7 +944,7 @@ public final class PowerManager {
         try {
             return mService.isDeviceIdleMode();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -956,7 +964,7 @@ public final class PowerManager {
         try {
             return mService.isLightDeviceIdleMode();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -975,7 +983,7 @@ public final class PowerManager {
         try {
             return mIDeviceIdleController.isPowerSaveWhitelistApp(packageName);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -992,6 +1000,7 @@ public final class PowerManager {
         try {
             mService.shutdown(confirm, reason, wait);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1118,6 +1127,7 @@ public final class PowerManager {
                     try {
                         mService.releaseWakeLock(mToken, 0);
                     } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             }
@@ -1186,6 +1196,7 @@ public final class PowerManager {
                     mService.acquireWakeLock(mToken, mFlags, mTag, mPackageName, mWorkSource,
                             mHistoryTag);
                 } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
                 mHeld = true;
             }
@@ -1224,6 +1235,7 @@ public final class PowerManager {
                         try {
                             mService.releaseWakeLock(mToken, flags);
                         } catch (RemoteException e) {
+                            throw e.rethrowFromSystemServer();
                         }
                         mHeld = false;
                     }
@@ -1280,6 +1292,7 @@ public final class PowerManager {
                     try {
                         mService.updateWakeLockWorkSource(mToken, mWorkSource, mHistoryTag);
                     } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             }
index 9984755..8fd3b0c 100644 (file)
@@ -383,6 +383,9 @@ public class Process {
     public static final int SIGNAL_KILL = 9;
     public static final int SIGNAL_USR1 = 10;
 
+    private static long sStartElapsedRealtime;
+    private static long sStartUptimeMillis;
+
     /**
      * State for communicating with the zygote process.
      *
@@ -772,6 +775,26 @@ public class Process {
     public static final native long getElapsedCpuTime();
 
     /**
+     * Return the {@link SystemClock#elapsedRealtime()} at which this process was started.
+     */
+    public static final long getStartElapsedRealtime() {
+        return sStartElapsedRealtime;
+    }
+
+    /**
+     * Return the {@link SystemClock#uptimeMillis()} at which this process was started.
+     */
+    public static final long getStartUptimeMillis() {
+        return sStartUptimeMillis;
+    }
+
+    /** @hide */
+    public static final void setStartTimes(long elapsedRealtime, long uptimeMillis) {
+        sStartElapsedRealtime = elapsedRealtime;
+        sStartUptimeMillis = uptimeMillis;
+    }
+
+    /**
      * Returns true if the current process is a 64-bit runtime.
      */
     public static final boolean is64Bit() {
index 20f237a..04fca19 100644 (file)
@@ -20,20 +20,23 @@ package android.os;
  *
  * <p>This exception includes an error code specific to the throwing
  * service.  This is mostly used by system services to indicate
- * domain specific error conditions.
+ * domain specific error conditions.</p>
+ *
+ * <p>Since these exceptions are designed to be passed through Binder
+ * interfaces, and to be generated by native-code Binder services,
+ * they do not support exception chaining.</p>
  *
  * @hide
  */
 public class ServiceSpecificException extends RuntimeException {
     public final int errorCode;
 
-    ServiceSpecificException(int errorCode, String message) {
+    public ServiceSpecificException(int errorCode, String message) {
         super(message);
         this.errorCode = errorCode;
     }
 
-    ServiceSpecificException(int errorCode) {
+    public ServiceSpecificException(int errorCode) {
         this.errorCode = errorCode;
     }
 }
-
index 20b3798..7223dfb 100644 (file)
@@ -36,6 +36,7 @@ import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
+import android.telephony.TelephonyManager;
 import android.view.WindowManager.LayoutParams;
 
 import com.android.internal.R;
@@ -680,6 +681,22 @@ public class UserManager {
     }
 
     /**
+     * Returns whether switching users is currently allowed.
+     * <p>For instance switching users is not allowed if the current user is in a phone call,
+     * or system user hasn't been unlocked yet
+     * @hide
+     */
+    public boolean canSwitchUsers() {
+        boolean allowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
+                mContext.getContentResolver(),
+                Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
+        boolean isSystemUserUnlocked = isUserUnlocked(UserHandle.SYSTEM);
+        boolean inCall = TelephonyManager.getDefault().getCallState()
+                != TelephonyManager.CALL_STATE_IDLE;
+        return (allowUserSwitchingWhenSystemUserLocked || isSystemUserUnlocked) && !inCall;
+    }
+
+    /**
      * Returns the user handle for the user that this process is running under.
      *
      * @return the user handle of this process.
@@ -1641,7 +1658,7 @@ public class UserManager {
      * android.graphics.drawable.Drawable, UserHandle, android.graphics.Rect, int)}.
      * <p>
      * If the original drawable is a BitmapDrawable and the backing bitmap is
-     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
      * is performed in place and the original drawable is returned.
      * </p>
      *
@@ -1664,17 +1681,17 @@ public class UserManager {
      * badge to be used.
      * <p>
      * If the original drawable is a BitmapDrawable and the backing bitmap is
-     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the bading
+     * mutable as per {@link android.graphics.Bitmap#isMutable()}, the badging
      * is performed in place and the original drawable is returned.
      * </p>
      *
      * @param badgedDrawable The drawable to badge.
      * @param user The target user.
      * @param badgeLocation Where in the bounds of the badged drawable to place
-     *         the badge. If not provided, the badge is applied on top of the entire
+     *         the badge. If it's {@code null}, the badge is applied on top of the entire
      *         drawable being badged.
      * @param badgeDensity The optional desired density for the badge as per
-     *         {@link android.util.DisplayMetrics#densityDpi}. If not provided,
+     *         {@link android.util.DisplayMetrics#densityDpi}. If it's not positive,
      *         the density of the display is used.
      * @return A drawable that combines the original drawable and a badge as
      *         determined by the system.
index d860c7d..54d20d3 100644 (file)
@@ -76,7 +76,7 @@ import java.io.File;
  */
 // NOTE: This is a legacy specialization of VolumeInfo which describes the volume for a specific
 // user, but is now part of the public API.
-public class StorageVolume implements Parcelable {
+public final class StorageVolume implements Parcelable {
 
     private final String mId;
     private final int mStorageId;
index 4b70649..ea0597d 100644 (file)
@@ -438,10 +438,6 @@ public class VolumeInfo implements Parcelable {
         final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
         intent.setData(uri);
-
-        // note that docsui treats this as *force* show advanced. So sending
-        // false permits advanced to be shown based on user preferences.
-        intent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, isPrimary());
         intent.putExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, true);
         return intent;
     }
index b921351..0439fe2 100644 (file)
@@ -29,8 +29,11 @@ import android.os.Bundle;
  * <p>
  * The content provider exposes a table containing blocked numbers. The columns and URIs for
  * accessing this table are defined by the {@link BlockedNumbers} class. Messages, and calls from
- * blocked numbers are discarded by the platform. Notifications upon provider changes can be
- * received using a {@link android.database.ContentObserver}.
+ * blocked numbers are discarded by the platform. If the user contacts emergency
+ * services, number blocking is disabled by the platform for a duration defined by
+ * {@link android.telephony.CarrierConfigManager#KEY_DURATION_BLOCKING_DISABLED_AFTER_EMERGENCY_INT}.
+ * Notifications upon provider changes can be received using a
+ * {@link android.database.ContentObserver}.
  * </p>
  *
  * <h3> Permissions </h3>
@@ -141,25 +144,26 @@ public class BlockedNumberContract {
 
         /**
          * Content URI for the blocked numbers.
-         *
-         * Supported operations
-         * blocked
-         * - query
-         * - delete
-         * - insert
-         *
-         * blocked/ID
-         * - query (selection is not supported)
-         * - delete (selection is not supported)
+         * <h3> Supported operations </h3>
+         * <p> blocked
+         * <ul>
+         * <li> query
+         * <li> delete
+         * <li> insert
+         * </ul>
+         * <p> blocked/ID
+         * <ul>
+         * <li> query (selection is not supported)
+         * <li> delete (selection is not supported)
+         * </ul>
          */
-        public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI,
-                "blocked");
+        public static final Uri CONTENT_URI = Uri.withAppendedPath(AUTHORITY_URI, "blocked");
 
         /**
          * The MIME type of {@link #CONTENT_URI} itself providing a directory of blocked phone
          * numbers.
          */
-        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_numbers";
+        public static final String CONTENT_TYPE = "vnd.android.cursor.dir/blocked_number";
 
         /**
          * The MIME type of a blocked phone number under {@link #CONTENT_URI}.
@@ -215,7 +219,7 @@ public class BlockedNumberContract {
 
     /**
      * Returns {@code true} if blocking numbers is supported for the current user.
-     * <p> Typically, blocking numbers is only supported for the primary user.
+     * <p> Typically, blocking numbers is only supported for one user at a time.
      */
     public static boolean canCurrentUserBlockNumbers(Context context) {
         final Bundle res = context.getContentResolver().call(
@@ -292,6 +296,9 @@ public class BlockedNumberContract {
             return res != null && res.getBoolean(RES_NUMBER_IS_BLOCKED, false);
         }
 
+        /**
+         * Returns the current status of block suppression.
+         */
         public static BlockSuppressionStatus getBlockSuppressionStatus(Context context) {
             final Bundle res = context.getContentResolver().call(
                     AUTHORITY_URI, METHOD_GET_BLOCK_SUPPRESSION_STATUS, null, null);
index 904b393..4b43f53 100644 (file)
@@ -8763,6 +8763,15 @@ public final class ContactsContract {
          * <li><em>Note: Some apps may choose to use phone number as the unique contact ID in DATA1.
          * If this applies to you and you’d like phone number to be shown below the Contact Name by
          * the Voice Assistant, then you may choose to leave DATA3 empty.</em></li>
+         * <li><em>Note: If your app also uses DATA3 to display contact details in the Contacts App,
+         * make sure it does not include prefix text such as "Message +<phone>" or "Free Message
+         * +<phone>", etc. If you must show the prefix text in the Contacts App, please use a
+         * different DATA# column, and update your contacts.xml to point to this new column. </em>
+         * </li>
+         * <li>Everytime the user sends a message to a contact, your app may choose to update the
+         * {@link ContactOptionsColumns#TIMES_CONTACTED} entry through DataUsageFeedback class.
+         * Doing this will allow Voice Assistant to bias speech recognition to contacts frequently
+         * contacted, this is particularly useful for contact names that are hard to pronounce.</li>
          * </ul>
          * <p>
          * Input: {@link android.content.Intent#getType} is the MIME type of the data being sent.
index 3700098..0065cd9 100644 (file)
@@ -93,9 +93,6 @@ public final class DocumentsContract {
     public static final String EXTRA_PACKAGE_NAME = "android.content.extra.PACKAGE_NAME";
 
     /** {@hide} */
-    public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";
-
-    /** {@hide} */
     public static final String EXTRA_SHOW_FILESIZE = "android.content.extra.SHOW_FILESIZE";
 
     /** {@hide} */
@@ -481,7 +478,6 @@ public final class DocumentsContract {
         /**
          * Capacity of a root in bytes. This column is optional, and may be
          * {@code null} if unknown or unbounded.
-         * {@hide}
          * <p>
          * Type: INTEGER (long)
          */
@@ -564,22 +560,29 @@ public final class DocumentsContract {
         public static final int FLAG_EMPTY = 1 << 16;
 
         /**
-         * Flag indicating that this root should only be visible to advanced
-         * users.
+         * Flag indicating that this root has settings.
          *
          * @see #COLUMN_FLAGS
+         * @see DocumentsContract#ACTION_DOCUMENT_ROOT_SETTINGS
          * @hide
          */
-        public static final int FLAG_ADVANCED = 1 << 17;
+        public static final int FLAG_HAS_SETTINGS = 1 << 17;
 
         /**
-         * Flag indicating that this root has settings.
+         * Flag indicating that this root is on removable SD card storage.
+         *
+         * @see #COLUMN_FLAGS
+         * @hide
+         */
+        public static final int FLAG_REMOVABLE_SD = 1 << 18;
+
+        /**
+         * Flag indicating that this root is on removable USB storage.
          *
          * @see #COLUMN_FLAGS
-         * @see DocumentsContract#ACTION_DOCUMENT_ROOT_SETTINGS
          * @hide
          */
-        public static final int FLAG_HAS_SETTINGS = 1 << 18;
+        public static final int FLAG_REMOVABLE_USB = 1 << 19;
     }
 
     /**
index cb45deb..a40cf96 100755 (executable)
@@ -1241,6 +1241,19 @@ public final class Settings {
     public static final String ACTION_SHOW_ADMIN_SUPPORT_DETAILS
             = "android.settings.SHOW_ADMIN_SUPPORT_DETAILS";
 
+    /**
+     * Activity Action: Show a dialog for remote bugreport flow.
+     * <p>
+     * Input: Nothing.
+     * <p>
+     * Output: Nothing.
+     *
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SHOW_REMOTE_BUGREPORT_DIALOG
+            = "android.settings.SHOW_REMOTE_BUGREPORT_DIALOG";
+
     // End of Intent actions for Settings
 
     /**
@@ -4522,6 +4535,13 @@ public final class Settings {
         public static final String USER_SETUP_COMPLETE = "user_setup_complete";
 
         /**
+         * Prefix for category name that marks whether a suggested action from that category was
+         * completed.
+         * @hide
+         */
+        public static final String COMPLETED_CATEGORY_PREFIX = "suggested.completed_category.";
+
+        /**
          * List of input methods that are currently enabled.  This is a string
          * containing the IDs of all enabled input methods, each ID separated
          * by ':'.
index f5396a3..140341c 100644 (file)
@@ -51,6 +51,30 @@ public abstract class CarrierMessagingService extends Service {
             = "android.service.carrier.CarrierMessagingService";
 
     /**
+     * The default bitmask value passed to the callback of {@link #onReceiveTextSms} with all
+     * {@code RECEIVE_OPTIONS_x} flags cleared to indicate that the message should be kept and a
+     * new message notification should be shown.
+     *
+     * @see #RECEIVE_OPTIONS_DROP
+     * @see #RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE
+     */
+    public static final int RECEIVE_OPTIONS_DEFAULT = 0;
+
+    /**
+     * Used to set the flag in the bitmask passed to the callback of {@link #onReceiveTextSms} to
+     * indicate that the inbound SMS should be dropped.
+     */
+    public static final int RECEIVE_OPTIONS_DROP = 0x1;
+
+    /**
+     * Used to set the flag in the bitmask passed to the callback of {@link #onReceiveTextSms} to
+     * indicate that a new message notification should not be shown to the user when the
+     * credential-encrypted storage of the device is not available before the user unlocks the
+     * phone. It is only applicable to devices that support file-based encryption.
+     */
+    public static final int RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE = 0x2;
+
+    /**
      * Indicates that an SMS or MMS message was successfully sent.
      */
     public static final int SEND_STATUS_OK = 0;
@@ -96,7 +120,9 @@ public abstract class CarrierMessagingService extends Service {
      * @param subId SMS subscription ID of the SIM
      * @param callback result callback. Call with {@code true} to keep an inbound SMS message and
      *        deliver to SMS apps, and {@code false} to drop the message.
+     * @deprecated Use {@link #onReceiveTextSms} instead.
      */
+    @Deprecated
     public void onFilterSms(@NonNull MessagePdu pdu, @NonNull String format, int destPort,
             int subId, @NonNull ResultCallback<Boolean> callback) {
         // optional
@@ -107,6 +133,36 @@ public abstract class CarrierMessagingService extends Service {
     }
 
     /**
+     * Override this method to filter inbound SMS messages.
+     *
+     * <p>This method will be called once for every incoming text SMS. You can invoke the callback
+     * with a bitmask to tell the platform how to handle the SMS. For a SMS received on a
+     * file-based encryption capable device while the credential-encrypted storage is not available,
+     * this method will be called for the second time when the credential-encrypted storage becomes
+     * available after the user unlocks the phone, if the bit {@link #RECEIVE_OPTIONS_DROP} is not
+     * set when invoking the callback.
+     *
+     * @param pdu the PDUs of the message
+     * @param format the format of the PDUs, typically "3gpp" or "3gpp2"
+     * @param destPort the destination port of a binary SMS, this will be -1 for text SMS
+     * @param subId SMS subscription ID of the SIM
+     * @param callback result callback. Call with a bitmask integer to indicate how the incoming
+     *        text SMS should be handled by the platform. Use {@link #RECEIVE_OPTIONS_DROP} and
+     *        {@link #RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE}
+     *        to set the flags in the bitmask.
+     */
+    public void onReceiveTextSms(@NonNull MessagePdu pdu, @NonNull String format,
+            int destPort, int subId, @NonNull final ResultCallback<Integer> callback) {
+        onFilterSms(pdu, format, destPort, subId, new ResultCallback<Boolean>() {
+            @Override
+            public void onReceiveResult(Boolean result) throws RemoteException {
+                callback.onReceiveResult(result ? RECEIVE_OPTIONS_DEFAULT : RECEIVE_OPTIONS_DROP
+                    | RECEIVE_OPTIONS_SKIP_NOTIFY_WHEN_CREDENTIAL_ENCRYPTED_STORAGE_UNAVAILABLE);
+            }
+        });
+    }
+
+    /**
      * Override this method to intercept text SMSs sent from the device.
      * @deprecated Override {@link #onSendTextSms} below instead.
      *
@@ -408,10 +464,11 @@ public abstract class CarrierMessagingService extends Service {
         @Override
         public void filterSms(MessagePdu pdu, String format, int destPort,
                               int subId, final ICarrierMessagingCallback callback) {
-            onFilterSms(pdu, format, destPort, subId, new ResultCallback<Boolean>() {
+            onReceiveTextSms(pdu, format, destPort, subId,
+                new ResultCallback<Integer>() {
                     @Override
-                    public void onReceiveResult(final Boolean result) throws RemoteException {
-                        callback.onFilterComplete(result);
+                    public void onReceiveResult(Integer options) throws RemoteException {
+                        callback.onFilterComplete(options);
                     }
                 });
         }
index 6118a20..2753669 100644 (file)
@@ -22,7 +22,7 @@ package android.service.carrier;
  * @hide
  */
 oneway interface ICarrierMessagingCallback {
-    void onFilterComplete(boolean keepMessage);
+    void onFilterComplete(int result);
     void onSendSmsComplete(int result, int messageRef);
     void onSendMultipartSmsComplete(int result, in int[] messageRefs);
     void onSendMmsComplete(int result, in byte[] sendConfPdu);
index b5387f1..41af837 100644 (file)
@@ -18,18 +18,17 @@ package android.service.notification;
 
 import android.annotation.SdkConstant;
 import android.annotation.SystemApi;
-import android.app.INotificationManager;
-import android.app.Notification;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.Handler;
 import android.os.IBinder;
-import android.os.Parcel;
-import android.os.Parcelable;
+import android.os.Looper;
+import android.os.Message;
 import android.os.RemoteException;
-import android.os.ServiceManager;
 import android.util.Log;
+import com.android.internal.os.SomeArgs;
 
 /**
  * A service that helps the user manage notifications by modifying the
@@ -125,8 +124,24 @@ public abstract class NotificationAssistantService extends NotificationListenerS
         }
     }
 
+    private Handler mHandler;
+
+    /** @hide */
+    @Override
+    public void registerAsSystemService(Context context, ComponentName componentName,
+            int currentUser) throws RemoteException {
+        super.registerAsSystemService(context, componentName, currentUser);
+        mHandler = new MyHandler(getContext().getMainLooper());
+    }
+
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        mHandler = new MyHandler(getContext().getMainLooper());
+    }
+
     @Override
-    public IBinder onBind(Intent intent) {
+    public final IBinder onBind(Intent intent) {
         if (mWrapper == null) {
             mWrapper = new NotificationAssistantWrapper();
         }
@@ -198,8 +213,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS
      * @param key the notification key
      * @param adjustment the new importance with an explanation
      */
-    public final void adjustImportance(String key, Adjustment adjustment)
-    {
+    public final void adjustImportance(String key, Adjustment adjustment) {
         if (!isBound()) return;
         try {
             getNotificationInterface().setImportanceFromAssistant(mWrapper, key,
@@ -212,7 +226,7 @@ public abstract class NotificationAssistantService extends NotificationListenerS
     private class NotificationAssistantWrapper extends NotificationListenerWrapper {
         @Override
         public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
-                                           int importance, boolean user) throws RemoteException {
+                int importance, boolean user) {
             StatusBarNotification sbn;
             try {
                 sbn = sbnHolder.get();
@@ -221,54 +235,114 @@ public abstract class NotificationAssistantService extends NotificationListenerS
                 return;
             }
 
-            try {
-                Adjustment adjustment =
-                    NotificationAssistantService.this.onNotificationEnqueued(sbn, importance, user);
-                if (adjustment != null) {
-                    adjustImportance(sbn.getKey(), adjustment);
-                }
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationEnqueued", t);
-            }
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = sbn;
+            args.argi1 = importance;
+            args.argi2 = user ? 1 : 0;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ENQUEUED,
+                    args).sendToTarget();
         }
 
         @Override
-        public void onNotificationVisibilityChanged(String key, long time, boolean visible)
-                throws RemoteException {
-            try {
-                NotificationAssistantService.this.onNotificationVisibilityChanged(key, time,
-                        visible);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationVisibilityChanged", t);
-            }
+        public void onNotificationVisibilityChanged(String key, long time, boolean visible) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = key;
+            args.arg2 = time;
+            args.argi1 = visible ? 1 : 0;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_VISIBILITY_CHANGED,
+                    args).sendToTarget();
         }
 
         @Override
-        public void onNotificationClick(String key, long time) throws RemoteException {
-            try {
-                NotificationAssistantService.this.onNotificationClick(key, time);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationClick", t);
-            }
+        public void onNotificationClick(String key, long time) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = key;
+            args.arg2 = time;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_CLICK,
+                    args).sendToTarget();
         }
 
         @Override
-        public void onNotificationActionClick(String key, long time, int actionIndex)
-                throws RemoteException {
-            try {
-                NotificationAssistantService.this.onNotificationActionClick(key, time, actionIndex);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationActionClick", t);
-            }
+        public void onNotificationActionClick(String key, long time, int actionIndex) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = key;
+            args.arg2 = time;
+            args.argi1 = actionIndex;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_ACTION_CLICK,
+                    args).sendToTarget();
         }
 
         @Override
-        public void onNotificationRemovedReason(String key, long time, int reason)
-                throws RemoteException {
-            try {
-                NotificationAssistantService.this.onNotificationRemoved(key, time, reason);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onNotificationRemoved", t);
+        public void onNotificationRemovedReason(String key, long time, int reason) {
+            SomeArgs args = SomeArgs.obtain();
+            args.arg1 = key;
+            args.arg2 = time;
+            args.argi1 = reason;
+            mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED_REASON,
+                    args).sendToTarget();
+        }
+    }
+
+    private final class MyHandler extends Handler {
+        public static final int MSG_ON_NOTIFICATION_ENQUEUED = 1;
+        public static final int MSG_ON_NOTIFICATION_VISIBILITY_CHANGED = 2;
+        public static final int MSG_ON_NOTIFICATION_CLICK = 3;
+        public static final int MSG_ON_NOTIFICATION_ACTION_CLICK = 4;
+        public static final int MSG_ON_NOTIFICATION_REMOVED_REASON = 5;
+
+        public MyHandler(Looper looper) {
+            super(looper, null, false);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ON_NOTIFICATION_ENQUEUED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
+                    final int importance = args.argi1;
+                    final boolean user = args.argi2 == 1;
+                    args.recycle();
+                    Adjustment adjustment = onNotificationEnqueued(sbn, importance, user);
+                    if (adjustment != null) {
+                        adjustImportance(sbn.getKey(), adjustment);
+                    }
+                } break;
+
+                case MSG_ON_NOTIFICATION_VISIBILITY_CHANGED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    final String key = (String) args.arg1;
+                    final long time = (long) args.arg2;
+                    final boolean visible = args.argi1 == 1;
+                    args.recycle();
+                    onNotificationVisibilityChanged(key, time, visible);
+                } break;
+
+                case MSG_ON_NOTIFICATION_CLICK: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    final String key = (String) args.arg1;
+                    final long time = (long) args.arg2;
+                    args.recycle();
+                    onNotificationClick(key, time);
+                } break;
+
+                case MSG_ON_NOTIFICATION_ACTION_CLICK: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    final String key = (String) args.arg1;
+                    final long time = (long) args.arg2;
+                    final int actionIndex = args.argi1;
+                    args.recycle();
+                    onNotificationActionClick(key, time, actionIndex);
+                } break;
+
+                case MSG_ON_NOTIFICATION_REMOVED_REASON: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    final String key = (String) args.arg1;
+                    final long time = (long) args.arg2;
+                    final int reason = args.argi1;
+                    args.recycle();
+                    onNotificationRemoved(key, time, reason);
+                } break;
             }
         }
     }
index b4332e1..73a890f 100644 (file)
 
 package android.service.notification;
 
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+
 import android.annotation.IntDef;
 import android.annotation.SystemApi;
 import android.annotation.SdkConstant;
@@ -43,7 +47,8 @@ import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.Log;
 import android.widget.RemoteViews;
-
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.SomeArgs;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
@@ -163,8 +168,14 @@ public abstract class NotificationListenerService extends Service {
     @SystemApi
     public static final int TRIM_LIGHT = 1;
 
+    private final Object mLock = new Object();
+
+    private Handler mHandler;
+
     /** @hide */
     protected NotificationListenerWrapper mWrapper = null;
+
+    @GuardedBy("mLock")
     private RankingMap mRankingMap;
 
     private INotificationManager mNoMan;
@@ -195,6 +206,12 @@ public abstract class NotificationListenerService extends Service {
     public static final String CATEGORY_VR_NOTIFICATIONS =
         "android.intent.category.vr.notifications";
 
+    @Override
+    protected void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        mHandler = new MyHandler(getMainLooper());
+    }
+
     /**
      * Implement this method to learn about new notifications as they are posted by apps.
      *
@@ -642,7 +659,9 @@ public abstract class NotificationListenerService extends Service {
      * @return A {@link RankingMap} object providing access to ranking information
      */
     public RankingMap getCurrentRanking() {
-        return mRankingMap;
+        synchronized (mLock) {
+            return mRankingMap;
+        }
     }
 
     @Override
@@ -684,6 +703,7 @@ public abstract class NotificationListenerService extends Service {
         INotificationManager noMan = getNotificationInterface();
         noMan.registerListener(mWrapper, componentName, currentUser);
         mCurrentUser = currentUser;
+        mHandler = new MyHandler(context.getMainLooper());
     }
 
     /**
@@ -710,7 +730,7 @@ public abstract class NotificationListenerService extends Service {
      * <P>The service should wait for the {@link #onListenerConnected()} event
      * before performing any operations.
      */
-    public static final void requestRebind(ComponentName componentName)
+    public static void requestRebind(ComponentName componentName)
             throws RemoteException {
         INotificationManager noMan = INotificationManager.Stub.asInterface(
                 ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -782,7 +802,6 @@ public abstract class NotificationListenerService extends Service {
             }
 
             try {
-                Notification notification = sbn.getNotification();
                 // convert icon metadata to legacy format for older clients
                 createLegacyIconExtras(sbn.getNotification());
                 maybePopulateRemoteViews(sbn.getNotification());
@@ -794,20 +813,23 @@ public abstract class NotificationListenerService extends Service {
             }
 
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-            synchronized (mWrapper) {
-                applyUpdate(update);
-                try {
-                    if (sbn != null) {
-                        NotificationListenerService.this.onNotificationPosted(sbn, mRankingMap);
-                    } else {
-                        // still pass along the ranking map, it may contain other information
-                        NotificationListenerService.this.onNotificationRankingUpdate(mRankingMap);
-                    }
-                } catch (Throwable t) {
-                    Log.w(TAG, "Error running onNotificationPosted", t);
+            synchronized (mLock) {
+                applyUpdateLocked(update);
+                if (sbn != null) {
+                    SomeArgs args = SomeArgs.obtain();
+                    args.arg1 = sbn;
+                    args.arg2 = mRankingMap;
+                    mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_POSTED,
+                            args).sendToTarget();
+                } else {
+                    // still pass along the ranking map, it may contain other information
+                    mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
+                            mRankingMap).sendToTarget();
                 }
             }
+
         }
+
         @Override
         public void onNotificationRemoved(IStatusBarNotificationHolder sbnHolder,
                 NotificationRankingUpdate update) {
@@ -819,56 +841,48 @@ public abstract class NotificationListenerService extends Service {
                 return;
             }
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-            synchronized (mWrapper) {
-                applyUpdate(update);
-                try {
-                    NotificationListenerService.this.onNotificationRemoved(sbn, mRankingMap);
-                } catch (Throwable t) {
-                    Log.w(TAG, "Error running onNotificationRemoved", t);
-                }
+            synchronized (mLock) {
+                applyUpdateLocked(update);
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = sbn;
+                args.arg2 = mRankingMap;
+                mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_REMOVED,
+                        args).sendToTarget();
             }
+
         }
+
         @Override
         public void onListenerConnected(NotificationRankingUpdate update) {
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-            synchronized (mWrapper) {
-                applyUpdate(update);
-                try {
-                    NotificationListenerService.this.onListenerConnected();
-                } catch (Throwable t) {
-                    Log.w(TAG, "Error running onListenerConnected", t);
-                }
+            synchronized (mLock) {
+                applyUpdateLocked(update);
             }
+            mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_CONNECTED).sendToTarget();
         }
+
         @Override
         public void onNotificationRankingUpdate(NotificationRankingUpdate update)
                 throws RemoteException {
             // protect subclass from concurrent modifications of (@link mNotificationKeys}.
-            synchronized (mWrapper) {
-                applyUpdate(update);
-                try {
-                    NotificationListenerService.this.onNotificationRankingUpdate(mRankingMap);
-                } catch (Throwable t) {
-                    Log.w(TAG, "Error running onNotificationRankingUpdate", t);
-                }
+            synchronized (mLock) {
+                applyUpdateLocked(update);
+                mHandler.obtainMessage(MyHandler.MSG_ON_NOTIFICATION_RANKING_UPDATE,
+                        mRankingMap).sendToTarget();
             }
+
         }
+
         @Override
         public void onListenerHintsChanged(int hints) throws RemoteException {
-            try {
-                NotificationListenerService.this.onListenerHintsChanged(hints);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onListenerHintsChanged", t);
-            }
+            mHandler.obtainMessage(MyHandler.MSG_ON_LISTENER_HINTS_CHANGED,
+                    hints, 0).sendToTarget();
         }
 
         @Override
         public void onInterruptionFilterChanged(int interruptionFilter) throws RemoteException {
-            try {
-                NotificationListenerService.this.onInterruptionFilterChanged(interruptionFilter);
-            } catch (Throwable t) {
-                Log.w(TAG, "Error running onInterruptionFilterChanged", t);
-            }
+            mHandler.obtainMessage(MyHandler.MSG_ON_INTERRUPTION_FILTER_CHANGED,
+                    interruptionFilter, 0).sendToTarget();
         }
 
         @Override
@@ -901,11 +915,12 @@ public abstract class NotificationListenerService extends Service {
         }
     }
 
-    private void applyUpdate(NotificationRankingUpdate update) {
+    private void applyUpdateLocked(NotificationRankingUpdate update) {
         mRankingMap = new RankingMap(update);
     }
 
-    private Context getContext() {
+    /** @hide */
+    protected Context getContext() {
         if (mSystemContext != null) {
             return mSystemContext;
         }
@@ -1289,4 +1304,57 @@ public abstract class NotificationListenerService extends Service {
             }
         };
     }
+
+    private final class MyHandler extends Handler {
+        public static final int MSG_ON_NOTIFICATION_POSTED = 1;
+        public static final int MSG_ON_NOTIFICATION_REMOVED = 2;
+        public static final int MSG_ON_LISTENER_CONNECTED = 3;
+        public static final int MSG_ON_NOTIFICATION_RANKING_UPDATE = 4;
+        public static final int MSG_ON_LISTENER_HINTS_CHANGED = 5;
+        public static final int MSG_ON_INTERRUPTION_FILTER_CHANGED = 6;
+
+        public MyHandler(Looper looper) {
+            super(looper, null, false);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_ON_NOTIFICATION_POSTED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
+                    RankingMap rankingMap = (RankingMap) args.arg2;
+                    args.recycle();
+                    onNotificationPosted(sbn, rankingMap);
+                } break;
+
+                case MSG_ON_NOTIFICATION_REMOVED: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    StatusBarNotification sbn = (StatusBarNotification) args.arg1;
+                    RankingMap rankingMap = (RankingMap) args.arg2;
+                    args.recycle();
+                    onNotificationRemoved(sbn, rankingMap);
+                } break;
+
+                case MSG_ON_LISTENER_CONNECTED: {
+                    onListenerConnected();
+                } break;
+
+                case MSG_ON_NOTIFICATION_RANKING_UPDATE: {
+                    RankingMap rankingMap = (RankingMap) msg.obj;
+                    onNotificationRankingUpdate(rankingMap);
+                } break;
+
+                case MSG_ON_LISTENER_HINTS_CHANGED: {
+                    final int hints = msg.arg1;
+                    onListenerHintsChanged(hints);
+                } break;
+
+                case MSG_ON_INTERRUPTION_FILTER_CHANGED: {
+                    final int interruptionFilter = msg.arg1;
+                    onInterruptionFilterChanged(interruptionFilter);
+                } break;
+            }
+        }
+    }
 }
index c73b75e..4644103 100644 (file)
@@ -17,4 +17,5 @@
 package android.service.notification;
 
 parcelable ZenModeConfig;
+parcelable ZenModeConfig.ZenRule;
 
index 97939a9..27315ee 100644 (file)
@@ -1017,7 +1017,7 @@ public class ZenModeConfig implements Parcelable {
     public static class ZenRule implements Parcelable {
         public boolean enabled;
         public boolean snoozing;         // user manually disabled this instance
-        public String name;              // required for automatic (unique)
+        public String name;              // required for automatic
         public int zenMode;
         public Uri conditionId;          // required for automatic
         public Condition condition;      // optional
index e79dfca..3564e11 100644 (file)
@@ -16,6 +16,7 @@
 
 package android.text.method;
 
+import android.graphics.Paint;
 import android.icu.lang.UCharacter;
 import android.icu.lang.UProperty;
 import android.view.KeyEvent;
@@ -25,6 +26,8 @@ import android.text.method.TextKeyListener.Capitalize;
 import android.text.style.ReplacementSpan;
 import android.widget.TextView;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.text.BreakIterator;
 import java.util.Arrays;
 import java.util.Collections;
@@ -45,6 +48,11 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
         implements KeyListener {
     /* package */ static final Object OLD_SEL_START = new NoCopySpan.Concrete();
 
+    private final Object mLock = new Object();
+
+    @GuardedBy("mLock")
+    static Paint sCachedPaint = null;
+
     /**
      * Performs the action that happens when you press the {@link KeyEvent#KEYCODE_DEL} key in
      * a {@link TextView}.  If there is a selection, deletes the selection; otherwise,
@@ -258,20 +266,15 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
     }
 
     // Returns the end offset to be deleted by a forward delete key from the given offset.
-    private static int getOffsetForForwardDeleteKey(CharSequence text, int offset) {
+    private static int getOffsetForForwardDeleteKey(CharSequence text, int offset, Paint paint) {
         final int len = text.length();
 
         if (offset >= len - 1) {
             return len;
         }
 
-        int codePoint = Character.codePointAt(text, offset);
-        offset += Character.charCount(codePoint);
-        if (offset == len) {
-            return len;
-        }
-
-        // TODO: Handle emoji, combining chars, etc.
+        offset = paint.getTextRunCursor(text, offset, len, Paint.DIRECTION_LTR /* not used */,
+                offset, Paint.CURSOR_AFTER);
 
         return adjustReplacementSpan(text, offset, false /* move to the end */);
     }
@@ -311,7 +314,18 @@ public abstract class BaseKeyListener extends MetaKeyKeyListener
         final int start = Selection.getSelectionEnd(content);
         final int end;
         if (isForwardDelete) {
-            end = getOffsetForForwardDeleteKey(content, start);
+            final Paint paint;
+            if (view instanceof TextView) {
+                paint = ((TextView)view).getPaint();
+            } else {
+                synchronized (mLock) {
+                    if (sCachedPaint == null) {
+                        sCachedPaint = new Paint();
+                    }
+                    paint = sCachedPaint;
+                }
+            }
+            end = getOffsetForForwardDeleteKey(content, start, paint);
         } else {
             end = getOffsetForBackspaceKey(content, start);
         }
index fbd9924..bd376ea 100644 (file)
@@ -224,7 +224,7 @@ public class Linkify {
         }
 
         if ((mask & EMAIL_ADDRESSES) != 0) {
-            gatherLinks(links, text, Patterns.EMAIL_ADDRESS,
+            gatherLinks(links, text, Patterns.AUTOLINK_EMAIL_ADDRESS,
                 new String[] { "mailto:" },
                 null, null);
         }
index bdb1fdc..92a5803 100644 (file)
@@ -67,7 +67,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {
     /**
      * @hide Special immutable empty ArrayMap.
      */
-    public static final ArrayMap EMPTY = new ArrayMap(true);
+    public static final ArrayMap EMPTY = new ArrayMap<>(-1);
 
     /**
      * Caches of small array objects to avoid spamming garbage.  The cache
@@ -80,6 +80,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {
     static Object[] mTwiceBaseCache;
     static int mTwiceBaseCacheSize;
 
+    final boolean mIdentityHashCode;
     int[] mHashes;
     Object[] mArray;
     int mSize;
@@ -236,30 +237,32 @@ public final class ArrayMap<K, V> implements Map<K, V> {
      * will grow once items are added to it.
      */
     public ArrayMap() {
-        mHashes = EmptyArray.INT;
-        mArray = EmptyArray.OBJECT;
-        mSize = 0;
+        this(0, false);
     }
 
     /**
      * Create a new ArrayMap with a given initial capacity.
      */
     public ArrayMap(int capacity) {
-        if (capacity == 0) {
-            mHashes = EmptyArray.INT;
-            mArray = EmptyArray.OBJECT;
-        } else {
-            allocArrays(capacity);
-        }
-        mSize = 0;
+        this(capacity, false);
     }
 
-    private ArrayMap(boolean immutable) {
+    /** {@hide} */
+    public ArrayMap(int capacity, boolean identityHashCode) {
+        mIdentityHashCode = identityHashCode;
+
         // If this is immutable, use the sentinal EMPTY_IMMUTABLE_INTS
         // instance instead of the usual EmptyArray.INT. The reference
         // is checked later to see if the array is allowed to grow.
-        mHashes = immutable ? EMPTY_IMMUTABLE_INTS : EmptyArray.INT;
-        mArray = EmptyArray.OBJECT;
+        if (capacity < 0) {
+            mHashes = EMPTY_IMMUTABLE_INTS;
+            mArray = EmptyArray.OBJECT;
+        } else if (capacity == 0) {
+            mHashes = EmptyArray.INT;
+            mArray = EmptyArray.OBJECT;
+        } else {
+            allocArrays(capacity);
+        }
         mSize = 0;
     }
 
@@ -336,7 +339,8 @@ public final class ArrayMap<K, V> implements Map<K, V> {
      * @return Returns the index of the key if it exists, else a negative integer.
      */
     public int indexOfKey(Object key) {
-        return key == null ? indexOfNull() : indexOf(key, key.hashCode());
+        return key == null ? indexOfNull()
+                : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
     }
 
     int indexOfValue(Object value) {
@@ -437,7 +441,7 @@ public final class ArrayMap<K, V> implements Map<K, V> {
             hash = 0;
             index = indexOfNull();
         } else {
-            hash = key.hashCode();
+            hash = mIdentityHashCode ? System.identityHashCode(key) : key.hashCode();
             index = indexOf(key, hash);
         }
         if (index >= 0) {
@@ -488,7 +492,8 @@ public final class ArrayMap<K, V> implements Map<K, V> {
      */
     public void append(K key, V value) {
         int index = mSize;
-        final int hash = key == null ? 0 : key.hashCode();
+        final int hash = key == null ? 0
+                : (mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
         if (index >= mHashes.length) {
             throw new IllegalStateException("Array is full");
         }
index b7a3c42..9e9314f 100644 (file)
@@ -69,6 +69,7 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
     static Object[] mTwiceBaseCache;
     static int mTwiceBaseCacheSize;
 
+    final boolean mIdentityHashCode;
     int[] mHashes;
     Object[] mArray;
     int mSize;
@@ -222,15 +223,19 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
      * will grow once items are added to it.
      */
     public ArraySet() {
-        mHashes = EmptyArray.INT;
-        mArray = EmptyArray.OBJECT;
-        mSize = 0;
+        this(0, false);
     }
 
     /**
      * Create a new ArraySet with a given initial capacity.
      */
     public ArraySet(int capacity) {
+        this(capacity, false);
+    }
+
+    /** {@hide} */
+    public ArraySet(int capacity, boolean identityHashCode) {
+        mIdentityHashCode = identityHashCode;
         if (capacity == 0) {
             mHashes = EmptyArray.INT;
             mArray = EmptyArray.OBJECT;
@@ -306,7 +311,8 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
      * @return Returns the index of the value if it exists, else a negative integer.
      */
     public int indexOf(Object key) {
-        return key == null ? indexOfNull() : indexOf(key, key.hashCode());
+        return key == null ? indexOfNull()
+                : indexOf(key, mIdentityHashCode ? System.identityHashCode(key) : key.hashCode());
     }
 
     /**
@@ -343,7 +349,7 @@ public final class ArraySet<E> implements Collection<E>, Set<E> {
             hash = 0;
             index = indexOfNull();
         } else {
-            hash = value.hashCode();
+            hash = mIdentityHashCode ? System.identityHashCode(value) : value.hashCode();
             index = indexOf(value, hash);
         }
         if (index >= 0) {
index fc39004..fa3921c 100644 (file)
@@ -478,8 +478,6 @@ public final class LocaleList implements Parcelable {
     /**
      * Returns the default locale list, adjusted by moving the default locale to its first
      * position.
-     *
-     * {@hide}
      */
     @NonNull @Size(min=1)
     public static LocaleList getAdjustedDefault() {
index 9f2bcfd..9ed4850 100644 (file)
@@ -394,6 +394,36 @@ public class Patterns {
     public static final Pattern AUTOLINK_WEB_URL = Pattern.compile(
             "(" + WEB_URL_WITH_PROTOCOL + "|" + WEB_URL_WITHOUT_PROTOCOL + ")");
 
+    /**
+     * Regular expression for valid email characters. Does not include some of the valid characters
+     * defined in RFC5321: #&~!^`{}/=$*?|
+     */
+    private static final String EMAIL_CHAR = LABEL_CHAR + "\\+\\-_%'";
+
+    /**
+     * Regular expression for local part of an email address. RFC5321 section 4.5.3.1.1 limits
+     * the local part to be at most 64 octets.
+     */
+    private static final String EMAIL_ADDRESS_LOCAL_PART =
+            "[" + EMAIL_CHAR + "]" + "(?:[" + EMAIL_CHAR + "\\.]{1,62}[" + EMAIL_CHAR + "])?";
+
+    /**
+     * Regular expression for the domain part of an email address. RFC5321 section 4.5.3.1.2 limits
+     * the domain to be at most 255 octets.
+     */
+    private static final String EMAIL_ADDRESS_DOMAIN =
+            "(?=.{1,255}(?:\\s|$|^))" + HOST_NAME;
+
+    /**
+     * Regular expression pattern to match email addresses. It excludes double quoted local parts
+     * and the special characters #&~!^`{}/=$*?| that are included in RFC5321.
+     * @hide
+     */
+    public static final Pattern AUTOLINK_EMAIL_ADDRESS = Pattern.compile("(" + WORD_BOUNDARY +
+            "(?:" + EMAIL_ADDRESS_LOCAL_PART + "@" + EMAIL_ADDRESS_DOMAIN + ")" +
+            WORD_BOUNDARY + ")"
+    );
+
     public static final Pattern EMAIL_ADDRESS
         = Pattern.compile(
             "[a-zA-Z0-9\\+\\.\\_\\%\\-\\+]{1,256}" +
index 728f723..60c7270 100644 (file)
@@ -75,6 +75,36 @@ public class ApkSignatureSchemeV2Verifier {
     public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 2;
 
     /**
+     * Returns {@code true} if the provided APK contains an APK Signature Scheme V2
+     * signature. The signature will not be verified.
+     */
+    public static boolean hasSignature(String apkFile) throws IOException {
+        try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) {
+            long fileSize = apk.length();
+            if (fileSize > Integer.MAX_VALUE) {
+                return false;
+            }
+            MappedByteBuffer apkContents =
+                    apk.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, fileSize);
+            // ZipUtils and APK Signature Scheme v2 verifier expect little-endian byte order.
+            apkContents.order(ByteOrder.LITTLE_ENDIAN);
+
+            final int centralDirOffset =
+                    (int) getCentralDirOffset(apkContents, getEocdOffset(apkContents));
+            // Find the APK Signing Block.
+            int apkSigningBlockOffset = findApkSigningBlock(apkContents, centralDirOffset);
+            ByteBuffer apkSigningBlock =
+                    sliceFromTo(apkContents, apkSigningBlockOffset, centralDirOffset);
+
+            // Find the APK Signature Scheme v2 Block inside the APK Signing Block.
+            findApkSignatureSchemeV2Block(apkSigningBlock);
+            return true;
+        } catch (SignatureNotFoundException e) {
+        }
+        return false;
+    }
+
+    /**
      * Verifies APK Signature Scheme v2 signatures of the provided APK and returns the certificates
      * associated with each signer.
      *
@@ -130,31 +160,8 @@ public class ApkSignatureSchemeV2Verifier {
         // ZipUtils and APK Signature Scheme v2 verifier expect little-endian byte order.
         apkContents.order(ByteOrder.LITTLE_ENDIAN);
 
-        // Find the offset of ZIP End of Central Directory (EoCD)
-        int eocdOffset = ZipUtils.findZipEndOfCentralDirectoryRecord(apkContents);
-        if (eocdOffset == -1) {
-            throw new SignatureNotFoundException(
-                    "Not an APK file: ZIP End of Central Directory record not found");
-        }
-        if (ZipUtils.isZip64EndOfCentralDirectoryLocatorPresent(apkContents, eocdOffset)) {
-            throw new SignatureNotFoundException("ZIP64 APK not supported");
-        }
-        ByteBuffer eocd = sliceFromTo(apkContents, eocdOffset, apkContents.capacity());
-
-        // Look up the offset of ZIP Central Directory.
-        long centralDirOffsetLong = ZipUtils.getZipEocdCentralDirectoryOffset(eocd);
-        if (centralDirOffsetLong >= eocdOffset) {
-            throw new SignatureNotFoundException(
-                    "ZIP Central Directory offset out of range: " + centralDirOffsetLong
-                    + ". ZIP End of Central Directory offset: " + eocdOffset);
-        }
-        long centralDirSizeLong = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
-        if (centralDirOffsetLong + centralDirSizeLong != eocdOffset) {
-            throw new SignatureNotFoundException(
-                    "ZIP Central Directory is not immediately followed by End of Central"
-                    + " Directory");
-        }
-        int centralDirOffset = (int) centralDirOffsetLong;
+        final int eocdOffset = getEocdOffset(apkContents);
+        final int centralDirOffset = (int) getCentralDirOffset(apkContents, eocdOffset);
 
         // Find the APK Signing Block.
         int apkSigningBlockOffset = findApkSigningBlock(apkContents, centralDirOffset);
@@ -499,6 +506,43 @@ public class ApkSignatureSchemeV2Verifier {
         return result;
     }
 
+    /**
+     * Finds the offset of ZIP End of Central Directory (EoCD).
+     *
+     * @throws SignatureNotFoundException If the EoCD could not be found
+     */
+    private static int getEocdOffset(ByteBuffer apkContents) throws SignatureNotFoundException {
+        int eocdOffset = ZipUtils.findZipEndOfCentralDirectoryRecord(apkContents);
+        if (eocdOffset == -1) {
+            throw new SignatureNotFoundException(
+                    "Not an APK file: ZIP End of Central Directory record not found");
+        }
+        return eocdOffset;
+    }
+
+    private static long getCentralDirOffset(ByteBuffer apkContents, int eocdOffset)
+            throws SignatureNotFoundException {
+        if (ZipUtils.isZip64EndOfCentralDirectoryLocatorPresent(apkContents, eocdOffset)) {
+            throw new SignatureNotFoundException("ZIP64 APK not supported");
+        }
+        ByteBuffer eocd = sliceFromTo(apkContents, eocdOffset, apkContents.capacity());
+
+        // Look up the offset of ZIP Central Directory.
+        long centralDirOffsetLong = ZipUtils.getZipEocdCentralDirectoryOffset(eocd);
+        if (centralDirOffsetLong >= eocdOffset) {
+            throw new SignatureNotFoundException(
+                    "ZIP Central Directory offset out of range: " + centralDirOffsetLong
+                    + ". ZIP End of Central Directory offset: " + eocdOffset);
+        }
+        long centralDirSizeLong = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocd);
+        if (centralDirOffsetLong + centralDirSizeLong != eocdOffset) {
+            throw new SignatureNotFoundException(
+                    "ZIP Central Directory is not immediately followed by End of Central"
+                    + " Directory");
+        }
+        return centralDirOffsetLong;
+    }
+
     private static final int getChunkCount(int inputSizeBytes) {
         return (inputSizeBytes + CHUNK_SIZE_BYTES - 1) / CHUNK_SIZE_BYTES;
     }
index 9543acf..8048301 100644 (file)
@@ -167,7 +167,7 @@ interface IWindowManager
             in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
             int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
     void setAppVisibility(IBinder token, boolean visible);
-    void notifyAppStopped(IBinder token);
+    void notifyAppStopped(IBinder token, boolean stopped);
     void startAppFreezingScreen(IBinder token, int configChanges);
     void stopAppFreezingScreen(IBinder token, boolean force);
     void removeAppToken(IBinder token);
index b58c68f..aa86c03 100644 (file)
@@ -36,6 +36,7 @@ public class SurfaceControl {
             throws OutOfResourcesException;
     private static native void nativeRelease(long nativeObject);
     private static native void nativeDestroy(long nativeObject);
+    private static native void nativeDisconnect(long nativeObject);
 
     private static native Bitmap nativeScreenshot(IBinder displayToken,
             Rect sourceCrop, int width, int height, int minLayer, int maxLayer,
@@ -341,6 +342,15 @@ public class SurfaceControl {
         mCloseGuard.close();
     }
 
+    /**
+     * Disconnect any client still connected to the surface.
+     */
+    public void disconnect() {
+        if (mNativeObject != 0) {
+            nativeDisconnect(mNativeObject);
+        }
+    }
+
     private void checkNotReleased() {
         if (mNativeObject == 0) throw new NullPointerException(
                 "mNativeObject is null. Have you called release() already?");
index e7be7af..9bd3df0 100644 (file)
@@ -10270,6 +10270,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
     }
 
     /**
+     * Like {@link #getWindowVisibleDisplayFrame}, but returns the "full" display frame this window
+     * is currently in without any insets.
+     *
+     * @hide
+     */
+    public void getWindowDisplayFrame(Rect outRect) {
+        if (mAttachInfo != null) {
+            try {
+                mAttachInfo.mSession.getDisplayFrame(mAttachInfo.mWindow, outRect);
+            } catch (RemoteException e) {
+                return;
+            }
+            return;
+        }
+        // The view is not attached to a display so we don't have a context.
+        // Make a best guess about the display size.
+        Display d = DisplayManagerGlobal.getInstance().getRealDisplay(Display.DEFAULT_DISPLAY);
+        d.getRectSize(outRect);
+    }
+
+    /**
      * Dispatch a notification about a resource configuration change down
      * the view hierarchy.
      * ViewGroups should override to route to their children.
index c5b1653..afe2f10 100644 (file)
@@ -4398,8 +4398,14 @@ public final class ViewRootImpl implements ViewParent,
     private boolean updatePointerIcon(MotionEvent event) {
         final float x = event.getX();
         final float y = event.getY();
+        if (mView == null) {
+            // E.g. click outside a popup to dismiss it
+            Slog.d(mTag, "updatePointerIcon called after view was removed");
+            return false;
+        }
         if (x < 0 || x >= mView.getWidth() || y < 0 || y >= mView.getHeight()) {
-            Slog.e(mTag, "updatePointerIcon called with position out of bounds");
+            // E.g. when moving window divider with mouse
+            Slog.d(mTag, "updatePointerIcon called with position out of bounds");
             return false;
         }
         final PointerIcon pointerIcon = mView.getPointerIcon(event, x, y);
index 65c7654..42d1442 100644 (file)
@@ -21,13 +21,22 @@ import android.os.Handler;
 import android.view.KeyEvent;
 
 /**
- * <p>Wrapper class for proxying calls to another InputConnection.  Subclass
- * and have fun!
+ * <p>Wrapper class for proxying calls to another InputConnection.  Subclass and have fun!
  */
 public class InputConnectionWrapper implements InputConnection {
     private InputConnection mTarget;
     final boolean mMutable;
-    
+
+    /**
+     * Initializes a wrapper.
+     *
+     * <p><b>Caveat:</b> Although the system can accept {@code (InputConnection) null} in some
+     * places, you cannot emulate such a behavior by non-null {@link InputConnectionWrapper} that
+     * has {@code null} in {@code target}.</p>
+     * @param target the {@link InputConnection} to be proxied.
+     * @param mutable set {@code true} to protect this object from being reconfigured to target
+     * another {@link InputConnection}.  Note that this is ignored while the target is {@code null}.
+     */
     public InputConnectionWrapper(InputConnection target, boolean mutable) {
         mMutable = mutable;
         mTarget = target;
@@ -35,6 +44,12 @@ public class InputConnectionWrapper implements InputConnection {
 
     /**
      * Change the target of the input connection.
+     *
+     * <p><b>Caveat:</b> Although the system can accept {@code (InputConnection) null} in some
+     * places, you cannot emulate such a behavior by non-null {@link InputConnectionWrapper} that
+     * has {@code null} in {@code target}.</p>
+     * @param target the {@link InputConnection} to be proxied.
+     * @throws SecurityException when this wrapper has non-null target and is immutable.
      */
     public void setTarget(InputConnection target) {
         if (mTarget != null && !mMutable) {
@@ -42,99 +57,195 @@ public class InputConnectionWrapper implements InputConnection {
         }
         mTarget = target;
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public CharSequence getTextBeforeCursor(int n, int flags) {
         return mTarget.getTextBeforeCursor(n, flags);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public CharSequence getTextAfterCursor(int n, int flags) {
         return mTarget.getTextAfterCursor(n, flags);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public CharSequence getSelectedText(int flags) {
         return mTarget.getSelectedText(flags);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public int getCursorCapsMode(int reqModes) {
         return mTarget.getCursorCapsMode(reqModes);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
         return mTarget.getExtractedText(request, flags);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean deleteSurroundingTextInCodePoints(int beforeLength, int afterLength) {
         return mTarget.deleteSurroundingTextInCodePoints(beforeLength, afterLength);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean deleteSurroundingText(int beforeLength, int afterLength) {
         return mTarget.deleteSurroundingText(beforeLength, afterLength);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean setComposingText(CharSequence text, int newCursorPosition) {
         return mTarget.setComposingText(text, newCursorPosition);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean setComposingRegion(int start, int end) {
         return mTarget.setComposingRegion(start, end);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean finishComposingText() {
         return mTarget.finishComposingText();
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean commitText(CharSequence text, int newCursorPosition) {
         return mTarget.commitText(text, newCursorPosition);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean commitCompletion(CompletionInfo text) {
         return mTarget.commitCompletion(text);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean commitCorrection(CorrectionInfo correctionInfo) {
         return mTarget.commitCorrection(correctionInfo);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean setSelection(int start, int end) {
         return mTarget.setSelection(start, end);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean performEditorAction(int editorAction) {
         return mTarget.performEditorAction(editorAction);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean performContextMenuAction(int id) {
         return mTarget.performContextMenuAction(id);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean beginBatchEdit() {
         return mTarget.beginBatchEdit();
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean endBatchEdit() {
         return mTarget.endBatchEdit();
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean sendKeyEvent(KeyEvent event) {
         return mTarget.sendKeyEvent(event);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean clearMetaKeyStates(int states) {
         return mTarget.clearMetaKeyStates(states);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean reportFullscreenMode(boolean enabled) {
         return mTarget.reportFullscreenMode(enabled);
     }
-    
+
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean performPrivateCommand(String action, Bundle data) {
         return mTarget.performPrivateCommand(action, data);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public boolean requestCursorUpdates(int cursorUpdateMode) {
         return mTarget.requestCursorUpdates(cursorUpdateMode);
     }
 
+    /**
+     * {@inheritDoc}
+     * @throws NullPointerException if the target is {@code null}.
+     */
     public Handler getHandler() {
         return mTarget.getHandler();
     }
index 4c015ba..859df43 100644 (file)
@@ -664,7 +664,7 @@ public final class InputMethodManager {
         try {
             return mService.getInputMethodList();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -672,7 +672,7 @@ public final class InputMethodManager {
         try {
             return mService.getEnabledInputMethodList();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -689,7 +689,7 @@ public final class InputMethodManager {
             return mService.getEnabledInputMethodSubtypeList(
                     imi == null ? null : imi.getId(), allowsImplicitlySelectedSubtypes);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -697,7 +697,7 @@ public final class InputMethodManager {
         try {
             mService.updateStatusIcon(imeToken, packageName, iconId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -705,7 +705,7 @@ public final class InputMethodManager {
         try {
             mService.updateStatusIcon(imeToken, null, 0);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -714,7 +714,7 @@ public final class InputMethodManager {
         try {
             mService.setImeWindowStatus(imeToken, vis, backDisposition);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -728,7 +728,7 @@ public final class InputMethodManager {
         try {
             mService.registerSuggestionSpansForNotification(spans);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -737,7 +737,7 @@ public final class InputMethodManager {
         try {
             mService.notifySuggestionPicked(span, originalString, index);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -833,6 +833,7 @@ public final class InputMethodManager {
                 try {
                     mService.finishInput(mClient);
                 } catch (RemoteException e) {
+                    throw e.rethrowFromSystemServer();
                 }
             }
             notifyInputConnectionFinished();
@@ -996,9 +997,8 @@ public final class InputMethodManager {
             try {
                 return mService.showSoftInput(mClient, flags, resultReceiver);
             } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
-            
-            return false;
         }
     }
     
@@ -1007,6 +1007,7 @@ public final class InputMethodManager {
         try {
             mService.showSoftInput(mClient, flags, resultReceiver);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
     
@@ -1065,8 +1066,8 @@ public final class InputMethodManager {
             try {
                 return mService.hideSoftInput(mClient, flags, resultReceiver);
             } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
-            return false;
         }
     }
     
@@ -1421,6 +1422,7 @@ public final class InputMethodManager {
         try {
             mService.hideSoftInput(mClient, HIDE_NOT_ALWAYS, null);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1476,6 +1478,7 @@ public final class InputMethodManager {
                         rootView.getWindowToken(), controlFlags, softInputMode, windowFlags, null,
                         null);
             } catch (RemoteException e) {
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1716,7 +1719,7 @@ public final class InputMethodManager {
         try {
             mService.setInputMethod(token, id);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1733,7 +1736,7 @@ public final class InputMethodManager {
         try {
             mService.setInputMethodAndSubtype(token, id, subtype);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1753,7 +1756,7 @@ public final class InputMethodManager {
         try {
             mService.hideMySoftInput(token, flags);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
     
@@ -1774,7 +1777,7 @@ public final class InputMethodManager {
         try {
             mService.showMySoftInput(token, flags);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1980,7 +1983,7 @@ public final class InputMethodManager {
                         SHOW_IM_PICKER_MODE_EXCLUDE_AUXILIARY_SUBTYPES;
                 mService.showInputMethodPickerFromClient(mClient, mode);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1989,7 +1992,7 @@ public final class InputMethodManager {
         try {
             mService.showInputMethodPickerFromClient(mClient, SHOW_IM_PICKER_MODE_AUTO);
         } catch (RemoteException e) {
-            Log.w(TAG, "IME died: " + mCurId, e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2003,7 +2006,7 @@ public final class InputMethodManager {
             try {
                 mService.showInputMethodAndSubtypeEnablerFromClient(mClient, imiId);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2018,8 +2021,7 @@ public final class InputMethodManager {
             try {
                 return mService.getCurrentInputMethodSubtype();
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return null;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2036,8 +2038,7 @@ public final class InputMethodManager {
             try {
                 return mService.setCurrentInputMethodSubtype(subtype);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return false;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2071,7 +2072,7 @@ public final class InputMethodManager {
                 mLastSentUserActionNotificationSequenceNumber =
                         mNextUserActionNotificationSequenceNumber;
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2104,7 +2105,7 @@ public final class InputMethodManager {
                     }
                 }
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+                throw e.rethrowFromSystemServer();
             }
             return ret;
         }
@@ -2119,8 +2120,7 @@ public final class InputMethodManager {
             try {
                 return mService.getInputMethodWindowVisibleHeight();
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return 0;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2139,8 +2139,7 @@ public final class InputMethodManager {
             try {
                 return mService.switchToLastInputMethod(imeToken);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return false;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2160,8 +2159,7 @@ public final class InputMethodManager {
             try {
                 return mService.switchToNextInputMethod(imeToken, onlyCurrentIme);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return false;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2182,8 +2180,7 @@ public final class InputMethodManager {
             try {
                 return mService.shouldOfferSwitchingToNextInputMethod(imeToken);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return false;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2218,7 +2215,7 @@ public final class InputMethodManager {
             try {
                 mService.setAdditionalInputMethodSubtypes(imiId, subtypes);
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -2228,8 +2225,7 @@ public final class InputMethodManager {
             try {
                 return mService.getLastInputMethodSubtype();
             } catch (RemoteException e) {
-                Log.w(TAG, "IME died: " + mCurId, e);
-                return null;
+                throw e.rethrowFromSystemServer();
             }
         }
     }
index 496f7ee..d2aef0a 100644 (file)
@@ -3078,7 +3078,8 @@ public abstract class AbsListView extends AdapterView<ListAdapter> implements Te
             final int motionPosition = mClickMotionPosition;
             if (adapter != null && mItemCount > 0 &&
                     motionPosition != INVALID_POSITION &&
-                    motionPosition < adapter.getCount() && sameWindow()) {
+                    motionPosition < adapter.getCount() && sameWindow() &&
+                    adapter.isEnabled(motionPosition)) {
                 final View view = getChildAt(motionPosition - mFirstPosition);
                 // If there is no view, something bad happened (the view scrolled off the
                 // screen, etc.) and we should cancel the click
index 87bee44..6e3dbd8 100644 (file)
@@ -23,32 +23,17 @@ import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.text.TextUtils;
-import android.text.InputType;
-import android.text.format.DateFormat;
-import android.text.format.DateUtils;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.util.SparseArray;
-import android.view.LayoutInflater;
 import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
-import android.view.inputmethod.EditorInfo;
-import android.view.inputmethod.InputMethodManager;
-import android.widget.NumberPicker.OnValueChangeListener;
 
 import com.android.internal.R;
 
-import java.text.DateFormatSymbols;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Locale;
 import java.util.TimeZone;
 
-import libcore.icu.ICU;
-
 /**
  * Provides a widget for selecting a date.
  * <p>
@@ -527,674 +512,123 @@ public class DatePicker extends FrameLayout {
         protected void onLocaleChanged(Locale locale) {
             // Stub.
         }
-    }
-
-    /**
-     * A callback interface for updating input validity when the date picker
-     * when included into a dialog.
-     *
-     * @hide
-     */
-    public static interface ValidationCallback {
-        void onValidationChanged(boolean valid);
-    }
-
-    /**
-     * A delegate implementing the basic DatePicker
-     */
-    private static class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
-
-        private static final String DATE_FORMAT = "MM/dd/yyyy";
-
-        private static final int DEFAULT_START_YEAR = 1900;
-
-        private static final int DEFAULT_END_YEAR = 2100;
-
-        private static final boolean DEFAULT_CALENDAR_VIEW_SHOWN = true;
-
-        private static final boolean DEFAULT_SPINNERS_SHOWN = true;
-
-        private static final boolean DEFAULT_ENABLED_STATE = true;
-
-        private final LinearLayout mSpinners;
-
-        private final NumberPicker mDaySpinner;
-
-        private final NumberPicker mMonthSpinner;
-
-        private final NumberPicker mYearSpinner;
-
-        private final EditText mDaySpinnerInput;
-
-        private final EditText mMonthSpinnerInput;
 
-        private final EditText mYearSpinnerInput;
-
-        private final CalendarView mCalendarView;
-
-        private String[] mShortMonths;
-
-        private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
-
-        private int mNumberOfMonths;
-
-        private Calendar mTempDate;
-
-        private Calendar mMinDate;
-
-        private Calendar mMaxDate;
-
-        private Calendar mCurrentDate;
-
-        private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
-
-        DatePickerSpinnerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
-                int defStyleAttr, int defStyleRes) {
-            super(delegator, context);
-
-            mDelegator = delegator;
-            mContext = context;
-
-            // initialization based on locale
-            setCurrentLocale(Locale.getDefault());
-
-            final TypedArray attributesArray = context.obtainStyledAttributes(attrs,
-                    R.styleable.DatePicker, defStyleAttr, defStyleRes);
-            boolean spinnersShown = attributesArray.getBoolean(R.styleable.DatePicker_spinnersShown,
-                    DEFAULT_SPINNERS_SHOWN);
-            boolean calendarViewShown = attributesArray.getBoolean(
-                    R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN);
-            int startYear = attributesArray.getInt(R.styleable.DatePicker_startYear,
-                    DEFAULT_START_YEAR);
-            int endYear = attributesArray.getInt(R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
-            String minDate = attributesArray.getString(R.styleable.DatePicker_minDate);
-            String maxDate = attributesArray.getString(R.styleable.DatePicker_maxDate);
-            int layoutResourceId = attributesArray.getResourceId(
-                    R.styleable.DatePicker_legacyLayout, R.layout.date_picker_legacy);
-            attributesArray.recycle();
-
-            LayoutInflater inflater = (LayoutInflater) context
-                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            inflater.inflate(layoutResourceId, mDelegator, true);
-
-            OnValueChangeListener onChangeListener = new OnValueChangeListener() {
-                public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
-                    updateInputState();
-                    mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
-                    // take care of wrapping of days and months to update greater fields
-                    if (picker == mDaySpinner) {
-                        int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
-                        if (oldVal == maxDayOfMonth && newVal == 1) {
-                            mTempDate.add(Calendar.DAY_OF_MONTH, 1);
-                        } else if (oldVal == 1 && newVal == maxDayOfMonth) {
-                            mTempDate.add(Calendar.DAY_OF_MONTH, -1);
-                        } else {
-                            mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
-                        }
-                    } else if (picker == mMonthSpinner) {
-                        if (oldVal == 11 && newVal == 0) {
-                            mTempDate.add(Calendar.MONTH, 1);
-                        } else if (oldVal == 0 && newVal == 11) {
-                            mTempDate.add(Calendar.MONTH, -1);
-                        } else {
-                            mTempDate.add(Calendar.MONTH, newVal - oldVal);
-                        }
-                    } else if (picker == mYearSpinner) {
-                        mTempDate.set(Calendar.YEAR, newVal);
-                    } else {
-                        throw new IllegalArgumentException();
-                    }
-                    // now set the date to the adjusted one
-                    setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
-                            mTempDate.get(Calendar.DAY_OF_MONTH));
-                    updateSpinners();
-                    updateCalendarView();
-                    notifyDateChanged();
-                }
-            };
-
-            mSpinners = (LinearLayout) mDelegator.findViewById(R.id.pickers);
-
-            // calendar view day-picker
-            mCalendarView = (CalendarView) mDelegator.findViewById(R.id.calendar_view);
-            mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
-                public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) {
-                    setDate(year, month, monthDay);
-                    updateSpinners();
-                    notifyDateChanged();
-                }
-            });
-
-            // day
-            mDaySpinner = (NumberPicker) mDelegator.findViewById(R.id.day);
-            mDaySpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
-            mDaySpinner.setOnLongPressUpdateInterval(100);
-            mDaySpinner.setOnValueChangedListener(onChangeListener);
-            mDaySpinnerInput = (EditText) mDaySpinner.findViewById(R.id.numberpicker_input);
-
-            // month
-            mMonthSpinner = (NumberPicker) mDelegator.findViewById(R.id.month);
-            mMonthSpinner.setMinValue(0);
-            mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
-            mMonthSpinner.setDisplayedValues(mShortMonths);
-            mMonthSpinner.setOnLongPressUpdateInterval(200);
-            mMonthSpinner.setOnValueChangedListener(onChangeListener);
-            mMonthSpinnerInput = (EditText) mMonthSpinner.findViewById(R.id.numberpicker_input);
-
-            // year
-            mYearSpinner = (NumberPicker) mDelegator.findViewById(R.id.year);
-            mYearSpinner.setOnLongPressUpdateInterval(100);
-            mYearSpinner.setOnValueChangedListener(onChangeListener);
-            mYearSpinnerInput = (EditText) mYearSpinner.findViewById(R.id.numberpicker_input);
-
-            // show only what the user required but make sure we
-            // show something and the spinners have higher priority
-            if (!spinnersShown && !calendarViewShown) {
-                setSpinnersShown(true);
-            } else {
-                setSpinnersShown(spinnersShown);
-                setCalendarViewShown(calendarViewShown);
+        /**
+         * Class for managing state storing/restoring.
+         */
+        static class SavedState extends View.BaseSavedState {
+            private final int mSelectedYear;
+            private final int mSelectedMonth;
+            private final int mSelectedDay;
+            private final long mMinDate;
+            private final long mMaxDate;
+            private final int mCurrentView;
+            private final int mListPosition;
+            private final int mListPositionOffset;
+
+            public SavedState(Parcelable superState, int year, int month, int day, long minDate,
+                    long maxDate) {
+                this(superState, year, month, day, minDate, maxDate, 0, 0, 0);
             }
 
-            // set the min date giving priority of the minDate over startYear
-            mTempDate.clear();
-            if (!TextUtils.isEmpty(minDate)) {
-                if (!parseDate(minDate, mTempDate)) {
-                    mTempDate.set(startYear, 0, 1);
-                }
-            } else {
-                mTempDate.set(startYear, 0, 1);
+            /**
+             * Constructor called from {@link DatePicker#onSaveInstanceState()}
+             */
+            public SavedState(Parcelable superState, int year, int month, int day, long minDate,
+                    long maxDate, int currentView, int listPosition, int listPositionOffset) {
+                super(superState);
+                mSelectedYear = year;
+                mSelectedMonth = month;
+                mSelectedDay = day;
+                mMinDate = minDate;
+                mMaxDate = maxDate;
+                mCurrentView = currentView;
+                mListPosition = listPosition;
+                mListPositionOffset = listPositionOffset;
             }
-            setMinDate(mTempDate.getTimeInMillis());
 
-            // set the max date giving priority of the maxDate over endYear
-            mTempDate.clear();
-            if (!TextUtils.isEmpty(maxDate)) {
-                if (!parseDate(maxDate, mTempDate)) {
-                    mTempDate.set(endYear, 11, 31);
-                }
-            } else {
-                mTempDate.set(endYear, 11, 31);
+            /**
+             * Constructor called from {@link #CREATOR}
+             */
+            private SavedState(Parcel in) {
+                super(in);
+                mSelectedYear = in.readInt();
+                mSelectedMonth = in.readInt();
+                mSelectedDay = in.readInt();
+                mMinDate = in.readLong();
+                mMaxDate = in.readLong();
+                mCurrentView = in.readInt();
+                mListPosition = in.readInt();
+                mListPositionOffset = in.readInt();
             }
-            setMaxDate(mTempDate.getTimeInMillis());
 
-            // initialize to current date
-            mCurrentDate.setTimeInMillis(System.currentTimeMillis());
-            init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), mCurrentDate
-                    .get(Calendar.DAY_OF_MONTH), null);
-
-            // re-order the number spinners to match the current date format
-            reorderSpinners();
-
-            // accessibility
-            setContentDescriptions();
-
-            // If not explicitly specified this view is important for accessibility.
-            if (mDelegator.getImportantForAccessibility() == IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
-                mDelegator.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES);
+            @Override
+            public void writeToParcel(Parcel dest, int flags) {
+                super.writeToParcel(dest, flags);
+                dest.writeInt(mSelectedYear);
+                dest.writeInt(mSelectedMonth);
+                dest.writeInt(mSelectedDay);
+                dest.writeLong(mMinDate);
+                dest.writeLong(mMaxDate);
+                dest.writeInt(mCurrentView);
+                dest.writeInt(mListPosition);
+                dest.writeInt(mListPositionOffset);
             }
-        }
-
-        @Override
-        public void init(int year, int monthOfYear, int dayOfMonth,
-                         OnDateChangedListener onDateChangedListener) {
-            setDate(year, monthOfYear, dayOfMonth);
-            updateSpinners();
-            updateCalendarView();
-            mOnDateChangedListener = onDateChangedListener;
-        }
 
-        @Override
-        public void updateDate(int year, int month, int dayOfMonth) {
-            if (!isNewDate(year, month, dayOfMonth)) {
-                return;
+            public int getSelectedDay() {
+                return mSelectedDay;
             }
-            setDate(year, month, dayOfMonth);
-            updateSpinners();
-            updateCalendarView();
-            notifyDateChanged();
-        }
-
-        @Override
-        public int getYear() {
-            return mCurrentDate.get(Calendar.YEAR);
-        }
-
-        @Override
-        public int getMonth() {
-            return mCurrentDate.get(Calendar.MONTH);
-        }
 
-        @Override
-        public int getDayOfMonth() {
-            return mCurrentDate.get(Calendar.DAY_OF_MONTH);
-        }
-
-        @Override
-        public void setFirstDayOfWeek(int firstDayOfWeek) {
-            mCalendarView.setFirstDayOfWeek(firstDayOfWeek);
-        }
-
-        @Override
-        public int getFirstDayOfWeek() {
-            return mCalendarView.getFirstDayOfWeek();
-        }
-
-        @Override
-        public void setMinDate(long minDate) {
-            mTempDate.setTimeInMillis(minDate);
-            if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
-                    && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
-                return;
-            }
-            mMinDate.setTimeInMillis(minDate);
-            mCalendarView.setMinDate(minDate);
-            if (mCurrentDate.before(mMinDate)) {
-                mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
-                updateCalendarView();
+            public int getSelectedMonth() {
+                return mSelectedMonth;
             }
-            updateSpinners();
-        }
-
-        @Override
-        public Calendar getMinDate() {
-            final Calendar minDate = Calendar.getInstance();
-            minDate.setTimeInMillis(mCalendarView.getMinDate());
-            return minDate;
-        }
 
-        @Override
-        public void setMaxDate(long maxDate) {
-            mTempDate.setTimeInMillis(maxDate);
-            if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
-                    && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
-                return;
-            }
-            mMaxDate.setTimeInMillis(maxDate);
-            mCalendarView.setMaxDate(maxDate);
-            if (mCurrentDate.after(mMaxDate)) {
-                mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
-                updateCalendarView();
+            public int getSelectedYear() {
+                return mSelectedYear;
             }
-            updateSpinners();
-        }
-
-        @Override
-        public Calendar getMaxDate() {
-            final Calendar maxDate = Calendar.getInstance();
-            maxDate.setTimeInMillis(mCalendarView.getMaxDate());
-            return maxDate;
-        }
-
-        @Override
-        public void setEnabled(boolean enabled) {
-            mDaySpinner.setEnabled(enabled);
-            mMonthSpinner.setEnabled(enabled);
-            mYearSpinner.setEnabled(enabled);
-            mCalendarView.setEnabled(enabled);
-            mIsEnabled = enabled;
-        }
-
-        @Override
-        public boolean isEnabled() {
-            return mIsEnabled;
-        }
-
-        @Override
-        public CalendarView getCalendarView() {
-            return mCalendarView;
-        }
-
-        @Override
-        public void setCalendarViewShown(boolean shown) {
-            mCalendarView.setVisibility(shown ? VISIBLE : GONE);
-        }
-
-        @Override
-        public boolean getCalendarViewShown() {
-            return (mCalendarView.getVisibility() == View.VISIBLE);
-        }
 
-        @Override
-        public void setSpinnersShown(boolean shown) {
-            mSpinners.setVisibility(shown ? VISIBLE : GONE);
-        }
-
-        @Override
-        public boolean getSpinnersShown() {
-            return mSpinners.isShown();
-        }
-
-        @Override
-        public void onConfigurationChanged(Configuration newConfig) {
-            setCurrentLocale(newConfig.locale);
-        }
-
-        @Override
-        public Parcelable onSaveInstanceState(Parcelable superState) {
-            return new SavedState(superState, getYear(), getMonth(), getDayOfMonth());
-        }
-
-        @Override
-        public void onRestoreInstanceState(Parcelable state) {
-            SavedState ss = (SavedState) state;
-            setDate(ss.mYear, ss.mMonth, ss.mDay);
-            updateSpinners();
-            updateCalendarView();
-        }
-
-        @Override
-        public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
-            onPopulateAccessibilityEvent(event);
-            return true;
-        }
-
-        @Override
-        public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
-            final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
-            String selectedDateUtterance = DateUtils.formatDateTime(mContext,
-                    mCurrentDate.getTimeInMillis(), flags);
-            event.getText().add(selectedDateUtterance);
-        }
-
-        /**
-         * Sets the current locale.
-         *
-         * @param locale The current locale.
-         */
-        @Override
-        protected void setCurrentLocale(Locale locale) {
-            super.setCurrentLocale(locale);
-
-            mTempDate = getCalendarForLocale(mTempDate, locale);
-            mMinDate = getCalendarForLocale(mMinDate, locale);
-            mMaxDate = getCalendarForLocale(mMaxDate, locale);
-            mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
-
-            mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
-            mShortMonths = new DateFormatSymbols().getShortMonths();
-
-            if (usingNumericMonths()) {
-                // We're in a locale where a date should either be all-numeric, or all-text.
-                // All-text would require custom NumberPicker formatters for day and year.
-                mShortMonths = new String[mNumberOfMonths];
-                for (int i = 0; i < mNumberOfMonths; ++i) {
-                    mShortMonths[i] = String.format("%d", i + 1);
-                }
+            public long getMinDate() {
+                return mMinDate;
             }
-        }
 
-        /**
-         * Tests whether the current locale is one where there are no real month names,
-         * such as Chinese, Japanese, or Korean locales.
-         */
-        private boolean usingNumericMonths() {
-            return Character.isDigit(mShortMonths[Calendar.JANUARY].charAt(0));
-        }
-
-        /**
-         * Gets a calendar for locale bootstrapped with the value of a given calendar.
-         *
-         * @param oldCalendar The old calendar.
-         * @param locale The locale.
-         */
-        private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
-            if (oldCalendar == null) {
-                return Calendar.getInstance(locale);
-            } else {
-                final long currentTimeMillis = oldCalendar.getTimeInMillis();
-                Calendar newCalendar = Calendar.getInstance(locale);
-                newCalendar.setTimeInMillis(currentTimeMillis);
-                return newCalendar;
+            public long getMaxDate() {
+                return mMaxDate;
             }
-        }
 
-        /**
-         * Reorders the spinners according to the date format that is
-         * explicitly set by the user and if no such is set fall back
-         * to the current locale's default format.
-         */
-        private void reorderSpinners() {
-            mSpinners.removeAllViews();
-            // We use numeric spinners for year and day, but textual months. Ask icu4c what
-            // order the user's locale uses for that combination. http://b/7207103.
-            String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), "yyyyMMMdd");
-            char[] order = ICU.getDateFormatOrder(pattern);
-            final int spinnerCount = order.length;
-            for (int i = 0; i < spinnerCount; i++) {
-                switch (order[i]) {
-                    case 'd':
-                        mSpinners.addView(mDaySpinner);
-                        setImeOptions(mDaySpinner, spinnerCount, i);
-                        break;
-                    case 'M':
-                        mSpinners.addView(mMonthSpinner);
-                        setImeOptions(mMonthSpinner, spinnerCount, i);
-                        break;
-                    case 'y':
-                        mSpinners.addView(mYearSpinner);
-                        setImeOptions(mYearSpinner, spinnerCount, i);
-                        break;
-                    default:
-                        throw new IllegalArgumentException(Arrays.toString(order));
-                }
+            public int getCurrentView() {
+                return mCurrentView;
             }
-        }
-
-        /**
-         * Parses the given <code>date</code> and in case of success sets the result
-         * to the <code>outDate</code>.
-         *
-         * @return True if the date was parsed.
-         */
-        private boolean parseDate(String date, Calendar outDate) {
-            try {
-                outDate.setTime(mDateFormat.parse(date));
-                return true;
-            } catch (ParseException e) {
-                Log.w(LOG_TAG, "Date: " + date + " not in format: " + DATE_FORMAT);
-                return false;
-            }
-        }
-
-        private boolean isNewDate(int year, int month, int dayOfMonth) {
-            return (mCurrentDate.get(Calendar.YEAR) != year
-                    || mCurrentDate.get(Calendar.MONTH) != month
-                    || mCurrentDate.get(Calendar.DAY_OF_MONTH) != dayOfMonth);
-        }
 
-        private void setDate(int year, int month, int dayOfMonth) {
-            mCurrentDate.set(year, month, dayOfMonth);
-            if (mCurrentDate.before(mMinDate)) {
-                mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
-            } else if (mCurrentDate.after(mMaxDate)) {
-                mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
+            public int getListPosition() {
+                return mListPosition;
             }
-        }
 
-        private void updateSpinners() {
-            // set the spinner ranges respecting the min and max dates
-            if (mCurrentDate.equals(mMinDate)) {
-                mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
-                mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
-                mDaySpinner.setWrapSelectorWheel(false);
-                mMonthSpinner.setDisplayedValues(null);
-                mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
-                mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
-                mMonthSpinner.setWrapSelectorWheel(false);
-            } else if (mCurrentDate.equals(mMaxDate)) {
-                mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH));
-                mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
-                mDaySpinner.setWrapSelectorWheel(false);
-                mMonthSpinner.setDisplayedValues(null);
-                mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
-                mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
-                mMonthSpinner.setWrapSelectorWheel(false);
-            } else {
-                mDaySpinner.setMinValue(1);
-                mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
-                mDaySpinner.setWrapSelectorWheel(true);
-                mMonthSpinner.setDisplayedValues(null);
-                mMonthSpinner.setMinValue(0);
-                mMonthSpinner.setMaxValue(11);
-                mMonthSpinner.setWrapSelectorWheel(true);
+            public int getListPositionOffset() {
+                return mListPositionOffset;
             }
 
-            // make sure the month names are a zero based array
-            // with the months in the month spinner
-            String[] displayedValues = Arrays.copyOfRange(mShortMonths,
-                    mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
-            mMonthSpinner.setDisplayedValues(displayedValues);
-
-            // year spinner range does not change based on the current date
-            mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
-            mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
-            mYearSpinner.setWrapSelectorWheel(false);
-
-            // set the spinner values
-            mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
-            mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
-            mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
+            @SuppressWarnings("all")
+            // suppress unused and hiding
+            public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
 
-            if (usingNumericMonths()) {
-                mMonthSpinnerInput.setRawInputType(InputType.TYPE_CLASS_NUMBER);
-            }
-        }
-
-        /**
-         * Updates the calendar view with the current date.
-         */
-        private void updateCalendarView() {
-            mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false);
-        }
-
-
-        /**
-         * Notifies the listener, if such, for a change in the selected date.
-         */
-        private void notifyDateChanged() {
-            mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
-            if (mOnDateChangedListener != null) {
-                mOnDateChangedListener.onDateChanged(mDelegator, getYear(), getMonth(),
-                        getDayOfMonth());
-            }
-        }
-
-        /**
-         * Sets the IME options for a spinner based on its ordering.
-         *
-         * @param spinner The spinner.
-         * @param spinnerCount The total spinner count.
-         * @param spinnerIndex The index of the given spinner.
-         */
-        private void setImeOptions(NumberPicker spinner, int spinnerCount, int spinnerIndex) {
-            final int imeOptions;
-            if (spinnerIndex < spinnerCount - 1) {
-                imeOptions = EditorInfo.IME_ACTION_NEXT;
-            } else {
-                imeOptions = EditorInfo.IME_ACTION_DONE;
-            }
-            TextView input = (TextView) spinner.findViewById(R.id.numberpicker_input);
-            input.setImeOptions(imeOptions);
-        }
-
-        private void setContentDescriptions() {
-            // Day
-            trySetContentDescription(mDaySpinner, R.id.increment,
-                    R.string.date_picker_increment_day_button);
-            trySetContentDescription(mDaySpinner, R.id.decrement,
-                    R.string.date_picker_decrement_day_button);
-            // Month
-            trySetContentDescription(mMonthSpinner, R.id.increment,
-                    R.string.date_picker_increment_month_button);
-            trySetContentDescription(mMonthSpinner, R.id.decrement,
-                    R.string.date_picker_decrement_month_button);
-            // Year
-            trySetContentDescription(mYearSpinner, R.id.increment,
-                    R.string.date_picker_increment_year_button);
-            trySetContentDescription(mYearSpinner, R.id.decrement,
-                    R.string.date_picker_decrement_year_button);
-        }
-
-        private void trySetContentDescription(View root, int viewId, int contDescResId) {
-            View target = root.findViewById(viewId);
-            if (target != null) {
-                target.setContentDescription(mContext.getString(contDescResId));
-            }
-        }
+                public SavedState createFromParcel(Parcel in) {
+                    return new SavedState(in);
+                }
 
-        private void updateInputState() {
-            // Make sure that if the user changes the value and the IME is active
-            // for one of the inputs if this widget, the IME is closed. If the user
-            // changed the value via the IME and there is a next input the IME will
-            // be shown, otherwise the user chose another means of changing the
-            // value and having the IME up makes no sense.
-            InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
-            if (inputMethodManager != null) {
-                if (inputMethodManager.isActive(mYearSpinnerInput)) {
-                    mYearSpinnerInput.clearFocus();
-                    inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-                } else if (inputMethodManager.isActive(mMonthSpinnerInput)) {
-                    mMonthSpinnerInput.clearFocus();
-                    inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
-                } else if (inputMethodManager.isActive(mDaySpinnerInput)) {
-                    mDaySpinnerInput.clearFocus();
-                    inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+                public SavedState[] newArray(int size) {
+                    return new SavedState[size];
                 }
-            }
+            };
         }
     }
 
     /**
-     * Class for managing state storing/restoring.
+     * A callback interface for updating input validity when the date picker
+     * when included into a dialog.
+     *
+     * @hide
      */
-    private static class SavedState extends BaseSavedState {
-
-        private final int mYear;
-
-        private final int mMonth;
-
-        private final int mDay;
-
-        /**
-         * Constructor called from {@link DatePicker#onSaveInstanceState()}
-         */
-        private SavedState(Parcelable superState, int year, int month, int day) {
-            super(superState);
-            mYear = year;
-            mMonth = month;
-            mDay = day;
-        }
-
-        /**
-         * Constructor called from {@link #CREATOR}
-         */
-        private SavedState(Parcel in) {
-            super(in);
-            mYear = in.readInt();
-            mMonth = in.readInt();
-            mDay = in.readInt();
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeInt(mYear);
-            dest.writeInt(mMonth);
-            dest.writeInt(mDay);
-        }
-
-        @SuppressWarnings("all")
-        // suppress unused and hiding
-        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
-
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
+    public interface ValidationCallback {
+        void onValidationChanged(boolean valid);
     }
 }
index cbb6109..5adac01 100755 (executable)
 
 package android.widget;
 
+import com.android.internal.R;
+
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
@@ -37,8 +38,6 @@ import android.view.accessibility.AccessibilityEvent;
 import android.widget.DayPickerView.OnDaySelectedListener;
 import android.widget.YearPickerView.OnYearSelectedListener;
 
-import com.android.internal.R;
-
 import java.text.SimpleDateFormat;
 import java.util.Calendar;
 import java.util.Locale;
@@ -550,25 +549,27 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
-        final SavedState ss = (SavedState) state;
-
-        // TODO: Move instance state into DayPickerView, YearPickerView.
-        mCurrentDate.set(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay());
-        mMinDate.setTimeInMillis(ss.getMinDate());
-        mMaxDate.setTimeInMillis(ss.getMaxDate());
-
-        onCurrentDateChanged(false);
-
-        final int currentView = ss.getCurrentView();
-        setCurrentView(currentView);
-
-        final int listPosition = ss.getListPosition();
-        if (listPosition != -1) {
-            if (currentView == VIEW_MONTH_DAY) {
-                mDayPickerView.setPosition(listPosition);
-            } else if (currentView == VIEW_YEAR) {
-                final int listPositionOffset = ss.getListPositionOffset();
-                mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset);
+        if (state instanceof SavedState) {
+            final SavedState ss = (SavedState) state;
+
+            // TODO: Move instance state into DayPickerView, YearPickerView.
+            mCurrentDate.set(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay());
+            mMinDate.setTimeInMillis(ss.getMinDate());
+            mMaxDate.setTimeInMillis(ss.getMaxDate());
+
+            onCurrentDateChanged(false);
+
+            final int currentView = ss.getCurrentView();
+            setCurrentView(currentView);
+
+            final int listPosition = ss.getListPosition();
+            if (listPosition != -1) {
+                if (currentView == VIEW_MONTH_DAY) {
+                    mDayPickerView.setPosition(listPosition);
+                } else if (currentView == VIEW_YEAR) {
+                    final int listPositionOffset = ss.getListPositionOffset();
+                    mYearPickerView.setSelectionFromTop(listPosition, listPositionOffset);
+                }
             }
         }
     }
@@ -613,108 +614,4 @@ class DatePickerCalendarDelegate extends DatePicker.AbstractDatePickerDelegate {
     private void tryVibrate() {
         mDelegator.performHapticFeedback(HapticFeedbackConstants.CALENDAR_DATE);
     }
-
-    /**
-     * Class for managing state storing/restoring.
-     */
-    private static class SavedState extends View.BaseSavedState {
-        private final int mSelectedYear;
-        private final int mSelectedMonth;
-        private final int mSelectedDay;
-        private final long mMinDate;
-        private final long mMaxDate;
-        private final int mCurrentView;
-        private final int mListPosition;
-        private final int mListPositionOffset;
-
-        /**
-         * Constructor called from {@link DatePicker#onSaveInstanceState()}
-         */
-        private SavedState(Parcelable superState, int year, int month, int day,
-                long minDate, long maxDate, int currentView, int listPosition,
-                int listPositionOffset) {
-            super(superState);
-            mSelectedYear = year;
-            mSelectedMonth = month;
-            mSelectedDay = day;
-            mMinDate = minDate;
-            mMaxDate = maxDate;
-            mCurrentView = currentView;
-            mListPosition = listPosition;
-            mListPositionOffset = listPositionOffset;
-        }
-
-        /**
-         * Constructor called from {@link #CREATOR}
-         */
-        private SavedState(Parcel in) {
-            super(in);
-            mSelectedYear = in.readInt();
-            mSelectedMonth = in.readInt();
-            mSelectedDay = in.readInt();
-            mMinDate = in.readLong();
-            mMaxDate = in.readLong();
-            mCurrentView = in.readInt();
-            mListPosition = in.readInt();
-            mListPositionOffset = in.readInt();
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeInt(mSelectedYear);
-            dest.writeInt(mSelectedMonth);
-            dest.writeInt(mSelectedDay);
-            dest.writeLong(mMinDate);
-            dest.writeLong(mMaxDate);
-            dest.writeInt(mCurrentView);
-            dest.writeInt(mListPosition);
-            dest.writeInt(mListPositionOffset);
-        }
-
-        public int getSelectedDay() {
-            return mSelectedDay;
-        }
-
-        public int getSelectedMonth() {
-            return mSelectedMonth;
-        }
-
-        public int getSelectedYear() {
-            return mSelectedYear;
-        }
-
-        public long getMinDate() {
-            return mMinDate;
-        }
-
-        public long getMaxDate() {
-            return mMaxDate;
-        }
-
-        public int getCurrentView() {
-            return mCurrentView;
-        }
-
-        public int getListPosition() {
-            return mListPosition;
-        }
-
-        public int getListPositionOffset() {
-            return mListPositionOffset;
-        }
-
-        @SuppressWarnings("all")
-        // suppress unused and hiding
-        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
-
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
 }
diff --git a/core/java/android/widget/DatePickerSpinnerDelegate.java b/core/java/android/widget/DatePickerSpinnerDelegate.java
new file mode 100644 (file)
index 0000000..255de79
--- /dev/null
@@ -0,0 +1,652 @@
+/*
+ * Copyright (C) 2016 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.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.os.Parcelable;
+import android.text.InputType;
+import android.text.TextUtils;
+import android.text.format.DateFormat;
+import android.text.format.DateUtils;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.DatePicker.AbstractDatePickerDelegate;
+import android.widget.NumberPicker.OnValueChangeListener;
+
+import java.text.DateFormatSymbols;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Arrays;
+import java.util.Calendar;
+import java.util.Locale;
+
+import libcore.icu.ICU;
+
+/**
+ * A delegate implementing the basic DatePicker
+ */
+class DatePickerSpinnerDelegate extends AbstractDatePickerDelegate {
+
+    private static final String DATE_FORMAT = "MM/dd/yyyy";
+
+    private static final int DEFAULT_START_YEAR = 1900;
+
+    private static final int DEFAULT_END_YEAR = 2100;
+
+    private static final boolean DEFAULT_CALENDAR_VIEW_SHOWN = true;
+
+    private static final boolean DEFAULT_SPINNERS_SHOWN = true;
+
+    private static final boolean DEFAULT_ENABLED_STATE = true;
+
+    private final LinearLayout mSpinners;
+
+    private final NumberPicker mDaySpinner;
+
+    private final NumberPicker mMonthSpinner;
+
+    private final NumberPicker mYearSpinner;
+
+    private final EditText mDaySpinnerInput;
+
+    private final EditText mMonthSpinnerInput;
+
+    private final EditText mYearSpinnerInput;
+
+    private final CalendarView mCalendarView;
+
+    private String[] mShortMonths;
+
+    private final java.text.DateFormat mDateFormat = new SimpleDateFormat(DATE_FORMAT);
+
+    private int mNumberOfMonths;
+
+    private Calendar mTempDate;
+
+    private Calendar mMinDate;
+
+    private Calendar mMaxDate;
+
+    private Calendar mCurrentDate;
+
+    private boolean mIsEnabled = DEFAULT_ENABLED_STATE;
+
+    DatePickerSpinnerDelegate(DatePicker delegator, Context context, AttributeSet attrs,
+            int defStyleAttr, int defStyleRes) {
+        super(delegator, context);
+
+        mDelegator = delegator;
+        mContext = context;
+
+        // initialization based on locale
+        setCurrentLocale(Locale.getDefault());
+
+        final TypedArray attributesArray = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.DatePicker, defStyleAttr, defStyleRes);
+        boolean spinnersShown = attributesArray.getBoolean(com.android.internal.R.styleable.DatePicker_spinnersShown,
+                DEFAULT_SPINNERS_SHOWN);
+        boolean calendarViewShown = attributesArray.getBoolean(
+                com.android.internal.R.styleable.DatePicker_calendarViewShown, DEFAULT_CALENDAR_VIEW_SHOWN);
+        int startYear = attributesArray.getInt(com.android.internal.R.styleable.DatePicker_startYear,
+                DEFAULT_START_YEAR);
+        int endYear = attributesArray.getInt(com.android.internal.R.styleable.DatePicker_endYear, DEFAULT_END_YEAR);
+        String minDate = attributesArray.getString(com.android.internal.R.styleable.DatePicker_minDate);
+        String maxDate = attributesArray.getString(com.android.internal.R.styleable.DatePicker_maxDate);
+        int layoutResourceId = attributesArray.getResourceId(
+                com.android.internal.R.styleable.DatePicker_legacyLayout, com.android.internal.R.layout.date_picker_legacy);
+        attributesArray.recycle();
+
+        LayoutInflater inflater = (LayoutInflater) context
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(layoutResourceId, mDelegator, true);
+
+        OnValueChangeListener onChangeListener = new OnValueChangeListener() {
+            public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
+                updateInputState();
+                mTempDate.setTimeInMillis(mCurrentDate.getTimeInMillis());
+                // take care of wrapping of days and months to update greater fields
+                if (picker == mDaySpinner) {
+                    int maxDayOfMonth = mTempDate.getActualMaximum(Calendar.DAY_OF_MONTH);
+                    if (oldVal == maxDayOfMonth && newVal == 1) {
+                        mTempDate.add(Calendar.DAY_OF_MONTH, 1);
+                    } else if (oldVal == 1 && newVal == maxDayOfMonth) {
+                        mTempDate.add(Calendar.DAY_OF_MONTH, -1);
+                    } else {
+                        mTempDate.add(Calendar.DAY_OF_MONTH, newVal - oldVal);
+                    }
+                } else if (picker == mMonthSpinner) {
+                    if (oldVal == 11 && newVal == 0) {
+                        mTempDate.add(Calendar.MONTH, 1);
+                    } else if (oldVal == 0 && newVal == 11) {
+                        mTempDate.add(Calendar.MONTH, -1);
+                    } else {
+                        mTempDate.add(Calendar.MONTH, newVal - oldVal);
+                    }
+                } else if (picker == mYearSpinner) {
+                    mTempDate.set(Calendar.YEAR, newVal);
+                } else {
+                    throw new IllegalArgumentException();
+                }
+                // now set the date to the adjusted one
+                setDate(mTempDate.get(Calendar.YEAR), mTempDate.get(Calendar.MONTH),
+                        mTempDate.get(Calendar.DAY_OF_MONTH));
+                updateSpinners();
+                updateCalendarView();
+                notifyDateChanged();
+            }
+        };
+
+        mSpinners = (LinearLayout) mDelegator.findViewById(com.android.internal.R.id.pickers);
+
+        // calendar view day-picker
+        mCalendarView = (CalendarView) mDelegator.findViewById(com.android.internal.R.id.calendar_view);
+        mCalendarView.setOnDateChangeListener(new CalendarView.OnDateChangeListener() {
+            public void onSelectedDayChange(CalendarView view, int year, int month, int monthDay) {
+                setDate(year, month, monthDay);
+                updateSpinners();
+                notifyDateChanged();
+            }
+        });
+
+        // day
+        mDaySpinner = (NumberPicker) mDelegator.findViewById(com.android.internal.R.id.day);
+        mDaySpinner.setFormatter(NumberPicker.getTwoDigitFormatter());
+        mDaySpinner.setOnLongPressUpdateInterval(100);
+        mDaySpinner.setOnValueChangedListener(onChangeListener);
+        mDaySpinnerInput = (EditText) mDaySpinner.findViewById(com.android.internal.R.id.numberpicker_input);
+
+        // month
+        mMonthSpinner = (NumberPicker) mDelegator.findViewById(com.android.internal.R.id.month);
+        mMonthSpinner.setMinValue(0);
+        mMonthSpinner.setMaxValue(mNumberOfMonths - 1);
+        mMonthSpinner.setDisplayedValues(mShortMonths);
+        mMonthSpinner.setOnLongPressUpdateInterval(200);
+        mMonthSpinner.setOnValueChangedListener(onChangeListener);
+        mMonthSpinnerInput = (EditText) mMonthSpinner.findViewById(com.android.internal.R.id.numberpicker_input);
+
+        // year
+        mYearSpinner = (NumberPicker) mDelegator.findViewById(com.android.internal.R.id.year);
+        mYearSpinner.setOnLongPressUpdateInterval(100);
+        mYearSpinner.setOnValueChangedListener(onChangeListener);
+        mYearSpinnerInput = (EditText) mYearSpinner.findViewById(com.android.internal.R.id.numberpicker_input);
+
+        // show only what the user required but make sure we
+        // show something and the spinners have higher priority
+        if (!spinnersShown && !calendarViewShown) {
+            setSpinnersShown(true);
+        } else {
+            setSpinnersShown(spinnersShown);
+            setCalendarViewShown(calendarViewShown);
+        }
+
+        // set the min date giving priority of the minDate over startYear
+        mTempDate.clear();
+        if (!TextUtils.isEmpty(minDate)) {
+            if (!parseDate(minDate, mTempDate)) {
+                mTempDate.set(startYear, 0, 1);
+            }
+        } else {
+            mTempDate.set(startYear, 0, 1);
+        }
+        setMinDate(mTempDate.getTimeInMillis());
+
+        // set the max date giving priority of the maxDate over endYear
+        mTempDate.clear();
+        if (!TextUtils.isEmpty(maxDate)) {
+            if (!parseDate(maxDate, mTempDate)) {
+                mTempDate.set(endYear, 11, 31);
+            }
+        } else {
+            mTempDate.set(endYear, 11, 31);
+        }
+        setMaxDate(mTempDate.getTimeInMillis());
+
+        // initialize to current date
+        mCurrentDate.setTimeInMillis(System.currentTimeMillis());
+        init(mCurrentDate.get(Calendar.YEAR), mCurrentDate.get(Calendar.MONTH), mCurrentDate
+                .get(Calendar.DAY_OF_MONTH), null);
+
+        // re-order the number spinners to match the current date format
+        reorderSpinners();
+
+        // accessibility
+        setContentDescriptions();
+
+        // If not explicitly specified this view is important for accessibility.
+        if (mDelegator.getImportantForAccessibility() == View.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {
+            mDelegator.setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_YES);
+        }
+    }
+
+    @Override
+    public void init(int year, int monthOfYear, int dayOfMonth,
+                     DatePicker.OnDateChangedListener onDateChangedListener) {
+        setDate(year, monthOfYear, dayOfMonth);
+        updateSpinners();
+        updateCalendarView();
+        mOnDateChangedListener = onDateChangedListener;
+    }
+
+    @Override
+    public void updateDate(int year, int month, int dayOfMonth) {
+        if (!isNewDate(year, month, dayOfMonth)) {
+            return;
+        }
+        setDate(year, month, dayOfMonth);
+        updateSpinners();
+        updateCalendarView();
+        notifyDateChanged();
+    }
+
+    @Override
+    public int getYear() {
+        return mCurrentDate.get(Calendar.YEAR);
+    }
+
+    @Override
+    public int getMonth() {
+        return mCurrentDate.get(Calendar.MONTH);
+    }
+
+    @Override
+    public int getDayOfMonth() {
+        return mCurrentDate.get(Calendar.DAY_OF_MONTH);
+    }
+
+    @Override
+    public void setFirstDayOfWeek(int firstDayOfWeek) {
+        mCalendarView.setFirstDayOfWeek(firstDayOfWeek);
+    }
+
+    @Override
+    public int getFirstDayOfWeek() {
+        return mCalendarView.getFirstDayOfWeek();
+    }
+
+    @Override
+    public void setMinDate(long minDate) {
+        mTempDate.setTimeInMillis(minDate);
+        if (mTempDate.get(Calendar.YEAR) == mMinDate.get(Calendar.YEAR)
+                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMinDate.get(Calendar.DAY_OF_YEAR)) {
+            return;
+        }
+        mMinDate.setTimeInMillis(minDate);
+        mCalendarView.setMinDate(minDate);
+        if (mCurrentDate.before(mMinDate)) {
+            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
+            updateCalendarView();
+        }
+        updateSpinners();
+    }
+
+    @Override
+    public Calendar getMinDate() {
+        final Calendar minDate = Calendar.getInstance();
+        minDate.setTimeInMillis(mCalendarView.getMinDate());
+        return minDate;
+    }
+
+    @Override
+    public void setMaxDate(long maxDate) {
+        mTempDate.setTimeInMillis(maxDate);
+        if (mTempDate.get(Calendar.YEAR) == mMaxDate.get(Calendar.YEAR)
+                && mTempDate.get(Calendar.DAY_OF_YEAR) != mMaxDate.get(Calendar.DAY_OF_YEAR)) {
+            return;
+        }
+        mMaxDate.setTimeInMillis(maxDate);
+        mCalendarView.setMaxDate(maxDate);
+        if (mCurrentDate.after(mMaxDate)) {
+            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
+            updateCalendarView();
+        }
+        updateSpinners();
+    }
+
+    @Override
+    public Calendar getMaxDate() {
+        final Calendar maxDate = Calendar.getInstance();
+        maxDate.setTimeInMillis(mCalendarView.getMaxDate());
+        return maxDate;
+    }
+
+    @Override
+    public void setEnabled(boolean enabled) {
+        mDaySpinner.setEnabled(enabled);
+        mMonthSpinner.setEnabled(enabled);
+        mYearSpinner.setEnabled(enabled);
+        mCalendarView.setEnabled(enabled);
+        mIsEnabled = enabled;
+    }
+
+    @Override
+    public boolean isEnabled() {
+        return mIsEnabled;
+    }
+
+    @Override
+    public CalendarView getCalendarView() {
+        return mCalendarView;
+    }
+
+    @Override
+    public void setCalendarViewShown(boolean shown) {
+        mCalendarView.setVisibility(shown ? View.VISIBLE : View.GONE);
+    }
+
+    @Override
+    public boolean getCalendarViewShown() {
+        return (mCalendarView.getVisibility() == View.VISIBLE);
+    }
+
+    @Override
+    public void setSpinnersShown(boolean shown) {
+        mSpinners.setVisibility(shown ? View.VISIBLE : View.GONE);
+    }
+
+    @Override
+    public boolean getSpinnersShown() {
+        return mSpinners.isShown();
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration newConfig) {
+        setCurrentLocale(newConfig.locale);
+    }
+
+    @Override
+    public Parcelable onSaveInstanceState(Parcelable superState) {
+        return new SavedState(superState, getYear(), getMonth(), getDayOfMonth(),
+                getMinDate().getTimeInMillis(), getMaxDate().getTimeInMillis());
+    }
+
+    @Override
+    public void onRestoreInstanceState(Parcelable state) {
+        if (state instanceof SavedState) {
+            final SavedState ss = (SavedState) state;
+            setDate(ss.getSelectedYear(), ss.getSelectedMonth(), ss.getSelectedDay());
+            updateSpinners();
+            updateCalendarView();
+        }
+    }
+
+    @Override
+    public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
+        onPopulateAccessibilityEvent(event);
+        return true;
+    }
+
+    @Override
+    public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
+        final int flags = DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_SHOW_YEAR;
+        String selectedDateUtterance = DateUtils.formatDateTime(mContext,
+                mCurrentDate.getTimeInMillis(), flags);
+        event.getText().add(selectedDateUtterance);
+    }
+
+    /**
+     * Sets the current locale.
+     *
+     * @param locale The current locale.
+     */
+    @Override
+    protected void setCurrentLocale(Locale locale) {
+        super.setCurrentLocale(locale);
+
+        mTempDate = getCalendarForLocale(mTempDate, locale);
+        mMinDate = getCalendarForLocale(mMinDate, locale);
+        mMaxDate = getCalendarForLocale(mMaxDate, locale);
+        mCurrentDate = getCalendarForLocale(mCurrentDate, locale);
+
+        mNumberOfMonths = mTempDate.getActualMaximum(Calendar.MONTH) + 1;
+        mShortMonths = new DateFormatSymbols().getShortMonths();
+
+        if (usingNumericMonths()) {
+            // We're in a locale where a date should either be all-numeric, or all-text.
+            // All-text would require custom NumberPicker formatters for day and year.
+            mShortMonths = new String[mNumberOfMonths];
+            for (int i = 0; i < mNumberOfMonths; ++i) {
+                mShortMonths[i] = String.format("%d", i + 1);
+            }
+        }
+    }
+
+    /**
+     * Tests whether the current locale is one where there are no real month names,
+     * such as Chinese, Japanese, or Korean locales.
+     */
+    private boolean usingNumericMonths() {
+        return Character.isDigit(mShortMonths[Calendar.JANUARY].charAt(0));
+    }
+
+    /**
+     * Gets a calendar for locale bootstrapped with the value of a given calendar.
+     *
+     * @param oldCalendar The old calendar.
+     * @param locale The locale.
+     */
+    private Calendar getCalendarForLocale(Calendar oldCalendar, Locale locale) {
+        if (oldCalendar == null) {
+            return Calendar.getInstance(locale);
+        } else {
+            final long currentTimeMillis = oldCalendar.getTimeInMillis();
+            Calendar newCalendar = Calendar.getInstance(locale);
+            newCalendar.setTimeInMillis(currentTimeMillis);
+            return newCalendar;
+        }
+    }
+
+    /**
+     * Reorders the spinners according to the date format that is
+     * explicitly set by the user and if no such is set fall back
+     * to the current locale's default format.
+     */
+    private void reorderSpinners() {
+        mSpinners.removeAllViews();
+        // We use numeric spinners for year and day, but textual months. Ask icu4c what
+        // order the user's locale uses for that combination. http://b/7207103.
+        String pattern = DateFormat.getBestDateTimePattern(Locale.getDefault(), "yyyyMMMdd");
+        char[] order = ICU.getDateFormatOrder(pattern);
+        final int spinnerCount = order.length;
+        for (int i = 0; i < spinnerCount; i++) {
+            switch (order[i]) {
+                case 'd':
+                    mSpinners.addView(mDaySpinner);
+                    setImeOptions(mDaySpinner, spinnerCount, i);
+                    break;
+                case 'M':
+                    mSpinners.addView(mMonthSpinner);
+                    setImeOptions(mMonthSpinner, spinnerCount, i);
+                    break;
+                case 'y':
+                    mSpinners.addView(mYearSpinner);
+                    setImeOptions(mYearSpinner, spinnerCount, i);
+                    break;
+                default:
+                    throw new IllegalArgumentException(Arrays.toString(order));
+            }
+        }
+    }
+
+    /**
+     * Parses the given <code>date</code> and in case of success sets the result
+     * to the <code>outDate</code>.
+     *
+     * @return True if the date was parsed.
+     */
+    private boolean parseDate(String date, Calendar outDate) {
+        try {
+            outDate.setTime(mDateFormat.parse(date));
+            return true;
+        } catch (ParseException e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    private boolean isNewDate(int year, int month, int dayOfMonth) {
+        return (mCurrentDate.get(Calendar.YEAR) != year
+                || mCurrentDate.get(Calendar.MONTH) != month
+                || mCurrentDate.get(Calendar.DAY_OF_MONTH) != dayOfMonth);
+    }
+
+    private void setDate(int year, int month, int dayOfMonth) {
+        mCurrentDate.set(year, month, dayOfMonth);
+        if (mCurrentDate.before(mMinDate)) {
+            mCurrentDate.setTimeInMillis(mMinDate.getTimeInMillis());
+        } else if (mCurrentDate.after(mMaxDate)) {
+            mCurrentDate.setTimeInMillis(mMaxDate.getTimeInMillis());
+        }
+    }
+
+    private void updateSpinners() {
+        // set the spinner ranges respecting the min and max dates
+        if (mCurrentDate.equals(mMinDate)) {
+            mDaySpinner.setMinValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
+            mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
+            mDaySpinner.setWrapSelectorWheel(false);
+            mMonthSpinner.setDisplayedValues(null);
+            mMonthSpinner.setMinValue(mCurrentDate.get(Calendar.MONTH));
+            mMonthSpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.MONTH));
+            mMonthSpinner.setWrapSelectorWheel(false);
+        } else if (mCurrentDate.equals(mMaxDate)) {
+            mDaySpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.DAY_OF_MONTH));
+            mDaySpinner.setMaxValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
+            mDaySpinner.setWrapSelectorWheel(false);
+            mMonthSpinner.setDisplayedValues(null);
+            mMonthSpinner.setMinValue(mCurrentDate.getActualMinimum(Calendar.MONTH));
+            mMonthSpinner.setMaxValue(mCurrentDate.get(Calendar.MONTH));
+            mMonthSpinner.setWrapSelectorWheel(false);
+        } else {
+            mDaySpinner.setMinValue(1);
+            mDaySpinner.setMaxValue(mCurrentDate.getActualMaximum(Calendar.DAY_OF_MONTH));
+            mDaySpinner.setWrapSelectorWheel(true);
+            mMonthSpinner.setDisplayedValues(null);
+            mMonthSpinner.setMinValue(0);
+            mMonthSpinner.setMaxValue(11);
+            mMonthSpinner.setWrapSelectorWheel(true);
+        }
+
+        // make sure the month names are a zero based array
+        // with the months in the month spinner
+        String[] displayedValues = Arrays.copyOfRange(mShortMonths,
+                mMonthSpinner.getMinValue(), mMonthSpinner.getMaxValue() + 1);
+        mMonthSpinner.setDisplayedValues(displayedValues);
+
+        // year spinner range does not change based on the current date
+        mYearSpinner.setMinValue(mMinDate.get(Calendar.YEAR));
+        mYearSpinner.setMaxValue(mMaxDate.get(Calendar.YEAR));
+        mYearSpinner.setWrapSelectorWheel(false);
+
+        // set the spinner values
+        mYearSpinner.setValue(mCurrentDate.get(Calendar.YEAR));
+        mMonthSpinner.setValue(mCurrentDate.get(Calendar.MONTH));
+        mDaySpinner.setValue(mCurrentDate.get(Calendar.DAY_OF_MONTH));
+
+        if (usingNumericMonths()) {
+            mMonthSpinnerInput.setRawInputType(InputType.TYPE_CLASS_NUMBER);
+        }
+    }
+
+    /**
+     * Updates the calendar view with the current date.
+     */
+    private void updateCalendarView() {
+        mCalendarView.setDate(mCurrentDate.getTimeInMillis(), false, false);
+    }
+
+
+    /**
+     * Notifies the listener, if such, for a change in the selected date.
+     */
+    private void notifyDateChanged() {
+        mDelegator.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_SELECTED);
+        if (mOnDateChangedListener != null) {
+            mOnDateChangedListener.onDateChanged(mDelegator, getYear(), getMonth(),
+                    getDayOfMonth());
+        }
+    }
+
+    /**
+     * Sets the IME options for a spinner based on its ordering.
+     *
+     * @param spinner The spinner.
+     * @param spinnerCount The total spinner count.
+     * @param spinnerIndex The index of the given spinner.
+     */
+    private void setImeOptions(NumberPicker spinner, int spinnerCount, int spinnerIndex) {
+        final int imeOptions;
+        if (spinnerIndex < spinnerCount - 1) {
+            imeOptions = EditorInfo.IME_ACTION_NEXT;
+        } else {
+            imeOptions = EditorInfo.IME_ACTION_DONE;
+        }
+        TextView input = (TextView) spinner.findViewById(com.android.internal.R.id.numberpicker_input);
+        input.setImeOptions(imeOptions);
+    }
+
+    private void setContentDescriptions() {
+        // Day
+        trySetContentDescription(mDaySpinner, com.android.internal.R.id.increment,
+                com.android.internal.R.string.date_picker_increment_day_button);
+        trySetContentDescription(mDaySpinner, com.android.internal.R.id.decrement,
+                com.android.internal.R.string.date_picker_decrement_day_button);
+        // Month
+        trySetContentDescription(mMonthSpinner, com.android.internal.R.id.increment,
+                com.android.internal.R.string.date_picker_increment_month_button);
+        trySetContentDescription(mMonthSpinner, com.android.internal.R.id.decrement,
+                com.android.internal.R.string.date_picker_decrement_month_button);
+        // Year
+        trySetContentDescription(mYearSpinner, com.android.internal.R.id.increment,
+                com.android.internal.R.string.date_picker_increment_year_button);
+        trySetContentDescription(mYearSpinner, com.android.internal.R.id.decrement,
+                com.android.internal.R.string.date_picker_decrement_year_button);
+    }
+
+    private void trySetContentDescription(View root, int viewId, int contDescResId) {
+        View target = root.findViewById(viewId);
+        if (target != null) {
+            target.setContentDescription(mContext.getString(contDescResId));
+        }
+    }
+
+    private void updateInputState() {
+        // Make sure that if the user changes the value and the IME is active
+        // for one of the inputs if this widget, the IME is closed. If the user
+        // changed the value via the IME and there is a next input the IME will
+        // be shown, otherwise the user chose another means of changing the
+        // value and having the IME up makes no sense.
+        InputMethodManager inputMethodManager = InputMethodManager.peekInstance();
+        if (inputMethodManager != null) {
+            if (inputMethodManager.isActive(mYearSpinnerInput)) {
+                mYearSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mMonthSpinnerInput)) {
+                mMonthSpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            } else if (inputMethodManager.isActive(mDaySpinnerInput)) {
+                mDaySpinnerInput.clearFocus();
+                inputMethodManager.hideSoftInputFromWindow(mDelegator.getWindowToken(), 0);
+            }
+        }
+    }
+}
index 1d242d3..434e3eb 100644 (file)
@@ -117,6 +117,16 @@ public class EditText extends TextView {
         Selection.extendSelection(getText(), index);
     }
 
+    /**
+     * Causes words in the text that are longer than the view's width to be ellipsized instead of
+     * broken in the middle. {@link TextUtils.TruncateAt#MARQUEE
+     * TextUtils.TruncateAt#MARQUEE} is not supported.
+     *
+     * @param ellipsis Type of ellipsis to be applied.
+     * @throws IllegalArgumentException When the value of <code>ellipsis</code> parameter is
+     *      {@link TextUtils.TruncateAt#MARQUEE}.
+     * @see TextView#setEllipsize(TextUtils.TruncateAt)
+     */
     @Override
     public void setEllipsize(TextUtils.TruncateAt ellipsis) {
         if (ellipsis == TextUtils.TruncateAt.MARQUEE) {
index 881e5cd..a7b12c1 100644 (file)
@@ -215,7 +215,7 @@ public class Editor {
 
     boolean mInBatchEditControllers;
     boolean mShowSoftInputOnFocus = true;
-    boolean mPreserveDetachedSelection;
+    private boolean mPreserveDetachedSelection;
     boolean mTemporaryDetach;
 
     boolean mIsBeingLongClicked;
@@ -352,7 +352,6 @@ public class Editor {
 
     void replace() {
         int middle = (mTextView.getSelectionStart() + mTextView.getSelectionEnd()) / 2;
-        stopTextActionMode();
         Selection.setSelection((Spannable) mTextView.getText(), middle);
         showSuggestions();
     }
@@ -429,10 +428,8 @@ public class Editor {
             mSpellChecker = null;
         }
 
-        mPreserveDetachedSelection = true;
         hideCursorAndSpanControllers();
-        stopTextActionMode();
-        mPreserveDetachedSelection = false;
+        stopTextActionModeWithPreservingSelection();
         mTemporaryDetach = false;
     }
 
@@ -1104,7 +1101,6 @@ public class Editor {
                 mInsertionControllerEnabled) {
             final int offset = mTextView.getOffsetForPosition(mLastDownPositionX,
                     mLastDownPositionY);
-            stopTextActionMode();
             Selection.setSelection((Spannable) mTextView.getText(), offset);
             getInsertionController().show();
             mIsInsertionActionModeStartPending = true;
@@ -1208,18 +1204,15 @@ public class Editor {
             mTextView.onEndBatchEdit();
 
             if (mTextView.isInExtractedMode()) {
-                // terminateTextSelectionMode removes selection, which we want to keep when
-                // ExtractEditText goes out of focus.
-                final int selStart = mTextView.getSelectionStart();
-                final int selEnd = mTextView.getSelectionEnd();
                 hideCursorAndSpanControllers();
-                stopTextActionMode();
-                Selection.setSelection((Spannable) mTextView.getText(), selStart, selEnd);
+                stopTextActionModeWithPreservingSelection();
             } else {
-                if (mTemporaryDetach) mPreserveDetachedSelection = true;
                 hideCursorAndSpanControllers();
-                stopTextActionMode();
-                if (mTemporaryDetach) mPreserveDetachedSelection = false;
+                if (mTemporaryDetach) {
+                    stopTextActionModeWithPreservingSelection();
+                } else {
+                    stopTextActionMode();
+                }
                 downgradeEasyCorrectionSpans();
             }
             // No need to create the controller
@@ -1290,10 +1283,8 @@ public class Editor {
                 makeBlink();
             }
             final InputMethodManager imm = InputMethodManager.peekInstance();
-            final boolean immFullScreen = (imm != null && imm.isFullscreenMode());
-            if (mSelectionModifierCursorController != null && mTextView.hasSelection()
-                    && !immFullScreen && mTextActionMode != null) {
-                mSelectionModifierCursorController.show();
+            if (mTextView.hasSelection() && !extractedTextModeWillBeStarted()) {
+                startSelectionActionMode();
             }
         } else {
             if (mBlink != null) {
@@ -1304,9 +1295,7 @@ public class Editor {
             }
             // Order matters! Must be done before onParentLostFocus to rely on isShowingUp
             hideCursorAndSpanControllers();
-            if (mSelectionModifierCursorController != null) {
-                mSelectionModifierCursorController.hide();
-            }
+            stopTextActionModeWithPreservingSelection();
             if (mSuggestionsPopupWindow != null) {
                 mSuggestionsPopupWindow.onParentLostFocus();
             }
@@ -1856,6 +1845,38 @@ public class Editor {
         }
     }
 
+    void refreshTextActionMode() {
+        if (extractedTextModeWillBeStarted()) {
+            return;
+        }
+        final boolean hasSelection = mTextView.hasSelection();
+        final SelectionModifierCursorController selectionController = getSelectionController();
+        final InsertionPointCursorController insertionController = getInsertionController();
+        if ((selectionController != null && selectionController.isCursorBeingModified())
+                || (insertionController != null && insertionController.isCursorBeingModified())) {
+            // ActionMode should be managed by the currently active cursor controller.
+            return;
+        }
+        if (hasSelection) {
+            if (mTextActionMode == null || selectionController == null
+                    || !selectionController.isActive()) {
+                // Avoid dismissing the selection if it exists.
+                stopTextActionModeWithPreservingSelection();
+                startSelectionActionMode();
+            } else {
+                mTextActionMode.invalidateContentRect();
+            }
+        } else {
+            // Insertion action mode is started only when insertion controller is explicitly
+            // activated.
+            if (insertionController == null || !insertionController.isActive()) {
+                stopTextActionMode();
+            } else if (mTextActionMode != null) {
+                mTextActionMode.invalidateContentRect();
+            }
+        }
+    }
+
     /**
      * Start an Insertion action mode.
      */
@@ -1879,17 +1900,15 @@ public class Editor {
 
     /**
      * Starts a Selection Action Mode with the current selection and ensures the selection handles
-     * are shown if there is a selection, otherwise the insertion handle is shown. This should be
-     * used when the mode is started from a non-touch event.
+     * are shown if there is a selection. This should be used when the mode is started from a
+     * non-touch event.
      *
      * @return true if the selection mode was actually started.
      */
-    boolean startSelectionActionMode() {
+    private boolean startSelectionActionMode() {
         boolean selectionStarted = startSelectionActionModeInternal();
         if (selectionStarted) {
             getSelectionController().show();
-        } else if (getInsertionController() != null) {
-            getInsertionController().show();
         }
         return selectionStarted;
     }
@@ -1907,66 +1926,52 @@ public class Editor {
         if (extractedTextModeWillBeStarted()) {
             return false;
         }
-        if (mTextActionMode != null) {
-            mTextActionMode.finish();
+        if (!checkField()) {
+            return false;
         }
-        if (!checkFieldAndSelectCurrentWord()) {
+        if (!mTextView.hasSelection() && !selectCurrentWord()) {
+            // No selection and cannot select a word.
             return false;
         }
-
-        // Avoid dismissing the selection if it exists.
-        mPreserveDetachedSelection = true;
-        stopTextActionMode();
-        mPreserveDetachedSelection = false;
-
+        stopTextActionModeWithPreservingSelection();
         getSelectionController().enterDrag(
                 SelectionModifierCursorController.DRAG_ACCELERATOR_MODE_WORD);
         return true;
     }
 
     /**
-     * Checks whether a selection can be performed on the current TextView and if so selects
-     * the current word.
+     * Checks whether a selection can be performed on the current TextView.
      *
-     * @return true if there already was a selection or if the current word was selected.
+     * @return true if a selection can be performed
      */
-    boolean checkFieldAndSelectCurrentWord() {
+    boolean checkField() {
         if (!mTextView.canSelectText() || !mTextView.requestFocus()) {
             Log.w(TextView.LOG_TAG,
                     "TextView does not support text selection. Selection cancelled.");
             return false;
         }
-
-        if (!mTextView.hasSelection()) {
-            // There may already be a selection on device rotation
-            return selectCurrentWord();
-        }
         return true;
     }
 
     private boolean startSelectionActionModeInternal() {
+        if (extractedTextModeWillBeStarted()) {
+            return false;
+        }
         if (mTextActionMode != null) {
             // Text action mode is already started
             mTextActionMode.invalidate();
             return false;
         }
 
-        if (!checkFieldAndSelectCurrentWord()) {
+        if (!checkField() || !mTextView.hasSelection()) {
             return false;
         }
 
-        boolean willExtract = extractedTextModeWillBeStarted();
-
-        // Do not start the action mode when extracted text will show up full screen, which would
-        // immediately hide the newly created action bar and would be visually distracting.
-        if (!willExtract) {
-            ActionMode.Callback actionModeCallback =
-                    new TextActionModeCallback(true /* hasSelection */);
-            mTextActionMode = mTextView.startActionMode(
-                    actionModeCallback, ActionMode.TYPE_FLOATING);
-        }
+        ActionMode.Callback actionModeCallback =
+                new TextActionModeCallback(true /* hasSelection */);
+        mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);
 
-        final boolean selectionStarted = mTextActionMode != null || willExtract;
+        final boolean selectionStarted = mTextActionMode != null;
         if (selectionStarted && !mTextView.isTextSelectable() && mShowSoftInputOnFocus) {
             // Show the IME to be able to replace text, except when selecting non editable text.
             final InputMethodManager imm = InputMethodManager.peekInstance();
@@ -2107,6 +2112,12 @@ public class Editor {
         }
     }
 
+    private void stopTextActionModeWithPreservingSelection() {
+        mPreserveDetachedSelection = true;
+        stopTextActionMode();
+        mPreserveDetachedSelection = false;
+    }
+
     /**
      * @return True if this view supports insertion handles.
      */
@@ -2436,16 +2447,14 @@ public class Editor {
         if (offset == -1) {
             return;
         }
-        mPreserveDetachedSelection = true;
-        stopTextActionMode();
-        mPreserveDetachedSelection = false;
+        stopTextActionModeWithPreservingSelection();
         final boolean isOnSelection = mTextView.hasSelection()
                 && offset >= mTextView.getSelectionStart() && offset <= mTextView.getSelectionEnd();
         if (!isOnSelection) {
             // Right clicked position is not on the selection. Remove the selection and move the
             // cursor to the right clicked position.
-            stopTextActionMode();
             Selection.setSelection((Spannable) mTextView.getText(), offset);
+            stopTextActionMode();
         }
 
         if (shouldOfferToShowSuggestions()) {
@@ -3160,6 +3169,7 @@ public class Editor {
                 mTextView.getContext(), mTextView.mTextEditSuggestionHighlightStyle);
         private TextView mAddToDictionaryButton;
         private TextView mDeleteButton;
+        private ListView mSuggestionListView;
         private SuggestionSpan mMisspelledSpan;
         private int mContainerMarginWidth;
         private int mContainerMarginTop;
@@ -3177,7 +3187,7 @@ public class Editor {
                 ((Spannable) mTextView.getText()).removeSpan(mSuggestionRangeSpan);
 
                 mTextView.setCursorVisible(mCursorWasVisibleBeforeSuggestions);
-                if (hasInsertionController()) {
+                if (hasInsertionController() && !extractedTextModeWillBeStarted()) {
                     getInsertionController().show();
                 }
             }
@@ -3213,12 +3223,12 @@ public class Editor {
             mClippingLimitLeft = lp.leftMargin;
             mClippingLimitRight = lp.rightMargin;
 
-            final ListView suggestionListView = (ListView) relativeLayout.findViewById(
+            mSuggestionListView = (ListView) relativeLayout.findViewById(
                     com.android.internal.R.id.suggestionContainer);
 
             mSuggestionsAdapter = new SuggestionAdapter();
-            suggestionListView.setAdapter(mSuggestionsAdapter);
-            suggestionListView.setOnItemClickListener(this);
+            mSuggestionListView.setAdapter(mSuggestionsAdapter);
+            mSuggestionListView.setOnItemClickListener(this);
 
             // Inflate the suggestion items once and for all.
             mSuggestionInfos = new SuggestionInfo[MAX_NUMBER_SUGGESTIONS];
@@ -3327,6 +3337,9 @@ public class Editor {
         @Override
         public void show() {
             if (!(mTextView.getText() instanceof Editable)) return;
+            if (extractedTextModeWillBeStarted()) {
+                return;
+            }
 
             if (updateSuggestions()) {
                 mCursorWasVisibleBeforeSuggestions = mCursorVisible;
@@ -3374,6 +3387,7 @@ public class Editor {
                 popupBackground.getPadding(mTempRect);
                 width += mTempRect.left + mTempRect.right;
             }
+            mSuggestionListView.getLayoutParams().width = width;
             mPopupWindow.setWidth(width);
         }
 
@@ -3483,7 +3497,6 @@ public class Editor {
         public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
             Editable editable = (Editable) mTextView.getText();
             SuggestionInfo suggestionInfo = mSuggestionInfos[position];
-
             final int spanStart = editable.getSpanStart(suggestionInfo.mSuggestionSpan);
             final int spanEnd = editable.getSpanEnd(suggestionInfo.mSuggestionSpan);
             if (spanStart < 0 || spanEnd <= spanStart) {
@@ -4386,7 +4399,7 @@ public class Editor {
                         if (distanceSquared < touchSlop * touchSlop) {
                             // Tapping on the handle toggles the insertion action mode.
                             if (mTextActionMode != null) {
-                                mTextActionMode.finish();
+                                stopTextActionMode();
                             } else {
                                 startInsertionActionMode();
                             }
@@ -4803,6 +4816,10 @@ public class Editor {
          * preventing the activity from being recycled.
          */
         public void onDetached();
+
+        public boolean isCursorBeingModified();
+
+        public boolean isActive();
     }
 
     private class InsertionPointCursorController implements CursorController {
@@ -4846,6 +4863,16 @@ public class Editor {
 
             if (mHandle != null) mHandle.onDetached();
         }
+
+        @Override
+        public boolean isCursorBeingModified() {
+            return mHandle != null && mHandle.isDragging();
+        }
+
+        @Override
+        public boolean isActive() {
+            return mHandle != null && mHandle.isShowing();
+        }
     }
 
     class SelectionModifierCursorController implements CursorController {
@@ -5035,9 +5062,7 @@ public class Editor {
 
                         if (mStartOffset != offset) {
                             // Start character based drag accelerator.
-                            if (mTextActionMode != null) {
-                                mTextActionMode.finish();
-                            }
+                            stopTextActionMode();
                             enterDrag(DRAG_ACCELERATOR_MODE_CHARACTER);
                             mDiscardNextActionUp = true;
                             mHaventMovedEnoughToStartDrag = false;
@@ -5111,9 +5136,7 @@ public class Editor {
             if (mInsertionActionModeRunnable != null) {
                 mTextView.removeCallbacks(mInsertionActionModeRunnable);
             }
-            if (mTextActionMode != null) {
-                mTextActionMode.finish();
-            }
+            stopTextActionMode();
             if (!selectCurrentParagraph()) {
                 return false;
             }
@@ -5222,6 +5245,12 @@ public class Editor {
             mStartOffset = -1;
             mDragAcceleratorMode = DRAG_ACCELERATOR_MODE_INACTIVE;
             mSwitchedLines = false;
+            final int selectionStart = mTextView.getSelectionStart();
+            final int selectionEnd = mTextView.getSelectionEnd();
+            if (selectionStart > selectionEnd) {
+                Selection.setSelection((Spannable) mTextView.getText(),
+                        selectionEnd, selectionStart);
+            }
         }
 
         /**
@@ -5231,6 +5260,12 @@ public class Editor {
             return mStartHandle != null && mStartHandle.isDragging();
         }
 
+        @Override
+        public boolean isCursorBeingModified() {
+            return isDragAcceleratorActive() || isSelectionStartDragged()
+                    || (mEndHandle != null && mEndHandle.isDragging());
+        }
+
         /**
          * @return true if the user is selecting text using the drag accelerator.
          */
@@ -5252,6 +5287,11 @@ public class Editor {
             if (mStartHandle != null) mStartHandle.onDetached();
             if (mEndHandle != null) mEndHandle.onDetached();
         }
+
+        @Override
+        public boolean isActive() {
+            return mStartHandle != null && mStartHandle.isShowing();
+        }
     }
 
     private class CorrectionHighlighter {
index 54b3932..df2f575 100644 (file)
@@ -23,7 +23,6 @@ import com.android.internal.R;
 
 import android.annotation.NonNull;
 import android.content.Context;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -1587,18 +1586,16 @@ public class PopupWindow {
     public int getMaxAvailableHeight(
             @NonNull View anchor, int yOffset, boolean ignoreBottomDecorations) {
         final Rect displayFrame = new Rect();
-        anchor.getWindowVisibleDisplayFrame(displayFrame);
+        if (ignoreBottomDecorations) {
+            anchor.getWindowDisplayFrame(displayFrame);
+        } else {
+            anchor.getWindowVisibleDisplayFrame(displayFrame);
+        }
 
         final int[] anchorPos = mDrawingLocation;
         anchor.getLocationOnScreen(anchorPos);
 
-        final int bottomEdge;
-        if (ignoreBottomDecorations) {
-            final Resources res = anchor.getContext().getResources();
-            bottomEdge = res.getDisplayMetrics().heightPixels;
-        } else {
-            bottomEdge = displayFrame.bottom;
-        }
+        final int bottomEdge = displayFrame.bottom;
 
         final int distanceToBottom;
         if (mOverlapAnchor) {
index 2099b04..72a50ec 100644 (file)
 package android.widget;
 
 import android.animation.ObjectAnimator;
+import android.annotation.InterpolatorRes;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
-import android.graphics.PorterDuff;
-
-import android.util.FloatProperty;
-import android.util.IntProperty;
-import android.view.accessibility.AccessibilityNodeInfo;
-import com.android.internal.R;
-
-import android.annotation.InterpolatorRes;
 import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
+import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Shader;
 import android.graphics.drawable.Animatable;
@@ -46,6 +40,7 @@ import android.graphics.drawable.shapes.Shape;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.AttributeSet;
+import android.util.FloatProperty;
 import android.util.MathUtils;
 import android.util.Pools.SynchronizedPool;
 import android.view.Gravity;
@@ -55,6 +50,7 @@ import android.view.ViewDebug;
 import android.view.ViewHierarchyEncoder;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
+import android.view.accessibility.AccessibilityNodeInfo;
 import android.view.animation.AlphaAnimation;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
@@ -63,6 +59,7 @@ import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 import android.view.animation.Transformation;
 import android.widget.RemoteViews.RemoteView;
+import com.android.internal.R;
 
 import java.util.ArrayList;
 
@@ -606,15 +603,30 @@ public class ProgressBar extends View {
 
             if (indeterminate) {
                 // swap between indeterminate and regular backgrounds
-                mCurrentDrawable = mIndeterminateDrawable;
+                swapCurrentDrawable(mIndeterminateDrawable);
                 startAnimation();
             } else {
-                mCurrentDrawable = mProgressDrawable;
+                swapCurrentDrawable(mProgressDrawable);
                 stopAnimation();
             }
         }
     }
 
+    private void swapCurrentDrawable(Drawable newDrawable) {
+        final Drawable oldDrawable = mCurrentDrawable;
+        mCurrentDrawable = newDrawable;
+        if (oldDrawable != mCurrentDrawable) {
+            if (oldDrawable != null) {
+                oldDrawable.setVisible(false, false);
+            }
+            if (mCurrentDrawable != null) {
+                mCurrentDrawable.setVisible(
+                        getVisibility() == VISIBLE && getWindowVisibility() == VISIBLE,
+                        false);
+            }
+        }
+    }
+
     /**
      * <p>Get the drawable used to draw the progress bar in
      * indeterminate mode.</p>
@@ -654,7 +666,7 @@ public class ProgressBar extends View {
             }
 
             if (mIndeterminate) {
-                mCurrentDrawable = d;
+                swapCurrentDrawable(d);
                 postInvalidate();
             }
         }
@@ -820,7 +832,7 @@ public class ProgressBar extends View {
             }
 
             if (!mIndeterminate) {
-                mCurrentDrawable = d;
+                swapCurrentDrawable(d);
                 postInvalidate();
             }
 
@@ -1555,7 +1567,7 @@ public class ProgressBar extends View {
      * <p>Start the indeterminate progress animation.</p>
      */
     void startAnimation() {
-        if (getVisibility() != VISIBLE) {
+        if (getVisibility() != VISIBLE || getWindowVisibility() != VISIBLE) {
             return;
         }
 
@@ -1653,14 +1665,30 @@ public class ProgressBar extends View {
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
 
+        updateVisibility();
+    }
+
+    @Override
+    protected void onWindowVisibilityChanged(@Visibility int visibility) {
+        super.onWindowVisibilityChanged(visibility);
+
+        updateVisibility();
+    }
+
+    private void updateVisibility() {
+        final boolean isVisible = getVisibility() == VISIBLE && getWindowVisibility() == VISIBLE;
         if (mIndeterminate) {
             // let's be nice with the UI thread
-            if (visibility == GONE || visibility == INVISIBLE) {
-                stopAnimation();
-            } else {
+            if (isVisible) {
                 startAnimation();
+            } else {
+                stopAnimation();
             }
         }
+
+        if (mCurrentDrawable != null) {
+            mCurrentDrawable.setVisible(isVisible, false);
+        }
     }
 
     @Override
index 95fcdc1..73f8fdc 100644 (file)
@@ -20,6 +20,7 @@ import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
 import android.R;
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.Size;
@@ -662,11 +663,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
      */
     private int mDeviceProvisionedState = DEVICE_PROVISIONED_UNKNOWN;
 
-    /*
+    /**
      * Kick-start the font cache for the zygote process (to pay the cost of
      * initializing freetype for our default font only once).
+     * @hide
      */
-    static {
+    public static void preloadFontCache() {
         Paint p = new Paint();
         p.setAntiAlias(true);
         // We don't care about the result, just the side-effect of measuring.
@@ -1509,6 +1511,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                 if (result != null) {
                     if (isTextEditable()) {
                         replaceSelectionWithText(result);
+                        if (mEditor != null) {
+                            mEditor.refreshTextActionMode();
+                        }
                     } else {
                         if (result.length() > 0) {
                             Toast.makeText(getContext(), String.valueOf(result), Toast.LENGTH_LONG)
@@ -1518,12 +1523,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                 }
             } else if (mText instanceof Spannable) {
                 // Reset the selection.
-                stopTextActionMode();
-                Selection.setSelection((Spannable) mText, getSelectionStart(), getSelectionEnd());
-            }
-
-            if (mEditor.hasSelectionController()) {
-                mEditor.startSelectionActionMode();
+                Selection.setSelection((Spannable) mText, getSelectionEnd());
             }
         }
     }
@@ -5391,11 +5391,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
         // - onFocusChanged cannot start it when focus is given to a view with selected text (after
         //   a screen rotation) since layout is not yet initialized at that point.
         if (mEditor != null && mEditor.mCreatedWithASelection) {
-            if (mEditor.extractedTextModeWillBeStarted()) {
-                mEditor.checkFieldAndSelectCurrentWord();
-            } else {
-                mEditor.startSelectionActionMode();
-            }
+            mEditor.refreshTextActionMode();
             mEditor.mCreatedWithASelection = false;
         }
 
@@ -5834,8 +5830,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
 
         final int layoutDirection = getLayoutDirection();
         final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-        if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
-                mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
+        if (isMarqueeFadeEnabled()) {
             if (!mSingleLine && getLineCount() == 1 && canMarquee() &&
                     (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) != Gravity.LEFT) {
                 final int width = mRight - mLeft;
@@ -6593,6 +6588,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
         // in the extracted view.
         mEditor.hideCursorAndSpanControllers();
         stopTextActionMode();
+        if (mEditor.mSelectionModifierCursorController != null) {
+            mEditor.mSelectionModifierCursorController.resetTouchOffsets();
+        }
     }
 
     /**
@@ -7887,7 +7885,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     }
 
     /**
-     * Causes words in the text that are longer than the view is wide
+     * Causes words in the text that are longer than the view's width
      * to be ellipsized instead of broken in the middle.  You may also
      * want to {@link #setSingleLine} or {@link #setHorizontallyScrolling}
      * to constrain the text to a single line.  Use <code>null</code>
@@ -8288,6 +8286,9 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                 if (newSelEnd < 0) {
                     newSelEnd = Selection.getSelectionEnd(buf);
                 }
+                if (mEditor != null) {
+                    mEditor.refreshTextActionMode();
+                }
                 onSelectionChanged(newSelStart, newSelEnd);
             }
         }
@@ -8615,78 +8616,59 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
 
     @Override
     protected float getLeftFadingEdgeStrength() {
-        if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
-                mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
-            if (mMarquee != null && !mMarquee.isStopped()) {
-                final Marquee marquee = mMarquee;
-                if (marquee.shouldDrawLeftFade()) {
-                    final float scroll = marquee.getScroll();
-                    return scroll / getHorizontalFadingEdgeLength();
-                } else {
-                    return 0.0f;
-                }
-            } else if (getLineCount() == 1) {
-                final int layoutDirection = getLayoutDirection();
-                final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-                    case Gravity.LEFT:
-                        return 0.0f;
-                    case Gravity.RIGHT:
-                        return (mLayout.getLineRight(0) - (mRight - mLeft) -
-                                getCompoundPaddingLeft() - getCompoundPaddingRight() -
-                                mLayout.getLineLeft(0)) / getHorizontalFadingEdgeLength();
-                    case Gravity.CENTER_HORIZONTAL:
-                    case Gravity.FILL_HORIZONTAL:
-                        final int textDirection = mLayout.getParagraphDirection(0);
-                        if (textDirection == Layout.DIR_LEFT_TO_RIGHT) {
-                            return 0.0f;
-                        } else {
-                            return (mLayout.getLineRight(0) - (mRight - mLeft) -
-                                getCompoundPaddingLeft() - getCompoundPaddingRight() -
-                                mLayout.getLineLeft(0)) / getHorizontalFadingEdgeLength();
-                        }
-                }
+        if (isMarqueeFadeEnabled() && mMarquee != null && !mMarquee.isStopped()) {
+            final Marquee marquee = mMarquee;
+            if (marquee.shouldDrawLeftFade()) {
+                return getHorizontalFadingEdgeStrength(marquee.getScroll(), 0.0f);
+            } else {
+                return 0.0f;
             }
+        } else if (getLineCount() == 1) {
+            final float lineLeft = getLayout().getLineLeft(0);
+            if(lineLeft > mScrollX) return 0.0f;
+            return getHorizontalFadingEdgeStrength(mScrollX, lineLeft);
         }
         return super.getLeftFadingEdgeStrength();
     }
 
     @Override
     protected float getRightFadingEdgeStrength() {
-        if (mEllipsize == TextUtils.TruncateAt.MARQUEE &&
-                mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS) {
-            if (mMarquee != null && !mMarquee.isStopped()) {
-                final Marquee marquee = mMarquee;
-                final float maxFadeScroll = marquee.getMaxFadeScroll();
-                final float scroll = marquee.getScroll();
-                return (maxFadeScroll - scroll) / getHorizontalFadingEdgeLength();
-            } else if (getLineCount() == 1) {
-                final int layoutDirection = getLayoutDirection();
-                final int absoluteGravity = Gravity.getAbsoluteGravity(mGravity, layoutDirection);
-                switch (absoluteGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
-                    case Gravity.LEFT:
-                        final int textWidth = (mRight - mLeft) - getCompoundPaddingLeft() -
-                                getCompoundPaddingRight();
-                        final float lineWidth = mLayout.getLineWidth(0);
-                        return (lineWidth - textWidth) / getHorizontalFadingEdgeLength();
-                    case Gravity.RIGHT:
-                        return 0.0f;
-                    case Gravity.CENTER_HORIZONTAL:
-                    case Gravity.FILL_HORIZONTAL:
-                        final int textDirection = mLayout.getParagraphDirection(0);
-                        if (textDirection == Layout.DIR_RIGHT_TO_LEFT) {
-                            return 0.0f;
-                        } else {
-                            return (mLayout.getLineWidth(0) - ((mRight - mLeft) -
-                                getCompoundPaddingLeft() - getCompoundPaddingRight())) /
-                                getHorizontalFadingEdgeLength();
-                        }
-                }
-            }
+        if (isMarqueeFadeEnabled() && mMarquee != null && !mMarquee.isStopped()) {
+            final Marquee marquee = mMarquee;
+            return getHorizontalFadingEdgeStrength(marquee.getMaxFadeScroll(), marquee.getScroll());
+        } else if (getLineCount() == 1) {
+            final float rightEdge = mScrollX + (getWidth() - getCompoundPaddingLeft() -
+                    getCompoundPaddingRight());
+            final float lineRight = getLayout().getLineRight(0);
+            if(lineRight < rightEdge) return 0.0f;
+            return getHorizontalFadingEdgeStrength(rightEdge, lineRight);
         }
         return super.getRightFadingEdgeStrength();
     }
 
+    /**
+     * Calculates the fading edge strength as the ratio of the distance between two
+     * horizontal positions to {@link View#getHorizontalFadingEdgeLength()}. Uses the absolute
+     * value for the distance calculation.
+     *
+     * @param position1 A horizontal position.
+     * @param position2 A horizontal position.
+     * @return Fading edge strength between [0.0f, 1.0f].
+     */
+    @FloatRange(from=0.0, to=1.0)
+    private final float getHorizontalFadingEdgeStrength(float position1, float position2) {
+        final int horizontalFadingEdgeLength = getHorizontalFadingEdgeLength();
+        if(horizontalFadingEdgeLength == 0) return 0.0f;
+        final float diff = Math.abs(position1 - position2);
+        if(diff > horizontalFadingEdgeLength) return 1.0f;
+        return diff / horizontalFadingEdgeLength;
+    }
+
+    private final boolean isMarqueeFadeEnabled() {
+        return mEllipsize == TextUtils.TruncateAt.MARQUEE &&
+                mMarqueeFadeMode != MARQUEE_FADE_SWITCH_SHOW_ELLIPSIS;
+    }
+
     @Override
     protected int computeHorizontalScrollRange() {
         if (mLayout != null) {
@@ -9217,10 +9199,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                     }
                     if (start >= 0 && start <= end && end <= text.length()) {
                         Selection.setSelection((Spannable) text, start, end);
-                        // Make sure selection mode is engaged.
-                        if (mEditor != null) {
-                            mEditor.startSelectionActionMode();
-                        }
                         return true;
                     }
                 }
@@ -9411,16 +9389,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
 
         switch (id) {
             case ID_SELECT_ALL:
-                // This starts an action mode if triggered from another action mode. Text is
-                // highlighted, so that it can be bulk edited, like selectAllOnFocus does. Returns
-                // true even if text is empty.
-                boolean shouldRestartActionMode =
-                        mEditor != null && mEditor.mTextActionMode != null;
-                stopTextActionMode();
                 selectAllText();
-                if (shouldRestartActionMode) {
-                    mEditor.startSelectionActionMode();
-                }
                 return true;
 
             case ID_UNDO:
@@ -9446,7 +9415,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
             case ID_CUT:
                 setPrimaryClip(ClipData.newPlainText(null, getTransformedText(min, max)));
                 deleteText_internal(min, max);
-                stopTextActionMode();
                 return true;
 
             case ID_COPY:
@@ -9702,12 +9670,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
     }
 
     boolean selectAllText() {
-        // Need to hide insert point cursor controller before settings selection, otherwise insert
-        // point cursor controller obtains cursor update event and update cursor with cancelling
-        // selection.
-        if (mEditor != null) {
-            mEditor.hideInsertionPointCursorController();
-        }
         final int length = mText.length();
         Selection.setSelection((Spannable) mText, 0, length);
         return length > 0;
@@ -9746,7 +9708,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                     }
                 }
             }
-            stopTextActionMode();
             sLastCutCopyOrTextChangedTime = 0;
         }
     }
@@ -9759,7 +9720,7 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
             sharingIntent.removeExtra(android.content.Intent.EXTRA_TEXT);
             sharingIntent.putExtra(android.content.Intent.EXTRA_TEXT, selectedText);
             getContext().startActivity(Intent.createChooser(sharingIntent, null));
-            stopTextActionMode();
+            Selection.setSelection((Spannable) mText, getSelectionEnd());
         }
     }
 
@@ -10077,6 +10038,12 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
                 && getAccessibilitySelectionEnd() == end) {
             return;
         }
+        CharSequence text = getIterableTextForAccessibility();
+        if (Math.min(start, end) >= 0 && Math.max(start, end) <= text.length()) {
+            Selection.setSelection((Spannable) text, start, end);
+        } else {
+            Selection.removeSelection((Spannable) text);
+        }
         // Hide all selection controllers used for adjusting selection
         // since we are doing so explicitlty by other means and these
         // controllers interact with how selection behaves.
@@ -10084,12 +10051,6 @@ public class TextView extends View implements ViewTreeObserver.OnPreDrawListener
             mEditor.hideCursorAndSpanControllers();
             mEditor.stopTextActionMode();
         }
-        CharSequence text = getIterableTextForAccessibility();
-        if (Math.min(start, end) >= 0 && Math.max(start, end) <= text.length()) {
-            Selection.setSelection((Spannable) text, start, end);
-        } else {
-            Selection.removeSelection((Spannable) text);
-        }
     }
 
     /** @hide */
index a24d37f..f2fc617 100644 (file)
@@ -22,8 +22,11 @@ import android.annotation.Widget;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
+import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.Parcelable.Creator;
 import android.util.AttributeSet;
+import android.view.View;
 import android.view.accessibility.AccessibilityEvent;
 import com.android.internal.R;
 
@@ -301,5 +304,69 @@ public class TimePicker extends FrameLayout {
             mContext = context;
             mLocale = context.getResources().getConfiguration().locale;
         }
+
+        protected static class SavedState extends View.BaseSavedState {
+            private final int mHour;
+            private final int mMinute;
+            private final boolean mIs24HourMode;
+            private final int mCurrentItemShowing;
+
+            public SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode) {
+                this(superState, hour, minute, is24HourMode, 0);
+            }
+
+            public SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode,
+                    int currentItemShowing) {
+                super(superState);
+                mHour = hour;
+                mMinute = minute;
+                mIs24HourMode = is24HourMode;
+                mCurrentItemShowing = currentItemShowing;
+            }
+
+            private SavedState(Parcel in) {
+                super(in);
+                mHour = in.readInt();
+                mMinute = in.readInt();
+                mIs24HourMode = (in.readInt() == 1);
+                mCurrentItemShowing = in.readInt();
+            }
+
+            public int getHour() {
+                return mHour;
+            }
+
+            public int getMinute() {
+                return mMinute;
+            }
+
+            public boolean is24HourMode() {
+                return mIs24HourMode;
+            }
+
+            public int getCurrentItemShowing() {
+                return mCurrentItemShowing;
+            }
+
+            @Override
+            public void writeToParcel(Parcel dest, int flags) {
+                super.writeToParcel(dest, flags);
+                dest.writeInt(mHour);
+                dest.writeInt(mMinute);
+                dest.writeInt(mIs24HourMode ? 1 : 0);
+                dest.writeInt(mCurrentItemShowing);
+            }
+
+            @SuppressWarnings({"unused", "hiding"})
+            public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
+                public SavedState createFromParcel(Parcel in) {
+                    return new SavedState(in);
+                }
+
+                public SavedState[] newArray(int size) {
+                    return new SavedState[size];
+                }
+            };
+        }
     }
 }
index 05fd4c8..4a24e26 100644 (file)
@@ -21,7 +21,6 @@ import android.content.Context;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.SpannableStringBuilder;
 import android.text.format.DateFormat;
@@ -45,7 +44,6 @@ import com.android.internal.widget.NumericTextView;
 import com.android.internal.widget.NumericTextView.OnValueChangedListener;
 
 import java.util.Calendar;
-import java.util.Locale;
 
 /**
  * A delegate implementing the radial clock-based TimePicker.
@@ -501,9 +499,11 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
-        final SavedState ss = (SavedState) state;
-        initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing());
-        mRadialTimePickerView.invalidate();
+        if (state instanceof SavedState) {
+            final SavedState ss = (SavedState) state;
+            initialize(ss.getHour(), ss.getMinute(), ss.is24HourMode(), ss.getCurrentItemShowing());
+            mRadialTimePickerView.invalidate();
+        }
     }
 
     @Override
@@ -544,70 +544,6 @@ class TimePickerClockDelegate extends TimePicker.AbstractTimePickerDelegate impl
         }
     }
 
-    /**
-     * Used to save / restore state of time picker
-     */
-    private static class SavedState extends View.BaseSavedState {
-
-        private final int mHour;
-        private final int mMinute;
-        private final boolean mIs24HourMode;
-        private final int mCurrentItemShowing;
-
-        private SavedState(Parcelable superState, int hour, int minute, boolean is24HourMode,
-                int currentItemShowing) {
-            super(superState);
-            mHour = hour;
-            mMinute = minute;
-            mIs24HourMode = is24HourMode;
-            mCurrentItemShowing = currentItemShowing;
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            mHour = in.readInt();
-            mMinute = in.readInt();
-            mIs24HourMode = (in.readInt() == 1);
-            mCurrentItemShowing = in.readInt();
-        }
-
-        public int getHour() {
-            return mHour;
-        }
-
-        public int getMinute() {
-            return mMinute;
-        }
-
-        public boolean is24HourMode() {
-            return mIs24HourMode;
-        }
-
-        public int getCurrentItemShowing() {
-            return mCurrentItemShowing;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeInt(mHour);
-            dest.writeInt(mMinute);
-            dest.writeInt(mIs24HourMode ? 1 : 0);
-            dest.writeInt(mCurrentItemShowing);
-        }
-
-        @SuppressWarnings({"unused", "hiding"})
-        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
     private void tryVibrate() {
         mDelegator.performHapticFeedback(HapticFeedbackConstants.CLOCK_TICK);
     }
index 863d409..b113fd9 100644 (file)
@@ -18,7 +18,6 @@ package android.widget;
 
 import android.content.Context;
 import android.content.res.TypedArray;
-import android.os.Parcel;
 import android.os.Parcelable;
 import android.text.format.DateFormat;
 import android.text.format.DateUtils;
@@ -32,7 +31,6 @@ import android.view.inputmethod.InputMethodManager;
 import com.android.internal.R;
 
 import java.util.Calendar;
-import java.util.Locale;
 
 import libcore.icu.LocaleData;
 
@@ -387,14 +385,16 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
 
     @Override
     public Parcelable onSaveInstanceState(Parcelable superState) {
-        return new SavedState(superState, getHour(), getMinute());
+        return new SavedState(superState, getHour(), getMinute(), is24Hour());
     }
 
     @Override
     public void onRestoreInstanceState(Parcelable state) {
-        SavedState ss = (SavedState) state;
-        setHour(ss.getHour());
-        setMinute(ss.getMinute());
+        if (state instanceof SavedState) {
+            final SavedState ss = (SavedState) state;
+            setHour(ss.getHour());
+            setMinute(ss.getMinute());
+        }
     }
 
     @Override
@@ -525,52 +525,6 @@ class TimePickerSpinnerDelegate extends TimePicker.AbstractTimePickerDelegate {
         }
     }
 
-    /**
-     * Used to save / restore state of time picker
-     */
-    private static class SavedState extends View.BaseSavedState {
-        private final int mHour;
-        private final int mMinute;
-
-        private SavedState(Parcelable superState, int hour, int minute) {
-            super(superState);
-            mHour = hour;
-            mMinute = minute;
-        }
-
-        private SavedState(Parcel in) {
-            super(in);
-            mHour = in.readInt();
-            mMinute = in.readInt();
-        }
-
-        public int getHour() {
-            return mHour;
-        }
-
-        public int getMinute() {
-            return mMinute;
-        }
-
-        @Override
-        public void writeToParcel(Parcel dest, int flags) {
-            super.writeToParcel(dest, flags);
-            dest.writeInt(mHour);
-            dest.writeInt(mMinute);
-        }
-
-        @SuppressWarnings({"unused", "hiding"})
-        public static final Parcelable.Creator<SavedState> CREATOR = new Creator<SavedState>() {
-            public SavedState createFromParcel(Parcel in) {
-                return new SavedState(in);
-            }
-
-            public SavedState[] newArray(int size) {
-                return new SavedState[size];
-            }
-        };
-    }
-
     public static String[] getAmPmStrings(Context context) {
         String[] result = new String[2];
         LocaleData d = LocaleData.get(context.getResources().getConfiguration().locale);
index aca93ab..d8d6e56 100644 (file)
@@ -180,14 +180,16 @@ public class LocaleHelper {
      */
     public static final class LocaleInfoComparator implements Comparator<LocaleStore.LocaleInfo> {
         private final Collator mCollator;
+        private final boolean mCountryMode;
 
         /**
          * Constructor.
          *
          * @param sortLocale the locale to be used for sorting.
          */
-        public LocaleInfoComparator(Locale sortLocale) {
+        public LocaleInfoComparator(Locale sortLocale, boolean countryMode) {
             mCollator = Collator.getInstance(sortLocale);
+            mCountryMode = countryMode;
         }
 
         /**
@@ -202,9 +204,9 @@ public class LocaleHelper {
         public int compare(LocaleStore.LocaleInfo lhs, LocaleStore.LocaleInfo rhs) {
             // We don't care about the various suggestion types, just "suggested" (!= 0)
             // and "all others" (== 0)
-            if (lhs.isSuggested() == rhs.isSuggested()) {
+            if (mCountryMode || (lhs.isSuggested() == rhs.isSuggested())) {
                 // They are in the same "bucket" (suggested / others), so we compare the text
-                return mCollator.compare(lhs.getLabel(), rhs.getLabel());
+                return mCollator.compare(lhs.getLabel(mCountryMode), rhs.getLabel(mCountryMode));
             } else {
                 // One locale is suggested and one is not, so we put them in different "buckets"
                 return lhs.isSuggested() ? -1 : 1;
index 956ee8c..2ea225f 100644 (file)
@@ -50,7 +50,6 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
     private Set<LocaleStore.LocaleInfo> mLocaleList;
     private LocaleStore.LocaleInfo mParentLocale;
     private boolean mTranslatedOnly = false;
-    private boolean mCountryMode = false;
 
     /**
      * Other classes can register to be notified when a locale was selected.
@@ -70,15 +69,14 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
             boolean translatedOnly) {
         LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
         boolean shouldShowTheList = localePicker.setListener(context, listener, parent,
-                true /* country mode */, translatedOnly);
+                translatedOnly);
         return shouldShowTheList ? localePicker : null;
     }
 
     public static LocalePickerWithRegion createLanguagePicker(Context context,
             LocaleSelectedListener listener, boolean translatedOnly) {
         LocalePickerWithRegion localePicker = new LocalePickerWithRegion();
-        localePicker.setListener(context, listener, null,
-                false /* language mode */, translatedOnly);
+        localePicker.setListener(context, listener, /* parent */ null, translatedOnly);
         return localePicker;
     }
 
@@ -96,14 +94,7 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
      * "pretending" it was selected, and return false.</p>
      */
     private boolean setListener(Context context, LocaleSelectedListener listener,
-            LocaleStore.LocaleInfo parent, boolean countryMode, boolean translatedOnly) {
-        if (countryMode && (parent == null || parent.getLocale() == null)) {
-            // The list of countries is determined as all the countries where the parent language
-            // is used.
-            throw new IllegalArgumentException("The country selection list needs a parent.");
-        }
-
-        this.mCountryMode = countryMode;
+            LocaleStore.LocaleInfo parent, boolean translatedOnly) {
         this.mParentLocale = parent;
         this.mListener = listener;
         this.mTranslatedOnly = translatedOnly;
@@ -116,7 +107,7 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
             Collections.addAll(langTagsToIgnore, langTags);
         }
 
-        if (countryMode) {
+        if (parent != null) {
             mLocaleList = LocaleStore.getLevelLocales(context,
                     langTagsToIgnore, parent, translatedOnly);
             if (mLocaleList.size() <= 1) {
@@ -138,13 +129,11 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
         super.onCreate(savedInstanceState);
         setHasOptionsMenu(true);
 
-        final Locale sortingLocale = (mCountryMode && mParentLocale != null)
-                ? mParentLocale.getLocale()
-                : Locale.getDefault();
-
-        mAdapter = new SuggestedLocaleAdapter(mLocaleList, mCountryMode);
+        final boolean countryMode = mParentLocale != null;
+        final Locale sortingLocale = countryMode ? mParentLocale.getLocale() : Locale.getDefault();
+        mAdapter = new SuggestedLocaleAdapter(mLocaleList, countryMode);
         final LocaleHelper.LocaleInfoComparator comp =
-                new LocaleHelper.LocaleInfoComparator(sortingLocale);
+                new LocaleHelper.LocaleInfoComparator(sortingLocale, countryMode);
         mAdapter.sort(comp);
         setListAdapter(mAdapter);
     }
@@ -164,12 +153,8 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
     public void onResume() {
         super.onResume();
 
-        if (mCountryMode) {
-            if (mParentLocale == null) {
-                this.getActivity().setTitle(R.string.country_selection_title);
-            } else {
-                this.getActivity().setTitle(mParentLocale.getFullNameNative());
-            }
+        if (mParentLocale != null) {
+            this.getActivity().setTitle(mParentLocale.getFullNameNative());
         } else {
             this.getActivity().setTitle(R.string.language_selection_title);
         }
@@ -182,7 +167,7 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
         final LocaleStore.LocaleInfo locale =
                 (LocaleStore.LocaleInfo) getListAdapter().getItem(position);
 
-        if (mCountryMode || locale.getParent() != null) {
+        if (locale.getParent() != null) {
             if (mListener != null) {
                 mListener.onLocaleSelected(locale);
             }
@@ -205,7 +190,7 @@ public class LocalePickerWithRegion extends ListFragment implements SearchView.O
 
     @Override
     public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
-        if (!mCountryMode) {
+        if (mParentLocale == null) {
             inflater.inflate(R.menu.language_selection_list, menu);
 
             MenuItem mSearchMenuItem = menu.findItem(R.id.locale_search_menu);
index 465c4d8..c4e6675 100644 (file)
@@ -145,11 +145,11 @@ public class LocaleStore {
             return mLangScriptKey;
         }
 
-        String getLabel() {
-            if (getParent() == null || this.isSuggestionOfType(SUGGESTION_TYPE_SIM)) {
-                return getFullNameNative();
-            } else {
+        String getLabel(boolean countryMode) {
+            if (countryMode) {
                 return getFullCountryNameNative();
+            } else {
+                return getFullNameNative();
             }
         }
 
@@ -311,9 +311,7 @@ public class LocaleStore {
             if (level == 2) {
                 if (parent != null) { // region selection
                     if (parentId.equals(li.getParent().toLanguageTag())) {
-                        if (!li.isSuggestionOfType(LocaleInfo.SUGGESTION_TYPE_SIM)) {
-                            result.add(li);
-                        }
+                        result.add(li);
                     }
                 } else { // language selection
                     if (li.isSuggestionOfType(LocaleInfo.SUGGESTION_TYPE_SIM)) {
index 0d4a5aa..98102ea 100644 (file)
@@ -156,7 +156,7 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
 
                 TextView text = (TextView) convertView.findViewById(R.id.locale);
                 LocaleStore.LocaleInfo item = (LocaleStore.LocaleInfo) getItem(position);
-                text.setText(item.getLabel());
+                text.setText(item.getLabel(mCountryMode));
                 text.setTextLocale(item.getLocale());
                 if (mCountryMode) {
                     int layoutDir = TextUtils.getLayoutDirectionFromLocale(item.getParent());
@@ -171,6 +171,9 @@ public class SuggestedLocaleAdapter extends BaseAdapter implements Filterable {
     }
 
     private boolean showHeaders() {
+        if (mCountryMode) { // never show suggestions in country mode
+            return false;
+        }
         return mSuggestionCount != 0 && mSuggestionCount != mLocaleOptions.size();
     }
 
index 4e48e45..f04bcf2 100644 (file)
@@ -547,23 +547,25 @@ public class InputMethodUtils {
         LocaleUtils.filterByLanguage(keyboardSubtypes, sSubtypeToLocale, systemLocales,
                 applicableSubtypes);
 
-        boolean hasAsciiCapableKeyboard = false;
-        final int numApplicationSubtypes = applicableSubtypes.size();
-        for (int i = 0; i < numApplicationSubtypes; ++i) {
-            final InputMethodSubtype subtype = applicableSubtypes.get(i);
-            if (subtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
-                hasAsciiCapableKeyboard = true;
-                break;
-            }
-        }
-        if (!hasAsciiCapableKeyboard) {
-            final int numKeyboardSubtypes = keyboardSubtypes.size();
-            for (int i = 0; i < numKeyboardSubtypes; ++i) {
-                final InputMethodSubtype subtype = keyboardSubtypes.get(i);
-                final String mode = subtype.getMode();
-                if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey(
-                        TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) {
-                    applicableSubtypes.add(subtype);
+        if (!applicableSubtypes.isEmpty()) {
+            boolean hasAsciiCapableKeyboard = false;
+            final int numApplicationSubtypes = applicableSubtypes.size();
+            for (int i = 0; i < numApplicationSubtypes; ++i) {
+                final InputMethodSubtype subtype = applicableSubtypes.get(i);
+                if (subtype.containsExtraValueKey(TAG_ASCII_CAPABLE)) {
+                    hasAsciiCapableKeyboard = true;
+                    break;
+                }
+            }
+            if (!hasAsciiCapableKeyboard) {
+                final int numKeyboardSubtypes = keyboardSubtypes.size();
+                for (int i = 0; i < numKeyboardSubtypes; ++i) {
+                    final InputMethodSubtype subtype = keyboardSubtypes.get(i);
+                    final String mode = subtype.getMode();
+                    if (SUBTYPE_MODE_KEYBOARD.equals(mode) && subtype.containsExtraValueKey(
+                            TAG_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE)) {
+                        applicableSubtypes.add(subtype);
+                    }
                 }
             }
         }
index f178c8c..1b52146 100644 (file)
@@ -754,8 +754,7 @@ public final class BatteryStatsHelper {
         try {
             ParcelFileDescriptor pfd = service.getStatisticsStream();
             if (pfd != null) {
-                FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd);
-                try {
+                try (FileInputStream fis = new ParcelFileDescriptor.AutoCloseInputStream(pfd)) {
                     byte[] data = readFully(fis, MemoryFile.getSize(pfd.getFileDescriptor()));
                     Parcel parcel = Parcel.obtain();
                     parcel.unmarshall(data, 0, data.length);
index 6ad9e20..3abea26 100644 (file)
@@ -36,6 +36,7 @@ import android.text.Hyphenator;
 import android.util.EventLog;
 import android.util.Log;
 import android.webkit.WebViewFactory;
+import android.widget.TextView;
 
 import com.android.internal.os.InstallerConnection.InstallerException;
 
@@ -214,6 +215,7 @@ public class ZygoteInit {
 
     private static void preloadTextResources() {
         Hyphenator.init();
+        TextView.preloadFontCache();
     }
 
     /**
@@ -497,11 +499,11 @@ public class ZygoteInit {
 
         try {
             for (String classPathElement : classPathElements) {
+                // System server is fully AOTed and never profiled
+                // for profile guided compilation.
                 final int dexoptNeeded = DexFile.getDexOptNeeded(
-                        classPathElement, "*", instructionSet, false /* defer */);
+                        classPathElement, instructionSet, DexFile.COMPILATION_TYPE_FULL);
                 if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
-                    // System server is fully AOTed and never profiled
-                    // for profile guided compilation.
                     installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
                             dexoptNeeded, 0 /*dexFlags*/, null /*volumeUuid*/,
                             false /*useProfiles*/);
index 451078b..2653745 100644 (file)
@@ -21,7 +21,9 @@ import android.content.Context;
 import android.os.Handler;
 import android.os.Message;
 
-/**
+import com.android.internal.annotations.VisibleForTesting;
+
+ /**
  * An AlarmListener that sends the specified message to a Handler and keeps the system awake until
  * the message is processed.
  *
@@ -36,9 +38,13 @@ import android.os.Message;
  */
 public class WakeupMessage implements AlarmManager.OnAlarmListener {
     private final AlarmManager mAlarmManager;
-    private final Handler mHandler;
-    private final String mCmdName;
-    private final int mCmd, mArg1, mArg2;
+
+    @VisibleForTesting
+    protected final Handler mHandler;
+    @VisibleForTesting
+    protected final String mCmdName;
+    @VisibleForTesting
+    protected final int mCmd, mArg1, mArg2;
     private boolean mScheduled;
 
     public WakeupMessage(Context context, Handler handler,
index c4ed2e1..78c5e34 100644 (file)
@@ -65,6 +65,8 @@ public class ImageFloatingTextView extends TextView {
                 .setTextDirection(getTextDirectionHeuristic())
                 .setLineSpacing(getLineSpacingExtra(), getLineSpacingMultiplier())
                 .setIncludePad(getIncludeFontPadding())
+                .setEllipsize(shouldEllipsize ? effectiveEllipsize : null)
+                .setEllipsizedWidth(ellipsisWidth)
                 .setBreakStrategy(Layout.BREAK_STRATEGY_HIGH_QUALITY)
                 .setHyphenationFrequency(Layout.HYPHENATION_FREQUENCY_FULL);
         // we set the endmargin on the first 2 lines. this works just in our case but that's
index cbc735f..795012d 100644 (file)
@@ -896,8 +896,7 @@ public class LockPatternUtils {
      * @return true if device is file encrypted
      */
     public static boolean isFileEncryptionEnabled() {
-        final String status = SystemProperties.get("ro.crypto.type", "");
-        return "file".equalsIgnoreCase(status);
+        return StorageManager.isFileBasedEncryptionEnabled();
     }
 
     /**
diff --git a/core/java/com/android/server/net/NetworkPinner.java b/core/java/com/android/server/net/NetworkPinner.java
new file mode 100644 (file)
index 0000000..d922a48
--- /dev/null
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.net;
+
+import android.content.Context;
+import android.net.ConnectivityManager;
+import android.net.ConnectivityManager.NetworkCallback;
+import android.net.Network;
+import android.net.NetworkRequest;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+
+/**
+ * A class that pins a process to the first network that satisfies a particular NetworkRequest.
+ *
+ * We use this to maintain compatibility with pre-M apps that call WifiManager.enableNetwork()
+ * to connect to a Wi-Fi network that has no Internet access, and then assume that they will be
+ * able to use that network because it's the system default.
+ *
+ * In order to maintain compatibility with apps that call setProcessDefaultNetwork themselves,
+ * we try not to set the default network unless they have already done so, and we try not to
+ * clear the default network unless we set it ourselves.
+ *
+ * This should maintain behaviour that's compatible with L, which would pin the whole system to
+ * any wifi network that was created via enableNetwork(..., true) until that network
+ * disconnected.
+ *
+ * Note that while this hack allows network traffic to flow, it is quite limited. For example:
+ *
+ * 1. setProcessDefaultNetwork only affects this process, so:
+ *    - Any subprocesses spawned by this process will not be pinned to Wi-Fi.
+ *    - If this app relies on any other apps on the device also being on Wi-Fi, that won't work
+ *      either, because other apps on the device will not be pinned.
+ * 2. The behaviour of other APIs is not modified. For example:
+ *    - getActiveNetworkInfo will return the system default network, not Wi-Fi.
+ *    - There will be no CONNECTIVITY_ACTION broadcasts about TYPE_WIFI.
+ *    - getProcessDefaultNetwork will not return null, so if any apps are relying on that, they
+ *      will be surprised as well.
+ *
+ * This class is a per-process singleton because the process default network is a per-process
+ * singleton.
+ *
+ */
+public class NetworkPinner extends NetworkCallback {
+
+    private static final String TAG = NetworkPinner.class.getSimpleName();
+
+    @VisibleForTesting
+    protected static final Object sLock = new Object();
+
+    @GuardedBy("sLock")
+    private static ConnectivityManager sCM;
+    @GuardedBy("sLock")
+    private static Callback sCallback;
+    @VisibleForTesting
+    @GuardedBy("sLock")
+    protected static Network sNetwork;
+
+    private static void maybeInitConnectivityManager(Context context) {
+        // TODO: what happens if an app calls a WifiManager API before ConnectivityManager is
+        // registered? Can we fix this by starting ConnectivityService before WifiService?
+        if (sCM == null) {
+            // Getting a ConnectivityManager does not leak the calling context, because it stores
+            // the application context and not the calling context.
+            sCM = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
+            if (sCM == null) {
+                throw new IllegalStateException("Bad luck, ConnectivityService not started.");
+            }
+        }
+    }
+
+    private static class Callback extends NetworkCallback {
+        @Override
+        public void onAvailable(Network network) {
+            synchronized(sLock) {
+                if (this != sCallback) return;
+
+                if (sCM.getBoundNetworkForProcess() == null && sNetwork == null) {
+                    sCM.bindProcessToNetwork(network);
+                    sNetwork = network;
+                    Log.d(TAG, "Wifi alternate reality enabled on network " + network);
+                }
+                sLock.notify();
+            }
+        }
+
+        @Override
+        public void onLost(Network network) {
+            synchronized (sLock) {
+                if (this != sCallback) return;
+
+                if (network.equals(sNetwork) && network.equals(sCM.getBoundNetworkForProcess())) {
+                    unpin();
+                    Log.d(TAG, "Wifi alternate reality disabled on network " + network);
+                }
+                sLock.notify();
+            }
+        }
+    }
+
+    public static void pin(Context context, NetworkRequest request) {
+        synchronized (sLock) {
+            if (sCallback == null) {
+                maybeInitConnectivityManager(context);
+                sCallback = new Callback();
+                try {
+                    sCM.registerNetworkCallback(request, sCallback);
+                } catch (SecurityException e) {
+                    Log.d(TAG, "Failed to register network callback", e);
+                    sCallback = null;
+                }
+            }
+        }
+    }
+
+    public static void unpin() {
+        synchronized (sLock) {
+            if (sCallback != null) {
+                try {
+                    sCM.bindProcessToNetwork(null);
+                    sCM.unregisterNetworkCallback(sCallback);
+                } catch (SecurityException e) {
+                    Log.d(TAG, "Failed to unregister network callback", e);
+                }
+                sCallback = null;
+                sNetwork = null;
+            }
+        }
+    }
+}
index a8d684d..623b603 100644 (file)
@@ -7,7 +7,7 @@ LOCAL_CFLAGS += -U__APPLE__
 LOCAL_CFLAGS += -Wno-unused-parameter
 LOCAL_CFLAGS += -Wno-non-virtual-dtor
 LOCAL_CFLAGS += -Wno-maybe-uninitialized -Wno-parentheses
-#LOCAL_CFLAGS += -DHWUI_NEW_OPS
+LOCAL_CFLAGS += -DHWUI_NEW_OPS
 LOCAL_CPPFLAGS += -Wno-conversion-null
 
 ifeq ($(TARGET_ARCH), arm)
@@ -33,6 +33,7 @@ LOCAL_SRC_FILES:= \
     com_android_internal_content_NativeLibraryHelper.cpp \
     com_google_android_gles_jni_EGLImpl.cpp \
     com_google_android_gles_jni_GLImpl.cpp.arm \
+    android_app_Activity.cpp \
     android_app_ApplicationLoaders.cpp \
     android_app_NativeActivity.cpp \
     android_auditing_SecurityLog.cpp \
@@ -189,7 +190,6 @@ LOCAL_C_INCLUDES += \
     $(call include-path-for, bluedroid) \
     $(call include-path-for, libhardware)/hardware \
     $(call include-path-for, libhardware_legacy)/hardware_legacy \
-    $(TOP)/frameworks/av/include \
     $(TOP)/frameworks/base/media/jni \
     $(TOP)/system/core/base/include \
     $(TOP)/system/core/include \
@@ -260,7 +260,8 @@ LOCAL_SHARED_LIBRARIES := \
     libprocessgroup \
     libnativebridge \
     libradio_metadata \
-    libnativeloader
+    libnativeloader \
+    libmemunreachable \
 
 LOCAL_SHARED_LIBRARIES += \
     libhwui \
index 6ed07a7..2a04526 100644 (file)
@@ -178,6 +178,7 @@ extern int register_android_backup_FileBackupHelperBase(JNIEnv *env);
 extern int register_android_backup_BackupHelperDispatcher(JNIEnv *env);
 extern int register_android_app_backup_FullBackup(JNIEnv *env);
 extern int register_android_app_ApplicationLoaders(JNIEnv* env);
+extern int register_android_app_Activity(JNIEnv *env);
 extern int register_android_app_ActivityThread(JNIEnv *env);
 extern int register_android_app_NativeActivity(JNIEnv *env);
 extern int register_android_media_RemoteDisplay(JNIEnv *env);
@@ -1373,6 +1374,7 @@ static const RegJNIRec gRegJNI[] = {
     REG_JNI(register_android_backup_BackupHelperDispatcher),
     REG_JNI(register_android_app_backup_FullBackup),
     REG_JNI(register_android_app_ApplicationLoaders),
+    REG_JNI(register_android_app_Activity),
     REG_JNI(register_android_app_ActivityThread),
     REG_JNI(register_android_app_NativeActivity),
     REG_JNI(register_android_util_jar_StrictJarFile),
index 8b248b0..29c1075 100644 (file)
@@ -555,6 +555,12 @@ static jobject nativeDecodeFileDescriptor(JNIEnv* env, jobject clazz, jobject fi
     std::unique_ptr<SkFILEStream> fileStream(new SkFILEStream(file,
             SkFILEStream::kCallerPasses_Ownership));
 
+    // If there is no offset for the file descriptor, we use SkFILEStream directly.
+    if (::lseek(descriptor, 0, SEEK_CUR) == 0) {
+        assert(isSeekable(dupDescriptor));
+        return doDecode(env, fileStream.release(), padding, bitmapFactoryOptions);
+    }
+
     // Use a buffered stream. Although an SkFILEStream can be rewound, this
     // ensures that SkImageDecoder::Factory never rewinds beyond the
     // current position of the file descriptor.
@@ -584,7 +590,7 @@ static jobject nativeDecodeByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
 
 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
-    return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
+    return isSeekable(descriptor) ? JNI_TRUE : JNI_FALSE;
 }
 
 jobject decodeBitmap(JNIEnv* env, void* data, size_t size) {
index 4f9ce8b..5fa445e 100644 (file)
@@ -116,3 +116,7 @@ jobject android::nullObjectReturn(const char msg[]) {
     }
     return NULL;
 }
+
+bool android::isSeekable(int descriptor) {
+    return ::lseek64(descriptor, 0, SEEK_CUR) != -1;
+}
index c0b9410..d1a74a0 100644 (file)
@@ -68,6 +68,10 @@ private:
 
 jobject nullObjectReturn(const char msg[]);
 
+/** Check if the file descriptor is seekable.
+ */
+bool isSeekable(int descriptor);
+
 }; // namespace android
 
 #endif  // _ANDROID_GRAPHICS_UTILS_H_
diff --git a/core/jni/android_app_Activity.cpp b/core/jni/android_app_Activity.cpp
new file mode 100644 (file)
index 0000000..56f4f01
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <poll.h>
+
+#include <string>
+
+#include "core_jni_helpers.h"
+
+extern "C" void android_dlwarning(void*, void (*)(void*, const char*));
+
+namespace android
+{
+
+static jstring getDlWarning_native(JNIEnv* env, jobject) {
+    std::string msg;
+    android_dlwarning(&msg, [](void* obj, const char* msg) {
+        if (msg != nullptr) {
+            *reinterpret_cast<std::string*>(obj) = msg;
+        }
+    });
+
+    return msg.empty() ? nullptr : env->NewStringUTF(msg.c_str());
+}
+
+static const JNINativeMethod g_methods[] = {
+    { "getDlWarning",
+        "()Ljava/lang/String;",
+        reinterpret_cast<void*>(getDlWarning_native) },
+};
+
+static const char* const kActivityPathName = "android/app/Activity";
+
+int register_android_app_Activity(JNIEnv* env) {
+    return RegisterMethodsOrDie(env, kActivityPathName, g_methods, NELEM(g_methods));
+}
+
+} // namespace android
index 7930027..f37fd78 100644 (file)
@@ -33,9 +33,9 @@
 #include "core_jni_helpers.h"
 #include "android_runtime/android_hardware_camera2_CameraMetadata.h"
 
+#include <android/hardware/ICameraService.h>
 #include <binder/IServiceManager.h>
 #include <camera/CameraMetadata.h>
-#include <camera/ICameraService.h>
 #include <camera/VendorTagDescriptor.h>
 #include <nativehelper/ScopedUtfChars.h>
 #include <nativehelper/ScopedPrimitiveArray.h>
@@ -906,32 +906,35 @@ static jint CameraMetadata_getTypeFromTag(JNIEnv *env, jobject thiz, jint tag) {
 
 static jint CameraMetadata_setupGlobalVendorTagDescriptor(JNIEnv *env, jobject thiz) {
     const String16 NAME("media.camera");
-    sp<ICameraService> cameraService;
+    sp<hardware::ICameraService> cameraService;
     status_t err = getService(NAME, /*out*/&cameraService);
 
     if (err != OK) {
         ALOGE("%s: Failed to get camera service, received error %s (%d)", __FUNCTION__,
                 strerror(-err), err);
-        return err;
+        return hardware::ICameraService::ERROR_DISCONNECTED;
     }
 
-    sp<VendorTagDescriptor> desc;
-    err = cameraService->getCameraVendorTagDescriptor(/*out*/desc);
+    sp<VendorTagDescriptor> desc = new VendorTagDescriptor();
+    binder::Status res = cameraService->getCameraVendorTagDescriptor(/*out*/desc.get());
 
-    if (err == -EOPNOTSUPP) {
-        ALOGW("%s: Camera HAL too old; does not support vendor tags", __FUNCTION__);
+    if (res.serviceSpecificErrorCode() == hardware::ICameraService::ERROR_DISCONNECTED) {
+        // No camera module available, not an error on devices with no cameras
         VendorTagDescriptor::clearGlobalVendorTagDescriptor();
-
         return OK;
-    } else if (err != OK) {
-        ALOGE("%s: Failed to setup vendor tag descriptors, received error %s (%d)",
-                __FUNCTION__, strerror(-err), err);
-        return err;
+    } else if (!res.isOk()) {
+        VendorTagDescriptor::clearGlobalVendorTagDescriptor();
+        ALOGE("%s: Failed to setup vendor tag descriptors: %s",
+                __FUNCTION__, res.toString8().string());
+        return res.serviceSpecificErrorCode();
     }
 
     err = VendorTagDescriptor::setAsGlobalVendorTagDescriptor(desc);
 
-    return err;
+    if (err != OK) {
+        return hardware::ICameraService::ERROR_INVALID_OPERATION;
+    }
+    return OK;
 }
 
 } // extern "C"
index cb0abb6..c6baf1c 100644 (file)
@@ -80,6 +80,13 @@ using namespace img_utils;
         return nullptr; \
     }
 
+#define BAIL_IF_EXPR_RET_NULL_SP(expr, jnienv, tagId, writer) \
+    if (expr) { \
+        jniThrowExceptionFmt(jnienv, "java/lang/IllegalArgumentException", \
+                "Invalid metadata for tag %s (%x)", (writer)->getTagName(tagId), (tagId)); \
+        return nullptr; \
+    }
+
 
 #define ANDROID_DNGCREATOR_CTX_JNI_ID     "mNativeContext"
 
@@ -195,8 +202,8 @@ private:
 NativeContext::NativeContext(const CameraMetadata& characteristics, const CameraMetadata& result) :
         mCharacteristics(std::make_shared<CameraMetadata>(characteristics)),
         mResult(std::make_shared<CameraMetadata>(result)), mThumbnailWidth(0),
-        mThumbnailHeight(0), mOrientation(0), mThumbnailSet(false), mGpsSet(false),
-        mDescriptionSet(false), mCaptureTimeSet(false) {}
+        mThumbnailHeight(0), mOrientation(TAG_ORIENTATION_UNKNOWN), mThumbnailSet(false),
+        mGpsSet(false), mDescriptionSet(false), mCaptureTimeSet(false) {}
 
 NativeContext::~NativeContext() {}
 
@@ -1096,7 +1103,7 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
 
     {
         // Set orientation
-        uint16_t orientation = 1; // Normal
+        uint16_t orientation = TAG_ORIENTATION_NORMAL;
         BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_ORIENTATION, 1, &orientation, TIFF_IFD_0),
                 env, TAG_ORIENTATION, writer);
     }
@@ -1138,12 +1145,27 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
     }
 
     {
-        // Set blacklevel tags
+        // Set blacklevel tags, using dynamic black level if available
         camera_metadata_entry entry =
-                characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
-        BAIL_IF_EMPTY_RET_NULL_SP(entry, env, TAG_BLACKLEVEL, writer);
-        const uint32_t* blackLevel = reinterpret_cast<const uint32_t*>(entry.data.i32);
-        BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, entry.count, blackLevel,
+                results.find(ANDROID_SENSOR_DYNAMIC_BLACK_LEVEL);
+        uint32_t blackLevelRational[8] = {0};
+        if (entry.count != 0) {
+            BAIL_IF_EXPR_RET_NULL_SP(entry.count != 4, env, TAG_BLACKLEVEL, writer);
+            for (size_t i = 0; i < entry.count; i++) {
+                blackLevelRational[i * 2] = static_cast<uint32_t>(entry.data.f[i] * 100);
+                blackLevelRational[i * 2 + 1] = 100;
+            }
+        } else {
+            // Fall back to static black level which is guaranteed
+            entry = characteristics.find(ANDROID_SENSOR_BLACK_LEVEL_PATTERN);
+            BAIL_IF_EXPR_RET_NULL_SP(entry.count != 4, env, TAG_BLACKLEVEL, writer);
+            for (size_t i = 0; i < entry.count; i++) {
+                blackLevelRational[i * 2] = static_cast<uint32_t>(entry.data.i32[i]);
+                blackLevelRational[i * 2 + 1] = 1;
+            }
+
+        }
+        BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BLACKLEVEL, 4, blackLevelRational,
                 TIFF_IFD_0), env, TAG_BLACKLEVEL, writer);
 
         uint16_t repeatDim[2] = {2, 2};
@@ -1913,8 +1935,10 @@ static sp<TiffWriter> DngCreator_setup(JNIEnv* env, jobject thiz, uint32_t image
 
         {
             // Set bits per sample
-            uint16_t bits = BITS_PER_RGB_SAMPLE;
-            BAIL_IF_INVALID_RET_NULL_SP(writer->addEntry(TAG_BITSPERSAMPLE, 1, &bits, TIFF_IFD_0),
+            uint16_t bits[SAMPLES_PER_RGB_PIXEL];
+            for (int i = 0; i < SAMPLES_PER_RGB_PIXEL; i++) bits[i] = BITS_PER_RGB_SAMPLE;
+            BAIL_IF_INVALID_RET_NULL_SP(
+                    writer->addEntry(TAG_BITSPERSAMPLE, SAMPLES_PER_RGB_PIXEL, bits, TIFF_IFD_0),
                     env, TAG_BITSPERSAMPLE, writer);
         }
 
index f1ea7ec..80f9d57 100644 (file)
@@ -29,6 +29,7 @@
 
 #include <gui/Surface.h>
 #include <gui/IGraphicBufferProducer.h>
+#include <gui/IProducerListener.h>
 #include <ui/GraphicBuffer.h>
 #include <system/window.h>
 #include <hardware/camera3.h>
@@ -93,27 +94,17 @@ static void rgbToYuv420(uint8_t* rgbBuf, size_t width, size_t height, android_yc
             cStep, yStride, cStride);
 }
 
-static status_t configureSurface(const sp<ANativeWindow>& anw,
-                                 int32_t width,
-                                 int32_t height,
-                                 int32_t pixelFmt,
-                                 int32_t maxBufferSlack) {
+static status_t connectSurface(const sp<Surface>& surface, int32_t maxBufferSlack) {
     status_t err = NO_ERROR;
-    err = native_window_set_buffers_dimensions(anw.get(), width, height);
-    if (err != NO_ERROR) {
-        ALOGE("%s: Failed to set native window buffer dimensions, error %s (%d).", __FUNCTION__,
-                strerror(-err), err);
-        return err;
-    }
 
-    err = native_window_set_buffers_format(anw.get(), pixelFmt);
-    if (err != NO_ERROR) {
-        ALOGE("%s: Failed to set native window buffer format, error %s (%d).", __FUNCTION__,
+    err = surface->connect(NATIVE_WINDOW_API_CAMERA, /*listener*/NULL);
+    if (err != OK) {
+        ALOGE("%s: Unable to connect to surface, error %s (%d).", __FUNCTION__,
                 strerror(-err), err);
         return err;
     }
 
-    err = native_window_set_usage(anw.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
+    err = native_window_set_usage(surface.get(), GRALLOC_USAGE_SW_WRITE_OFTEN);
     if (err != NO_ERROR) {
         ALOGE("%s: Failed to set native window usage flag, error %s (%d).", __FUNCTION__,
                 strerror(-err), err);
@@ -121,19 +112,17 @@ static status_t configureSurface(const sp<ANativeWindow>& anw,
     }
 
     int minUndequeuedBuffers;
-    err = anw.get()->query(anw.get(),
-            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-            &minUndequeuedBuffers);
+    err = static_cast<ANativeWindow*>(surface.get())->query(surface.get(),
+            NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
     if (err != NO_ERROR) {
         ALOGE("%s: Failed to get native window min undequeued buffers, error %s (%d).",
                 __FUNCTION__, strerror(-err), err);
         return err;
     }
 
-    ALOGV("%s: Setting buffer count to %d, size to (%dx%d), fmt (0x%x)", __FUNCTION__,
-          maxBufferSlack + 1 + minUndequeuedBuffers,
-          width, height, pixelFmt);
-    err = native_window_set_buffer_count(anw.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
+    ALOGV("%s: Setting buffer count to %d", __FUNCTION__,
+            maxBufferSlack + 1 + minUndequeuedBuffers);
+    err = native_window_set_buffer_count(surface.get(), maxBufferSlack + 1 + minUndequeuedBuffers);
     if (err != NO_ERROR) {
         ALOGE("%s: Failed to set native window buffer count, error %s (%d).", __FUNCTION__,
                 strerror(-err), err);
@@ -509,6 +498,26 @@ static jint LegacyCameraDevice_nativeDetectSurfaceUsageFlags(JNIEnv* env, jobjec
     return usage;
 }
 
+static jint LegacyCameraDevice_nativeDisconnectSurface(JNIEnv* env, jobject thiz,
+          jobject surface) {
+    ALOGV("nativeDisconnectSurface");
+    if (surface == nullptr) return NO_ERROR;
+
+    sp<ANativeWindow> anw;
+    if ((anw = getNativeWindow(env, surface)) == NULL) {
+        ALOGV("Buffer queue has already been abandoned.");
+        return NO_ERROR;
+    }
+
+    status_t err = native_window_api_disconnect(anw.get(), NATIVE_WINDOW_API_CAMERA);
+    if(err != NO_ERROR) {
+        jniThrowException(env, "Ljava/lang/UnsupportedOperationException;",
+            "Error while disconnecting surface");
+        return err;
+    }
+    return NO_ERROR;
+}
+
 static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject thiz,
         jobject surfaceTexture, jintArray dimens) {
     ALOGV("nativeDetectTextureDimens");
@@ -540,15 +549,14 @@ static jint LegacyCameraDevice_nativeDetectTextureDimens(JNIEnv* env, jobject th
     return NO_ERROR;
 }
 
-static jint LegacyCameraDevice_nativeConfigureSurface(JNIEnv* env, jobject thiz, jobject surface,
-        jint width, jint height, jint pixelFormat) {
-    ALOGV("nativeConfigureSurface");
-    sp<ANativeWindow> anw;
-    if ((anw = getNativeWindow(env, surface)) == NULL) {
-        ALOGE("%s: Could not retrieve native window from surface.", __FUNCTION__);
+static jint LegacyCameraDevice_nativeConnectSurface(JNIEnv* env, jobject thiz, jobject surface) {
+    ALOGV("nativeConnectSurface");
+    sp<Surface> s;
+    if ((s = getSurface(env, surface)) == NULL) {
+        ALOGE("%s: Could not retrieve surface.", __FUNCTION__);
         return BAD_VALUE;
     }
-    status_t err = configureSurface(anw, width, height, pixelFormat, CAMERA_DEVICE_BUFFER_SLACK);
+    status_t err = connectSurface(s, CAMERA_DEVICE_BUFFER_SLACK);
     if (err != NO_ERROR) {
         ALOGE("%s: Error while configuring surface %s (%d).", __FUNCTION__, strerror(-err), err);
         return err;
@@ -740,9 +748,9 @@ static const JNINativeMethod gCameraDeviceMethods[] = {
     { "nativeDetectSurfaceDimens",
     "(Landroid/view/Surface;[I)I",
     (void *)LegacyCameraDevice_nativeDetectSurfaceDimens },
-    { "nativeConfigureSurface",
-    "(Landroid/view/Surface;III)I",
-    (void *)LegacyCameraDevice_nativeConfigureSurface },
+    { "nativeConnectSurface",
+    "(Landroid/view/Surface;)I",
+    (void *)LegacyCameraDevice_nativeConnectSurface },
     { "nativeProduceFrame",
     "(Landroid/view/Surface;[BIII)I",
     (void *)LegacyCameraDevice_nativeProduceFrame },
@@ -773,6 +781,9 @@ static const JNINativeMethod gCameraDeviceMethods[] = {
     { "nativeSetScalingMode",
     "(Landroid/view/Surface;I)I",
     (void *)LegacyCameraDevice_nativeSetScalingMode },
+    { "nativeDisconnectSurface",
+    "(Landroid/view/Surface;)I",
+    (void *)LegacyCameraDevice_nativeDisconnectSurface },
 };
 
 // Get all the required offsets in java class and register native functions
index 2fb7498..1eb0111 100644 (file)
@@ -320,7 +320,7 @@ android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
 static jint
 android_media_AudioSystem_newAudioSessionId(JNIEnv *env, jobject thiz)
 {
-    return AudioSystem::newAudioUniqueId();
+    return AudioSystem::newAudioUniqueId(AUDIO_UNIQUE_ID_USE_SESSION);
 }
 
 static jint
index defb88a..880a79c 100644 (file)
 #include <net/if.h>
 #include <linux/filter.h>
 #include <linux/if.h>
+#include <linux/if_arp.h>
 #include <linux/if_ether.h>
 #include <linux/if_packet.h>
 #include <net/if_ether.h>
+#include <netinet/icmp6.h>
 #include <netinet/ip.h>
+#include <netinet/ip6.h>
 #include <netinet/udp.h>
 #include <cutils/properties.h>
 
@@ -64,10 +67,9 @@ static jint android_net_utils_resetConnections(JNIEnv* env, jobject clazz,
 
 static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobject javaFd)
 {
-    int fd = jniGetFDFromFileDescriptor(env, javaFd);
     uint32_t ip_offset = sizeof(ether_header);
     uint32_t proto_offset = ip_offset + offsetof(iphdr, protocol);
-    uint32_t flags_offset = ip_offset +  offsetof(iphdr, frag_off);
+    uint32_t flags_offset = ip_offset + offsetof(iphdr, frag_off);
     uint32_t dport_indirect_offset = ip_offset + offsetof(udphdr, dest);
     struct sock_filter filter_code[] = {
         // Check the protocol is UDP.
@@ -94,6 +96,45 @@ static void android_net_utils_attachDhcpFilter(JNIEnv *env, jobject clazz, jobje
         filter_code,
     };
 
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
+    if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
+        jniThrowExceptionFmt(env, "java/net/SocketException",
+                "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
+    }
+}
+
+static void android_net_utils_attachRaFilter(JNIEnv *env, jobject clazz, jobject javaFd,
+        jint hardwareAddressType)
+{
+    if (hardwareAddressType != ARPHRD_ETHER) {
+        jniThrowExceptionFmt(env, "java/net/SocketException",
+                "attachRaFilter only supports ARPHRD_ETHER");
+        return;
+    }
+
+    uint32_t ipv6_offset = sizeof(ether_header);
+    uint32_t ipv6_next_header_offset = ipv6_offset + offsetof(ip6_hdr, ip6_nxt);
+    uint32_t icmp6_offset = ipv6_offset + sizeof(ip6_hdr);
+    uint32_t icmp6_type_offset = icmp6_offset + offsetof(icmp6_hdr, icmp6_type);
+    struct sock_filter filter_code[] = {
+        // Check IPv6 Next Header is ICMPv6.
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  ipv6_next_header_offset),
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    IPPROTO_ICMPV6, 0, 3),
+
+        // Check ICMPv6 type is Router Advertisement.
+        BPF_STMT(BPF_LD  | BPF_B   | BPF_ABS,  icmp6_type_offset),
+        BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K,    ND_ROUTER_ADVERT, 0, 1),
+
+        // Accept or reject.
+        BPF_STMT(BPF_RET | BPF_K,              0xffff),
+        BPF_STMT(BPF_RET | BPF_K,              0)
+    };
+    struct sock_fprog filter = {
+        sizeof(filter_code) / sizeof(filter_code[0]),
+        filter_code,
+    };
+
+    int fd = jniGetFDFromFileDescriptor(env, javaFd);
     if (setsockopt(fd, SOL_SOCKET, SO_ATTACH_FILTER, &filter, sizeof(filter)) != 0) {
         jniThrowExceptionFmt(env, "java/net/SocketException",
                 "setsockopt(SO_ATTACH_FILTER): %s", strerror(errno));
@@ -148,6 +189,7 @@ static const JNINativeMethod gNetworkUtilMethods[] = {
     { "protectFromVpn", "(I)Z", (void*)android_net_utils_protectFromVpn },
     { "queryUserAccess", "(II)Z", (void*)android_net_utils_queryUserAccess },
     { "attachDhcpFilter", "(Ljava/io/FileDescriptor;)V", (void*) android_net_utils_attachDhcpFilter },
+    { "attachRaFilter", "(Ljava/io/FileDescriptor;I)V", (void*) android_net_utils_attachRaFilter },
 };
 
 int register_android_net_NetworkUtils(JNIEnv* env)
index 2d69eaa..59b8911 100644 (file)
@@ -2012,22 +2012,35 @@ exit:
 static void
 android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B
   (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jbyte name) {
+    jniThrowException(_env, "java/lang/UnsupportedOperationException", "deprecated");
+}
+
+/* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
+static void
+android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2
+  (JNIEnv *_env, jobject _this, jint program, jint index, jint bufsize, jobject length_buf, jobject size_buf, jobject type_buf, jobject name_buf) {
     jintArray _lengthArray = (jintArray) 0;
     jint _lengthBufferOffset = (jint) 0;
     jintArray _sizeArray = (jintArray) 0;
     jint _sizeBufferOffset = (jint) 0;
     jintArray _typeArray = (jintArray) 0;
     jint _typeBufferOffset = (jint) 0;
+    jbyteArray _nameArray = (jbyteArray)0;
+    jint _nameBufferOffset = (jint)0;
     jint _lengthRemaining;
     GLsizei *length = (GLsizei *) 0;
     jint _sizeRemaining;
     GLint *size = (GLint *) 0;
     jint _typeRemaining;
     GLenum *type = (GLenum *) 0;
+    jint _nameRemaining;
+    GLchar* name = (GLchar*)0;
+
 
     length = (GLsizei *)getPointer(_env, length_buf, (jarray*)&_lengthArray, &_lengthRemaining, &_lengthBufferOffset);
     size = (GLint *)getPointer(_env, size_buf, (jarray*)&_sizeArray, &_sizeRemaining, &_sizeBufferOffset);
     type = (GLenum *)getPointer(_env, type_buf, (jarray*)&_typeArray, &_typeRemaining, &_typeBufferOffset);
+    name = (GLchar*)getPointer(_env, name_buf, (jarray*)&_nameArray, &_nameRemaining, &_nameBufferOffset);
     if (length == NULL) {
         char * _lengthBase = (char *)_env->GetIntArrayElements(_lengthArray, (jboolean *) 0);
         length = (GLsizei *) (_lengthBase + _lengthBufferOffset);
@@ -2040,6 +2053,10 @@ android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuff
         char * _typeBase = (char *)_env->GetIntArrayElements(_typeArray, (jboolean *) 0);
         type = (GLenum *) (_typeBase + _typeBufferOffset);
     }
+    if (name == NULL) {
+        char* _nameBase = (char *)_env->GetByteArrayElements(_nameArray, (jboolean*)0);
+        name = (GLchar *) (_nameBase + _nameBufferOffset);
+    }
     glGetTransformFeedbackVarying(
         (GLuint)program,
         (GLuint)index,
@@ -2047,11 +2064,7 @@ android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuff
         (GLsizei *)length,
         (GLint *)size,
         (GLenum *)type,
-        // The cast below is incorrect. The driver will end up writing to the
-        // address specified by name, which will always crash the process since
-        // it is guaranteed to be in low memory. The additional static_cast
-        // suppresses the warning for now. http://b/19478262
-        (char *)static_cast<uintptr_t>(name)
+        (GLchar*)name
     );
     if (_typeArray) {
         releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _typeArray, (jint*)type, JNI_TRUE);
@@ -2062,6 +2075,9 @@ android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuff
     if (_lengthArray) {
         releaseArrayPointer<jintArray, jint*, IntArrayReleaser>(_env, _lengthArray, (jint*)length, JNI_TRUE);
     }
+    if (_nameArray) {
+        releaseArrayPointer<jbyteArray, jbyte*, ByteArrayReleaser>(_env, _nameArray, (jbyte*)name, JNI_TRUE);
+    }
 }
 
 /* void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name ) */
@@ -5233,6 +5249,7 @@ static const JNINativeMethod methods[] = {
 {"glTransformFeedbackVaryings", "(I[Ljava/lang/String;I)V", (void *) android_glTransformFeedbackVaryings },
 {"glGetTransformFeedbackVarying", "(III[II[II[II[BI)V", (void *) android_glGetTransformFeedbackVarying__III_3II_3II_3II_3BI },
 {"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;B)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2B },
+{"glGetTransformFeedbackVarying", "(IIILjava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;Ljava/nio/ByteBuffer;)V", (void *) android_glGetTransformFeedbackVarying__IIILjava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2Ljava_nio_ByteBuffer_2 },
 {"glGetTransformFeedbackVarying", "(II[II[II)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying1 },
 {"glGetTransformFeedbackVarying", "(IILjava/nio/IntBuffer;Ljava/nio/IntBuffer;)Ljava/lang/String;", (void *) android_glGetTransformFeedbackVarying2 },
 {"glVertexAttribIPointerBounds", "(IIIILjava/nio/Buffer;I)V", (void *) android_glVertexAttribIPointerBounds__IIIILjava_nio_Buffer_2I },
index 03a1e71..f870a89 100644 (file)
@@ -21,6 +21,7 @@
 #include "utils/misc.h"
 #include "cutils/debugger.h"
 #include <memtrack/memtrack.h>
+#include <memunreachable/memunreachable.h>
 
 #include <cutils/log.h>
 #include <fcntl.h>
@@ -36,6 +37,9 @@
 #include <ctype.h>
 #include <malloc.h>
 
+#include <iomanip>
+#include <string>
+
 namespace android
 {
 
@@ -258,7 +262,13 @@ static void read_mapinfo(FILE *fp, stats_t* stats, bool* foundSwapPss)
             }
             name = line + name_pos;
             nameLen = strlen(name);
-
+            // Trim the end of the line if it is " (deleted)".
+            const char* deleted_str = " (deleted)";
+            if (nameLen > (int)strlen(deleted_str) &&
+                strcmp(name+nameLen-strlen(deleted_str), deleted_str) == 0) {
+                nameLen -= strlen(deleted_str);
+                name[nameLen] = '\0';
+            }
             if ((strstr(name, "[heap]") == name)) {
                 whichHeap = HEAP_NATIVE;
             } else if (strncmp(name, "[anon:libc_malloc]", 18) == 0) {
@@ -1023,6 +1033,13 @@ static void android_os_Debug_dumpNativeBacktraceToFile(JNIEnv* env, jobject claz
     close(fd);
 }
 
+static jstring android_os_Debug_getUnreachableMemory(JNIEnv* env, jobject clazz,
+    jint limit, jboolean contents)
+{
+    std::string s = GetUnreachableMemoryString(contents, limit);
+    return env->NewStringUTF(s.c_str());
+}
+
 /*
  * JNI registration.
  */
@@ -1058,6 +1075,8 @@ static const JNINativeMethod gMethods[] = {
             (void*)android_os_Debug_getDeathObjectCount },
     { "dumpNativeBacktraceToFile", "(ILjava/lang/String;)V",
             (void*)android_os_Debug_dumpNativeBacktraceToFile },
+    { "getUnreachableMemory", "(IZ)Ljava/lang/String;",
+            (void*)android_os_Debug_getUnreachableMemory },
 };
 
 int register_android_os_Debug(JNIEnv *env)
index cf68449..b7701d6 100644 (file)
@@ -411,22 +411,27 @@ static jlong nativeReadFromParcel(JNIEnv* env, jclass clazz,
         return 0;
     }
 
+    android::view::Surface surfaceShim;
+
+    // Calling code in Surface.java has already read the name of the Surface
+    // from the Parcel
+    surfaceShim.readFromParcel(parcel, /*nameAlreadyRead*/true);
+
     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
-    sp<IBinder> binder(parcel->readStrongBinder());
 
     // update the Surface only if the underlying IGraphicBufferProducer
     // has changed.
-    if (self != NULL
-            && (IInterface::asBinder(self->getIGraphicBufferProducer()) == binder)) {
+    if (self != nullptr
+            && (IInterface::asBinder(self->getIGraphicBufferProducer()) ==
+                    IInterface::asBinder(surfaceShim.graphicBufferProducer))) {
         // same IGraphicBufferProducer, return ourselves
         return jlong(self.get());
     }
 
     sp<Surface> sur;
-    sp<IGraphicBufferProducer> gbp(interface_cast<IGraphicBufferProducer>(binder));
-    if (gbp != NULL) {
+    if (surfaceShim.graphicBufferProducer != nullptr) {
         // we have a new IGraphicBufferProducer, create a new Surface for it
-        sur = new Surface(gbp, true);
+        sur = new Surface(surfaceShim.graphicBufferProducer, true);
         // and keep a reference before passing to java
         sur->incStrong(&sRefBaseOwner);
     }
@@ -447,7 +452,13 @@ static void nativeWriteToParcel(JNIEnv* env, jclass clazz,
         return;
     }
     sp<Surface> self(reinterpret_cast<Surface *>(nativeObject));
-    parcel->writeStrongBinder( self != 0 ? IInterface::asBinder(self->getIGraphicBufferProducer()) : NULL);
+    android::view::Surface surfaceShim;
+    if (self != nullptr) {
+        surfaceShim.graphicBufferProducer = self->getIGraphicBufferProducer();
+    }
+    // Calling code in Surface.java has already written the name of the Surface
+    // to the Parcel
+    surfaceShim.writeToParcel(parcel, /*nameAlreadyWritten*/true);
 }
 
 static jint nativeGetWidth(JNIEnv* env, jclass clazz, jlong nativeObject) {
index 1dfe40a..c838d03 100644 (file)
@@ -110,6 +110,13 @@ static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) {
     ctrl->decStrong((void *)nativeCreate);
 }
 
+static void nativeDisconnect(JNIEnv* env, jclass clazz, jlong nativeObject) {
+    SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+    if (ctrl != NULL) {
+        ctrl->disconnect();
+    }
+}
+
 static jobject nativeScreenshotBitmap(JNIEnv* env, jclass clazz,
         jobject displayTokenObj, jobject sourceCropObj, jint width, jint height,
         jint minLayer, jint maxLayer, bool allLayers, bool useIdentityTransform,
@@ -595,6 +602,8 @@ static const JNINativeMethod sSurfaceControlMethods[] = {
             (void*)nativeRelease },
     {"nativeDestroy", "(J)V",
             (void*)nativeDestroy },
+    {"nativeDisconnect", "(J)V",
+            (void*)nativeDisconnect },
     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/graphics/Rect;IIIIZZI)Landroid/graphics/Bitmap;",
             (void*)nativeScreenshotBitmap },
     {"nativeScreenshot", "(Landroid/os/IBinder;Landroid/view/Surface;Landroid/graphics/Rect;IIIIZZ)V",
index 03d93a1..8f85d4a 100644 (file)
@@ -87,6 +87,7 @@
     <protected-broadcast android:name="android.os.action.DEVICE_IDLE_MODE_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_WHITELIST_CHANGED" />
     <protected-broadcast android:name="android.os.action.POWER_SAVE_TEMP_WHITELIST_CHANGED" />
+    <protected-broadcast android:name="android.os.action.POWER_SAVE_MODE_CHANGED_INTERNAL" />
 
     <protected-broadcast android:name="android.os.action.SCREEN_BRIGHTNESS_BOOST_CHANGED" />
 
     <protected-broadcast android:name="com.android.server.WifiManager.action.START_SCAN" />
     <protected-broadcast android:name="com.android.server.WifiManager.action.START_PNO" />
     <protected-broadcast android:name="com.android.server.WifiManager.action.DELAYED_DRIVER_STOP" />
+    <protected-broadcast android:name="com.android.server.WifiManager.action.DEVICE_IDLE" />
     <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED" />
     <protected-broadcast android:name="com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED" />
     <protected-broadcast android:name="android.net.wifi.WIFI_STATE_CHANGED" />
     <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_FAILED" />
     <protected-broadcast android:name="android.app.action.ACTION_PASSWORD_SUCCEEDED" />
     <protected-broadcast android:name="com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION" />
+
     <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_ADDED" />
+    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
+    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_REMOVED" />
 
     <protected-broadcast android:name="android.bluetooth.adapter.action.BLE_STATE_CHANGED" />
     <protected-broadcast android:name="android.content.jobscheduler.JOB_DELAY_EXPIRED" />
     <protected-broadcast android:name="android.intent.action.DYNAMIC_SENSOR_CHANGED" />
 
     <protected-broadcast android:name="android.intent.action.ACTION_RADIO_OFF" />
-    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNLOCKED" />
 
     <protected-broadcast android:name="android.accounts.LOGIN_ACCOUNTS_CHANGED" />
     <protected-broadcast android:name="com.android.sync.SYNC_CONN_STATUS_CHANGED" />
 
     <protected-broadcast android:name="android.intent.action.TWILIGHT_CHANGED" />
 
+    <protected-broadcast android:name="com.android.server.fingerprint.ACTION_LOCKOUT_RESET" />
+    <protected-broadcast android:name="android.net.wifi.PASSPOINT_ICON_RECEIVED" />
+    <protected-broadcast android:name="com.android.server.notification.CountdownConditionProvider" />
+
     <!-- ====================================================================== -->
     <!--                          RUNTIME PERMISSIONS                           -->
     <!-- ====================================================================== -->
     <permission android:name="android.permission.GET_PACKAGE_IMPORTANCE"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows use of PendingIntent.getIntent().
+         @hide -->
+    <permission android:name="android.permission.GET_INTENT_SENDER_INTENT"
+        android:protectionLevel="signature" />
+
     <!-- ================================== -->
     <!-- Permissions affecting the display of other applications  -->
     <!-- ================================== -->
diff --git a/core/res/res/drawable-nodpi/default_wallpaper.jpg b/core/res/res/drawable-nodpi/default_wallpaper.jpg
deleted file mode 100644 (file)
index d7475b4..0000000
Binary files a/core/res/res/drawable-nodpi/default_wallpaper.jpg and /dev/null differ
diff --git a/core/res/res/drawable-nodpi/default_wallpaper.png b/core/res/res/drawable-nodpi/default_wallpaper.png
new file mode 100644 (file)
index 0000000..e9c4d5c
Binary files /dev/null and b/core/res/res/drawable-nodpi/default_wallpaper.png differ
diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg
deleted file mode 100644 (file)
index 03a14c0..0000000
Binary files a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.jpg and /dev/null differ
diff --git a/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png
new file mode 100644 (file)
index 0000000..9f3efa5
Binary files /dev/null and b/core/res/res/drawable-sw600dp-nodpi/default_wallpaper.png differ
diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg
deleted file mode 100644 (file)
index 543d118..0000000
Binary files a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.jpg and /dev/null differ
diff --git a/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png
new file mode 100644 (file)
index 0000000..8199e70
Binary files /dev/null and b/core/res/res/drawable-sw720dp-nodpi/default_wallpaper.png differ
diff --git a/core/res/res/drawable/work_widget_mask_view_background.xml b/core/res/res/drawable/work_widget_mask_view_background.xml
deleted file mode 100644 (file)
index 17f0dbc..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2015 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.
--->
- <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle">
-   <padding android:left="5dp" android:right="5dp" android:top="5dp" android:bottom="5dp"/>
-   <stroke android:width="1dp" android:color="#CCCCCC" />
- </shape>
index 9a4b28c..3c59b4e 100644 (file)
@@ -39,7 +39,7 @@
         <com.android.internal.widget.ImageFloatingTextView android:id="@+id/big_text"
             android:layout_width="match_parent"
             android:layout_height="0dp"
-            android:layout_marginTop="1.5dp"
+            android:layout_marginTop="1dp"
             android:paddingBottom="@dimen/notification_content_margin_bottom"
             android:textAppearance="@style/TextAppearance.Material.Notification"
             android:singleLine="false"
index 38470cd..47b30ec 100644 (file)
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.ImageFloatingTextView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/text"
     android:layout_width="match_parent"
     android:layout_height="wrap_content"
     android:layout_gravity="top"
-    android:layout_marginTop="1.5dp"
+    android:layout_marginTop="1dp"
     android:ellipsize="marquee"
     android:fadingEdge="horizontal"
     android:gravity="top"
index 15b18dd..d1c65c0 100644 (file)
@@ -33,7 +33,7 @@
             android:id="@+id/suggestionContainer"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingTop="8dp"
+            android:paddingTop="4dp"
             android:paddingBottom="0dp"
             android:divider="@null" />
         <LinearLayout
index ce86ddc..3c47705 100644 (file)
@@ -15,20 +15,24 @@ Copyright (C) 2015 The Android Open Source Project
     limitations under the License.
 -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/work_widget_mask_frame"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="#F3374248" >
+    android:background="#F3374248"
+    android:clickable="true" >
 
     <ImageView android:id="@+id/work_widget_app_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center"/>
+        android:layout_gravity="center"
+        android:clickable="false" />
 
-    <ImageView
+    <ImageView android:id="@+id/work_widget_badge_icon"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:layout_gravity="bottom|right"
         android:layout_marginBottom="4dp"
         android:layout_marginRight="4dp"
-        android:src="@drawable/ic_corp_badge_off" />
+        android:src="@drawable/ic_corp_badge_off"
+        android:clickable="false" />
 </FrameLayout>
index 8c00151..7ed9a20 100644 (file)
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Previše <xliff:g id="CONTENT_TYPE">%s</xliff:g> izbrisanih stavki."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Memorija tableta je puna! Izbrišite neke datoteke da biste oslobodili prostor."</string>
     <string name="low_memory" product="watch" msgid="4415914910770005166">"Memorija sata je puna. Izbrišite neke datoteke da biste oslobodili prostor."</string>
-    <string name="low_memory" product="tv" msgid="516619861191025923">"Skladišni prostor na TV-u je popunjen. Izbrišite neke datoteke da biste oslobodili prostor."</string>
+    <string name="low_memory" product="tv" msgid="516619861191025923">"Memorijski prostor na TV-u je popunjen. Izbrišite neke datoteke da biste oslobodili prostor."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Skladište telefona je puno! Izbrišite neke datoteke kako biste oslobodili prostor."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Mreža se možda nadgleda"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Od strane nepoznate treće strane"</string>
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Dozvoljava aplikaciji da učini sopstvene komponente trajnim u memoriji. Ovo može da ograniči memoriju dostupnu drugim aplikacijama i uspori tablet."</string>
     <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Dozvoljava aplikaciji da neke svoje delove trajno zadrži u memoriji. To može da ograniči memoriju dostupnu drugim aplikacijama i uspori TV."</string>
     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Dozvoljava aplikaciji da učini sopstvene komponente trajnim u memoriji. Ovo može da ograniči memoriju dostupnu drugim aplikacijama i uspori telefon."</string>
-    <string name="permlab_getPackageSize" msgid="7472921768357981986">"merenje prostora za skladištenje u aplikaciji"</string>
+    <string name="permlab_getPackageSize" msgid="7472921768357981986">"merenje memorijskog prostora u aplikaciji"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Dozvoljava aplikaciji da preuzme veličine kôda, podataka i keša."</string>
     <string name="permlab_writeSettings" msgid="2226195290955224730">"izmena podešavanja sistema"</string>
     <string name="permdesc_writeSettings" msgid="7775723441558907181">"Dozvoljava aplikaciji da menja podatke o podešavanju sistema. Zlonamerne aplikacije mogu da oštete konfiguraciju sistema."</string>
     <string name="deleteText" msgid="6979668428458199034">"Izbriši"</string>
     <string name="inputMethod" msgid="1653630062304567879">"Metod unosa"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Radnje u vezi sa tekstom"</string>
-    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Prostor za skladištenje je na izmaku"</string>
+    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Memorijski prostor je na izmaku"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Neke sistemske funkcije možda ne funkcionišu"</string>
-    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno skladišnog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
+    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Nema dovoljno memorijskog prostora za sistem. Uverite se da imate 250 MB slobodnog prostora i ponovo pokrenite."</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je pokrenuta"</string>
     <string name="app_running_notification_text" msgid="4653586947747330058">"Dodirnite za više informacija ili zaustavljanje aplikacije."</string>
     <string name="ok" msgid="5970060430562524910">"Potvrdi"</string>
index 67776e7..2ed5463 100644 (file)
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Eskatu pasahitza aingura kendu aurretik"</string>
     <string name="dock_forced_resizable" msgid="5914261505436217520">"Baliteke aplikazioak ez funtzionatzea pantaila zatituan."</string>
-    <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikazioak ez du onartzen pantaila banatua"</string>
+    <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Aplikazioak ez du onartzen pantaila zatitua"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Administratzaileak instalatu du"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Administratzaileak eguneratu du"</string>
     <string name="package_deleted_device_owner" msgid="7650577387493101353">"Administratzaileak ezabatu du"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Garrantzitsua da eragiten dien pertsonengatik."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzea baimendu nahi diozu?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> aplikazioari <xliff:g id="ACCOUNT">%2$s</xliff:g> kontua duen erabiltzailea sortzea baimendu nahi diozu? (Badago kontu hori duen erabiltzaile bat)"</string>
-    <string name="language_selection_title" msgid="2680677278159281088">"Gehitu hizkuntza bat"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Gehitu hizkuntza"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Lurralde-hobespena"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Adierazi hizkuntza"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Iradokitakoak"</string>
similarity index 54%
rename from core/java/android/view/Surface.aidl
rename to core/res/res/values-h426dp-port/integers.xml
index 90bf37a..94abbec 100644 (file)
@@ -1,20 +1,22 @@
-/* //device/java/android/android/view/Surface.aidl
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
 **
-** Copyright 2007, The Android Open Source Project
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
 **
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
+**     http://www.apache.org/licenses/LICENSE-2.0
 **
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
 ** limitations under the License.
 */
-
-package android.view;
-
-parcelable Surface;
+-->
+<resources>
+    <integer name="date_picker_mode">2</integer>
+    <integer name="time_picker_mode">2</integer>
+</resources>
index 018e054..a6ee770 100644 (file)
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Бошотуудан мурун PIN суралсын"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Бошотуудан мурун кулпуну ачкан үлгү суралсын"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Бошотуудан мурун сырсөз суралсын"</string>
-    <string name="dock_forced_resizable" msgid="5914261505436217520">"Колдонмо бөлүнгөн экранда иштебей калышы мүмкүн."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Колдонмодо экран бөлүнбөшү мүмкүн."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Колдонмодо экран бөлүнбөйт."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Администраторуңуз тарабынан орнотулган"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Администраторуңуз жаңырткан"</string>
     <string name="importance_from_person" msgid="9160133597262938296">"Булар сиз үчүн маанилүү адамдар."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби ?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"<xliff:g id="APP">%1$s</xliff:g> колдонмосу <xliff:g id="ACCOUNT">%2$s</xliff:g> каттоо эсеби менен жаңы колдонуучу түзө берсинби (мындай каттоо эсеби бар колдонуучу мурунтан эле бар) ?"</string>
-    <string name="language_selection_title" msgid="2680677278159281088">"Тилди кошуңуз"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Тил кошуңуз"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Чөлкөмдүк жөндөөлөр"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Тилди киргизиңиз"</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Сунушталган"</string>
index 8604e62..ecf45b7 100644 (file)
     <string name="importance_from_person" msgid="9160133597262938296">"Tai svarbu dėl susijusių žmonių."</string>
     <string name="user_creation_account_exists" msgid="1942606193570143289">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją?"</string>
     <string name="user_creation_adding" msgid="4482658054622099197">"Leisti „<xliff:g id="APP">%1$s</xliff:g>“ kurti naują <xliff:g id="ACCOUNT">%2$s</xliff:g> naudotoją (šią paskyrą naudojantis naudotojas jau yra)?"</string>
-    <string name="language_selection_title" msgid="2680677278159281088">"Kalbos pridėjimas"</string>
+    <string name="language_selection_title" msgid="2680677278159281088">"Pridėkite kalbą"</string>
     <string name="country_selection_title" msgid="2954859441620215513">"Regiono nuostata"</string>
     <string name="search_language_hint" msgid="7042102592055108574">"Įveskite kalbos pav."</string>
     <string name="language_picker_section_suggested" msgid="8414489646861640885">"Siūloma"</string>
index 06401bf..cd31b2b 100644 (file)
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"Minta PIN sebelum menyahsemat"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"Minta corak buka kunci sebelum menyahsemat"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"Minta kata laluan sebelum menyahsemat"</string>
-    <string name="dock_forced_resizable" msgid="5914261505436217520">"Apl mungkin tidak berfungsi dengan skrin terpisah."</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"Apl mungkin tidak berfungsi dengan skrin pisah."</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"Apl tidak menyokong skrin pisah."</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"Dipasang oleh pentadbir anda"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"Dikemas kini oleh pentadbir anda"</string>
index d1ac852..1e3a886 100644 (file)
     <string name="contentServiceTooManyDeletesNotificationDesc" msgid="8100981435080696431">"Превише <xliff:g id="CONTENT_TYPE">%s</xliff:g> избрисаних ставки."</string>
     <string name="low_memory" product="tablet" msgid="6494019234102154896">"Меморија таблета је пуна! Избришите неке датотеке да бисте ослободили простор."</string>
     <string name="low_memory" product="watch" msgid="4415914910770005166">"Меморија сата је пуна. Избришите неке датотеке да бисте ослободили простор."</string>
-    <string name="low_memory" product="tv" msgid="516619861191025923">"СкладиÑ\88ни простор на ТВ-у је попуњен. Избришите неке датотеке да бисте ослободили простор."</string>
+    <string name="low_memory" product="tv" msgid="516619861191025923">"Ð\9cемоÑ\80иÑ\98Ñ\81ки простор на ТВ-у је попуњен. Избришите неке датотеке да бисте ослободили простор."</string>
     <string name="low_memory" product="default" msgid="3475999286680000541">"Складиште телефона је пуно! Избришите неке датотеке како бисте ослободили простор."</string>
     <string name="ssl_ca_cert_warning" msgid="5848402127455021714">"Мрежа се можда надгледа"</string>
     <string name="ssl_ca_cert_noti_by_unknown" msgid="4475437862189850602">"Од стране непознате треће стране"</string>
     <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Дозвољава апликацији да учини сопствене компоненте трајним у меморији. Ово може да ограничи меморију доступну другим апликацијама и успори таблет."</string>
     <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Дозвољава апликацији да неке своје делове трајно задржи у меморији. То може да ограничи меморију доступну другим апликацијама и успори ТВ."</string>
     <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Дозвољава апликацији да учини сопствене компоненте трајним у меморији. Ово може да ограничи меморију доступну другим апликацијама и успори телефон."</string>
-    <string name="permlab_getPackageSize" msgid="7472921768357981986">"меÑ\80еÑ\9aе Ð¿Ñ\80оÑ\81Ñ\82оÑ\80а Ð·Ð° Ñ\81кладиÑ\88Ñ\82еÑ\9aе у апликацији"</string>
+    <string name="permlab_getPackageSize" msgid="7472921768357981986">"меÑ\80еÑ\9aе Ð¼ÐµÐ¼Ð¾Ñ\80иÑ\98Ñ\81ког Ð¿Ñ\80оÑ\81Ñ\82оÑ\80а у апликацији"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Дозвољава апликацији да преузме величине кôда, података и кеша."</string>
     <string name="permlab_writeSettings" msgid="2226195290955224730">"измена подешавања система"</string>
     <string name="permdesc_writeSettings" msgid="7775723441558907181">"Дозвољава апликацији да мења податке о подешавању система. Злонамерне апликације могу да оштете конфигурацију система."</string>
     <string name="deleteText" msgid="6979668428458199034">"Избриши"</string>
     <string name="inputMethod" msgid="1653630062304567879">"Метод уноса"</string>
     <string name="editTextMenuTitle" msgid="4909135564941815494">"Радње у вези са текстом"</string>
-    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ð\9fÑ\80оÑ\81Ñ\82оÑ\80 Ð·Ð° Ñ\81кладиÑ\88Ñ\82еÑ\9aе је на измаку"</string>
+    <string name="low_internal_storage_view_title" msgid="5576272496365684834">"Ð\9cемоÑ\80иÑ\98Ñ\81ки Ð¿Ñ\80оÑ\81Ñ\82оÑ\80 је на измаку"</string>
     <string name="low_internal_storage_view_text" msgid="6640505817617414371">"Неке системске функције можда не функционишу"</string>
-    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема довољно складишног простора за систем. Уверите се да имате 250 MB слободног простора и поново покрените."</string>
+    <string name="low_internal_storage_view_text_no_boot" msgid="6935190099204693424">"Нема довољно меморијског простора за систем. Уверите се да имате 250 MB слободног простора и поново покрените."</string>
     <string name="app_running_notification_title" msgid="8718335121060787914">"Апликација <xliff:g id="APP_NAME">%1$s</xliff:g> је покренута"</string>
     <string name="app_running_notification_text" msgid="4653586947747330058">"Додирните за више информација или заустављање апликације."</string>
     <string name="ok" msgid="5970060430562524910">"Потврди"</string>
diff --git a/core/res/res/values-w426dp-land/integers.xml b/core/res/res/values-w426dp-land/integers.xml
new file mode 100644 (file)
index 0000000..94abbec
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2016, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+**     http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+    <integer name="date_picker_mode">2</integer>
+    <integer name="time_picker_mode">2</integer>
+</resources>
index 85616b1..24a5b79 100644 (file)
     <string name="lock_to_app_unlock_pin" msgid="2552556656504331634">"取消时要求输入PIN码"</string>
     <string name="lock_to_app_unlock_pattern" msgid="4182192144797225137">"取消时要求绘制解锁图案"</string>
     <string name="lock_to_app_unlock_password" msgid="6380979775916974414">"取消时要求输入密码"</string>
-    <string name="dock_forced_resizable" msgid="5914261505436217520">"应用可能无法在分屏模式下运行。"</string>
+    <string name="dock_forced_resizable" msgid="5914261505436217520">"应用可能无法在分屏模式下正常运行。"</string>
     <string name="dock_non_resizeble_failed_to_dock_text" msgid="3871617304250207291">"应用不支持分屏。"</string>
     <string name="package_installed_device_owner" msgid="8420696545959087545">"已由管理员安装"</string>
     <string name="package_updated_device_owner" msgid="8856631322440187071">"由您单位的管理员更新"</string>
index 7c02128..90a573b 100644 (file)
@@ -8189,11 +8189,8 @@ i
         <!-- @hide From Theme.colorPrimary, used for the TaskDescription primary 
                    color. -->
         <attr name="colorPrimary" />
-        <!-- @hide From Theme.windowBackground, used for calculating the 
-                   TaskDescription background color. -->
-        <attr name="windowBackground" />
-        <!-- @hide From Theme.windowBackgroundFallback, used for calculating the 
-                   TaskDescription background color. -->
-        <attr name="windowBackgroundFallback" />
+        <!-- @hide From Theme.colorBackground, used for the TaskDescription background 
+                   color. -->
+        <attr name="colorBackground" />
     </declare-styleable>
 </resources>
index b65f19b..7857107 100644 (file)
     <!-- Boolean indicating whether or not wifi firmware debugging is enabled -->
     <bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">true</bool>
 
+    <!-- Integer size limit, in KB, for a single WifiLogger ringbuffer -->
+    <integer translatable="false" name="config_wifi_logger_ring_buffer_size_limit_kb">32</integer>
+
     <!-- Boolean indicating whether or not wifi should turn off when emergency call is made -->
     <bool translatable="false" name="config_wifi_turn_off_during_emergency_call">false</bool>
 
          flag). -->
     <bool name="config_forceWindowDrawsStatusBarBackground">true</bool>
 
+    <!-- If set, this will force the navigation bar to always be drawn with an opaque
+         background. -->
+    <bool name="config_forceNavBarAlwaysOpaque">false</bool>
+
     <!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
     <string translatable="false" name="config_defaultPictureInPictureBounds">"0 0 100 100"</string>
 
          handle wallpaper cropping.
     -->
     <string name="config_wallpaperCropperPackage" translatable="false">com.android.wallpapercropper</string>
+
+    <!-- True if the device supports at least one form of multi-window.
+         E.g. freeform, split-screen, picture-in-picture. -->
+    <bool name="config_supportsMultiWindow">true</bool>
 </resources>
index 8e27226..8f8d59e 100644 (file)
@@ -23,4 +23,7 @@
     <integer name="button_pressed_animation_delay">100</integer>
     <integer name="disabled_alpha_animation_duration">100</integer>
     <integer name="dock_enter_exit_duration">250</integer>
+
+    <integer name="date_picker_mode">1</integer>
+    <integer name="time_picker_mode">1</integer>
 </resources>
index 7b11302..d8efd63 100644 (file)
     <!-- Message of notification shown when ADB is actively connected to the phone. -->
     <string name="adb_active_notification_message">Touch to disable USB debugging.</string>
 
+    <!-- Title of notification shown to indicate that bug report is being collected. -->
+    <string name="taking_remote_bugreport_notification_title">Taking bug report\u2026</string>
     <!-- Title of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
     <string name="share_remote_bugreport_notification_title">Share bug report?</string>
     <!-- Title of notification shown to indicate that bug report is still being collected after sharing was accepted. -->
     <string name="sharing_remote_bugreport_notification_title">Sharing bug report\u2026</string>
-    <!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
-    <string name="share_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared and your device may temporarily slow down.</string>
-    <!-- Message of notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
-    <string name="share_finished_remote_bugreport_notification_message">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared.</string>
-    <!-- Message of notification shown to shown to indicate that bug report is still being collected after sharing was accepted. -->
-    <string name="sharing_remote_bugreport_notification_message">This may temporarily slow down your device</string>
+    <!-- Message of a notification shown to ask for user consent for sharing a bugreport that was requested remotely by the IT administrator. -->
+    <string name="share_remote_bugreport_notification_message_finished">Your IT admin requested a bug report to help troubleshoot this device. Apps and data may be shared.</string>
     <!-- Acceptance label of notification shown to ask for user consent for sharing the remote bugreport. -->
-    <string name="share_remote_bugreport_notification_accept">ACCEPT</string>
+    <string name="share_remote_bugreport_action">SHARE</string>
     <!-- Decline label of notification shown to ask for user consent for sharing the remote bugreport. -->
-    <string name="share_remote_bugreport_notification_decline">DECLINE</string>
+    <string name="decline_remote_bugreport_action">DECLINE</string>
 
     <!-- Used to replace %s in urls retreived from the signin server with locales.  For Some        -->
     <!-- devices we don't support all the locales we ship to and need to replace the '%s' with a    -->
index db418f7..a9c8a06 100644 (file)
@@ -652,7 +652,7 @@ please see styles_device_defaults.xml.
     </style>
 
     <style name="Widget.Material.TimePicker">
-        <item name="timePickerMode">clock</item>
+        <item name="timePickerMode">@integer/time_picker_mode</item>
         <item name="legacyLayout">@layout/time_picker_legacy_material</item>
         <!-- Attributes for new-style TimePicker. -->
         <item name="internalLayout">@layout/time_picker_material</item>
@@ -666,7 +666,7 @@ please see styles_device_defaults.xml.
     </style>
 
     <style name="Widget.Material.DatePicker">
-        <item name="datePickerMode">calendar</item>
+        <item name="datePickerMode">@integer/date_picker_mode</item>
         <item name="legacyLayout">@layout/date_picker_legacy_holo</item>
         <item name="calendarViewShown">true</item>
         <!-- Attributes for new-style DatePicker. -->
index 44a7a8d..15521e4 100644 (file)
   <java-symbol type="bool" name="config_wifi_enable_5GHz_preference" />
   <java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" />
   <java-symbol type="bool" name="config_wifi_enable_wifi_firmware_debugging" />
+  <java-symbol type="integer" name="config_wifi_logger_ring_buffer_size_limit_kb" />
   <java-symbol type="bool" name="config_wifi_turn_off_during_emergency_call" />
   <java-symbol type="bool" name="config_supportMicNearUltrasound" />
   <java-symbol type="bool" name="config_supportSpeakerNearUltrasound" />
   <java-symbol type="bool" name="config_supportAudioSourceUnprocessed" />
   <java-symbol type="bool" name="config_freeformWindowManagement" />
+  <java-symbol type="bool" name="config_supportsMultiWindow" />
   <java-symbol type="bool" name="config_guestUserEphemeral" />
   <java-symbol type="string" name="config_defaultPictureInPictureBounds" />
   <java-symbol type="string" name="config_centeredPictureInPictureBounds" />
   <java-symbol type="string" name="accessibility_binding_label" />
   <java-symbol type="string" name="adb_active_notification_message" />
   <java-symbol type="string" name="adb_active_notification_title" />
+  <java-symbol type="string" name="taking_remote_bugreport_notification_title" />
   <java-symbol type="string" name="share_remote_bugreport_notification_title" />
-  <java-symbol type="string" name="share_remote_bugreport_notification_message" />
-  <java-symbol type="string" name="share_finished_remote_bugreport_notification_message" />
   <java-symbol type="string" name="sharing_remote_bugreport_notification_title" />
-  <java-symbol type="string" name="sharing_remote_bugreport_notification_message" />
-  <java-symbol type="string" name="share_remote_bugreport_notification_accept" />
-  <java-symbol type="string" name="share_remote_bugreport_notification_decline" />
+  <java-symbol type="string" name="share_remote_bugreport_notification_message_finished" />
+  <java-symbol type="string" name="share_remote_bugreport_action" />
+  <java-symbol type="string" name="decline_remote_bugreport_action" />
   <java-symbol type="string" name="aerr_application" />
   <java-symbol type="string" name="aerr_process" />
   <java-symbol type="string" name="aerr_application_repeated" />
 
   <java-symbol type="string" name="config_packagedKeyboardName" />
   <java-symbol type="bool" name="config_forceWindowDrawsStatusBarBackground" />
+  <java-symbol type="bool" name="config_forceNavBarAlwaysOpaque" />
   <java-symbol type="color" name="system_bar_background_semi_transparent" />
 
   <!-- EditText suggestion popup. -->
   <java-symbol type="string" name="importance_from_person" />
 
   <java-symbol type="layout" name="work_widget_mask_view" />
+  <java-symbol type="id" name="work_widget_mask_frame" />
   <java-symbol type="id" name="work_widget_app_icon" />
-  <java-symbol type="drawable" name="work_widget_mask_view_background" />
+  <java-symbol type="id" name="work_widget_badge_icon" />
 
   <java-symbol type="id" name="aerr_report" />
   <java-symbol type="id" name="aerr_reset" />
index dd8baa7..11bb106 100644 (file)
@@ -544,9 +544,7 @@ easier.
         <item name="windowNoTitle">true</item>
         <item name="windowBackground">@color/transparent</item>
         <item name="backgroundDimEnabled">true</item>
-        <item name="windowTranslucentStatus">false</item>
-        <item name="windowTranslucentNavigation">false</item>
-        <item name="windowDrawsSystemBarBackgrounds">false</item>
+        <item name="statusBarColor">@color/transparent</item>
         <item name="windowContentOverlay">@null</item>
         <item name="colorControlActivated">?attr/colorControlHighlight</item>
         <item name="listPreferredItemPaddingStart">?attr/dialogPreferredPadding</item>
index 8bf635e..478d66c 100644 (file)
@@ -24,7 +24,6 @@
         <item name="windowBackground">@color/black</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
-        <item name="windowSwipeToDismiss">true</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
     </style>
@@ -42,7 +41,6 @@
         <item name="windowBackground">@color/white</item>
         <item name="windowContentOverlay">@null</item>
         <item name="windowIsFloating">false</item>
-        <item name="windowSwipeToDismiss">true</item>
         <!-- Required to force windowInsets dispatch through application UI. -->
         <item name="windowOverscan">true</item>
     </style>
index 998c72a..c92863d 100644 (file)
@@ -328,7 +328,12 @@ public class ValueAnimatorTests extends ActivityInstrumentationTestCase2<BasicAn
         // Only a1's pause listener should be called.
         assertTrue(l1.pauseCalled);
         assertFalse(l1.resumeCalled);
-        a1.resume();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                a1.resume();
+            }
+        });
 
         Thread.sleep(a1.getTotalDuration());
 
diff --git a/core/tests/coretests/src/android/content/pm/ContainerEncryptionParamsTest.java b/core/tests/coretests/src/android/content/pm/ContainerEncryptionParamsTest.java
deleted file mode 100644 (file)
index 7deaa9a..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-
-import java.util.Arrays;
-
-import javax.crypto.SecretKey;
-import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
-
-public class ContainerEncryptionParamsTest extends AndroidTestCase {
-    private static final String ENC_ALGORITHM = "AES/CBC/PKCS7Padding";
-
-    private static final byte[] IV_BYTES = "FOOBAR".getBytes();
-
-    private static final IvParameterSpec ENC_PARAMS = new IvParameterSpec(IV_BYTES);
-
-    private static final byte[] ENC_KEY_BYTES = "abcd1234wxyz7890".getBytes();
-
-    private static final SecretKey ENC_KEY = new SecretKeySpec(ENC_KEY_BYTES, "RAW");
-
-    private static final String MAC_ALGORITHM = "HMAC-SHA1";
-
-    private static final byte[] MAC_KEY_BYTES = "4wxyzabcd1237890".getBytes();
-
-    private static final SecretKey MAC_KEY = new SecretKeySpec(MAC_KEY_BYTES, "RAW");
-
-    private static final byte[] MAC_TAG = "faketag".getBytes();
-
-    private static final int AUTHENTICATED_START = 5;
-
-    private static final int ENCRYPTED_START = 11;
-
-    private static final int DATA_END = 19;
-
-    public void testParcel() throws Exception {
-        ContainerEncryptionParams expected = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        Parcel parcel = Parcel.obtain();
-        expected.writeToParcel(parcel, 0);
-        parcel.setDataPosition(0);
-
-        ContainerEncryptionParams actual = ContainerEncryptionParams.CREATOR
-                .createFromParcel(parcel);
-
-        assertEquals(ENC_ALGORITHM, actual.getEncryptionAlgorithm());
-
-        if (!(actual.getEncryptionSpec() instanceof IvParameterSpec)) {
-            fail("encryption parameters should be IvParameterSpec");
-        } else {
-            IvParameterSpec actualParams = (IvParameterSpec) actual.getEncryptionSpec();
-            assertTrue(Arrays.equals(IV_BYTES, actualParams.getIV()));
-        }
-
-        assertEquals(ENC_KEY, actual.getEncryptionKey());
-
-        assertEquals(MAC_ALGORITHM, actual.getMacAlgorithm());
-
-        assertNull(actual.getMacSpec());
-
-        assertEquals(MAC_KEY, actual.getMacKey());
-
-        assertTrue(Arrays.equals(MAC_TAG, actual.getMacTag()));
-
-        assertEquals(AUTHENTICATED_START, actual.getAuthenticatedDataStart());
-
-        assertEquals(ENCRYPTED_START, actual.getEncryptedDataStart());
-
-        assertEquals(DATA_END, actual.getDataEnd());
-    }
-
-    public void testEquals_Success() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertEquals(params1, params2);
-    }
-
-    public void testEquals_EncAlgo_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(new String(
-                "AES-256/CBC/PKCS7Padding"), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_EncParams_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec("BLAHBLAH".getBytes()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_EncKey_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec("BLAHBLAH".getBytes(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_MacAlgo_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), "BLAHBLAH", null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_MacKey_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec("FAKE_MAC_KEY".getBytes(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_MacTag_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), "broken".getBytes(),
-                AUTHENTICATED_START, ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_AuthenticatedStart_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START - 1,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_EncryptedStart_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START - 1, DATA_END);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_DataEnd_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END + 1);
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testHashCode_Success() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertEquals(params1.hashCode(), params2.hashCode());
-    }
-
-    public void testHashCode_EncAlgo_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(new String(
-                "AES-256/CBC/PKCS7Padding"), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_EncParams_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec("BLAHBLAH".getBytes()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_EncKey_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec("BLAHBLAH".getBytes(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_MacAlgo_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), "BLAHBLAH", null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_MacKey_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec("FAKE_MAC_KEY".getBytes(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_MacTag_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), "broken".getBytes(),
-                AUTHENTICATED_START, ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_AuthenticatedStart_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START - 1,
-                ENCRYPTED_START, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_EncryptedStart_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START - 1, DATA_END);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_DataEnd_Failure() throws Exception {
-        ContainerEncryptionParams params1 = new ContainerEncryptionParams(ENC_ALGORITHM,
-                ENC_PARAMS, ENC_KEY, MAC_ALGORITHM, null, MAC_KEY, MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END);
-
-        ContainerEncryptionParams params2 = new ContainerEncryptionParams(
-                new String(ENC_ALGORITHM), new IvParameterSpec(IV_BYTES.clone()),
-                new SecretKeySpec(ENC_KEY_BYTES.clone(), "RAW"), new String(MAC_ALGORITHM), null,
-                new SecretKeySpec(MAC_KEY_BYTES.clone(), "RAW"), MAC_TAG, AUTHENTICATED_START,
-                ENCRYPTED_START, DATA_END + 1);
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-}
index e9fd5fb..5d46489 100644 (file)
@@ -38,7 +38,7 @@ public class ConfigurationBoundResourceCacheTest
     @Override
     protected void setUp() throws Exception {
         super.setUp();
-        mCache = new ConfigurationBoundResourceCache<Float>(getActivity().getResources());
+        mCache = new ConfigurationBoundResourceCache<>();
     }
 
     public void testGetEmpty() {
diff --git a/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java b/core/tests/coretests/src/android/text/method/ForwardDeleteTest.java
new file mode 100644 (file)
index 0000000..da17045
--- /dev/null
@@ -0,0 +1,472 @@
+/*
+ * Copyright (C) 2016 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.text.method;
+
+import android.app.Activity;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.test.suitebuilder.annotation.Suppress;
+import android.text.InputType;
+import android.text.method.BaseKeyListener;
+import android.text.method.KeyListenerTestCase;
+import android.view.KeyEvent;
+import android.widget.EditText;
+import android.widget.TextView.BufferType;
+
+/**
+ * Test forward delete key handling of  {@link android.text.method.BaseKeyListener}.
+ *
+ * TODO: Move some of test cases to the CTS.
+ */
+public class ForwardDeleteTest extends KeyListenerTestCase {
+    private static final BaseKeyListener mKeyListener = new BaseKeyListener() {
+        public int getInputType() {
+            return InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_NORMAL;
+        }
+    };
+
+    // Sync the state to the TextView and call onKeyDown with KEYCODE_FORWARD_DEL key event.
+    // Then update the state to the result of TextView.
+    private void forwardDelete(final EditorState state, int modifiers) {
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mTextView.setText(state.mText, BufferType.EDITABLE);
+                mTextView.setKeyListener(mKeyListener);
+                mTextView.setSelection(state.mSelectionStart, state.mSelectionEnd);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+        assertTrue(mTextView.hasWindowFocus());
+
+        final KeyEvent keyEvent = getKey(KeyEvent.KEYCODE_FORWARD_DEL, modifiers);
+        mActivity.runOnUiThread(new Runnable() {
+            public void run() {
+                mTextView.onKeyDown(keyEvent.getKeyCode(), keyEvent);
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+
+        state.mText = mTextView.getText();
+        state.mSelectionStart = mTextView.getSelectionStart();
+        state.mSelectionEnd = mTextView.getSelectionEnd();
+    }
+
+    @SmallTest
+    public void testSurrogatePairs() {
+        EditorState state = new EditorState();
+
+        // U+1F441 is EYE
+        state.setByString("| U+1F441");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // U+1F5E8 is LEFT SPEECH BUBBLE
+        state.setByString("| U+1F441 U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // TODO: introduce edge cases.
+    }
+
+    @SmallTest
+    public void testReplacementSpan() {
+        EditorState state = new EditorState();
+
+        state.setByString("| 'abc' ( 'de' ) 'fg'");
+        forwardDelete(state, 0);
+        state.assertEquals("| 'bc' ( 'de' ) 'fg'");
+        forwardDelete(state, 0);
+        state.assertEquals("| 'c' ( 'de' ) 'fg'");
+        forwardDelete(state, 0);
+        state.assertEquals("| ( 'de' ) 'fg'");
+        forwardDelete(state, 0);
+        state.assertEquals("| 'fg'");
+        forwardDelete(state, 0);
+        state.assertEquals("| 'g'");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("'abc' [ ( 'de' ) ] 'fg'");
+        forwardDelete(state, 0);
+        state.assertEquals("'abc' | 'fg'");
+        forwardDelete(state, 0);
+        state.assertEquals("'abc' | 'g'");
+        forwardDelete(state, 0);
+        state.assertEquals("'abc' |");
+        forwardDelete(state, 0);
+        state.assertEquals("'abc' |");
+
+        state.setByString("'ab' [ 'c' ( 'de' ) 'f' ] 'g'");
+        forwardDelete(state, 0);
+        state.assertEquals("'ab' | 'g'");
+        forwardDelete(state, 0);
+        state.assertEquals("'ab' |");
+        forwardDelete(state, 0);
+        state.assertEquals("'ab' |");
+
+        // TODO: introduce edge cases.
+    }
+
+    @SmallTest
+    public void testCombiningEnclosingKeycaps() {
+        EditorState state = new EditorState();
+
+        // U+20E3 is COMBINING ENCLOSING KEYCAP.
+        state.setByString("| '1' U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Edge cases
+        // multiple COMBINING ENCLOSING KEYCAP
+        state.setByString("| '1' U+20E3 U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated multiple COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+20E3 U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
+    public void testVariationSelector() {
+        EditorState state = new EditorState();
+
+        // U+FE0F is VARIATION SELECTOR-16.
+        state.setByString("| '#' U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // U+E0100 is VARIATION SELECTOR-17.
+        state.setByString("| U+845B U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Edge cases
+        // Isolated variation selectors
+        state.setByString("| U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated multiple variation selectors
+        state.setByString("| U+FE0F U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+FE0F U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+E0100 U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+E0100 U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Multiple variation selectors
+        state.setByString("| '#' U+FE0F U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| '#' U+FE0F U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+845B U+E0100 U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+845B U+E0100 U+E0100");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
+    public void testEmojiZeroWidthJoinerSequence() {
+        EditorState state = new EditorState();
+
+        // U+200D is ZERO WIDTH JOINER.
+        state.setByString("| U+1F441 U+200D U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+1F468 U+200D U+2764 U+FE0F U+200D U+1F48B U+200D U+1F468");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Edge cases
+        // End with ZERO WIDTH JOINER
+        state.setByString("| U+1F441 U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Start with ZERO WIDTH JOINER
+        state.setByString("| U+200D U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Multiple ZERO WIDTH JOINER
+        state.setByString("| U+1F441 U+200D U+200D U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated ZERO WIDTH JOINER
+        state.setByString("| U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated multiple ZERO WIDTH JOINER
+        state.setByString("| U+200D U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
+    public void testFlags() {
+        EditorState state = new EditorState();
+
+        // U+1F1FA is REGIONAL INDICATOR SYMBOL LETTER U.
+        // U+1F1F8 is REGIONAL INDICATOR SYMBOL LETTER S.
+        state.setByString("| U+1F1FA U+1F1F8");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        state.setByString("| U+1F1FA U+1F1F8 U+1F1FA U+1F1F8");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA U+1F1F8");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Edge cases
+        // Isolated regional indicator symbol
+        state.setByString("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Odd numbered regional indicator symbols
+        state.setByString("| U+1F1FA U+1F1F8 U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
+    public void testEmojiModifier() {
+        EditorState state = new EditorState();
+
+        // U+1F3FB is EMOJI MODIFIER FITZPATRICK TYPE-1-2.
+        state.setByString("| U+1F466 U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Edge cases
+        // Isolated emoji modifier
+        state.setByString("| U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Isolated multiple emoji modifier
+        state.setByString("| U+1F3FB U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Multiple emoji modifiers
+        state.setByString("| U+1F466 U+1F3FB U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+
+    @SmallTest
+    public void testMixedEdgeCases() {
+        EditorState state = new EditorState();
+
+        // COMBINING ENCLOSING KEYCAP + variation selector
+        state.setByString("| '1' U+20E3 U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Variation selector + COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+2665 U+FE0F U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // COMBINING ENCLOSING KEYCAP + ending with ZERO WIDTH JOINER
+        state.setByString("| '1' U+20E3 U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // COMBINING ENCLOSING KEYCAP + ZERO WIDTH JOINER
+        state.setByString("| '1' U+20E3 U+200D U+1F5E8");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F5E8 ");
+
+        // Start with ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+200D U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // ZERO WIDTH JOINER + COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+1F441 U+200D U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // COMBINING ENCLOSING KEYCAP + regional indicator symbol
+        state.setByString("| '1' U+20E3 U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Regional indicator symbol + COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+1F1FA U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // COMBINING ENCLOSING KEYCAP + emoji modifier
+        state.setByString("| '1' U+20E3 U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+
+        // Emoji modifier + COMBINING ENCLOSING KEYCAP
+        state.setByString("| U+1F466 U+1F3FB U+20E3");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Variation selector + end with ZERO WIDTH JOINER
+        state.setByString("| U+2665 U+FE0F U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Variation selector + ZERO WIDTH JOINER
+        state.setByString("| U+1F469 U+200D U+2764 U+FE0F U+200D U+1F469");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Start with ZERO WIDTH JOINER + variation selector
+        state.setByString("| U+200D U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // ZERO WIDTH JOINER + variation selector
+        state.setByString("| U+1F469 U+200D U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Variation selector + regional indicator symbol
+        state.setByString("| U+2665 U+FE0F U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Regional indicator symbol + variation selector
+        state.setByString("| U+1F1FA U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Variation selector + emoji modifier
+        state.setByString("| U+2665 U+FE0F U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+
+        // Emoji modifier + variation selector
+        state.setByString("| U+1F466 U+1F3FB U+FE0F");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Start with ZERO WIDTH JOINER + regional indicator symbol
+        state.setByString("| U+200D U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // ZERO WIDTH JOINER + regional indicator symbol
+        state.setByString("| U+1F469 U+200D U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+
+        // Regional indicator symbol + end with ZERO WIDTH JOINER
+        state.setByString("| U+1F1FA U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Regional indicator symbol + ZERO WIDTH JOINER
+        state.setByString("| U+1F1FA U+200D U+1F469");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F469");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Start with ZERO WIDTH JOINER + emoji modifier
+        state.setByString("| U+200D U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+
+        // ZERO WIDTH JOINER + emoji modifier
+        state.setByString("| U+1F469 U+200D U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+
+        // Emoji modifier + end with ZERO WIDTH JOINER
+        state.setByString("| U+1F466 U+1F3FB U+200D");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Emoji modifier + ZERO WIDTH JOINER
+        state.setByString("| U+1F466 U+1F3FB U+200D U+1F469");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F469");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Regional indicator symbol + emoji modifier
+        state.setByString("| U+1F1FA U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F3FB");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+
+        // Emoji modifier + regional indicator symbol
+        state.setByString("| U+1F466 U+1F3FB U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("| U+1F1FA");
+        forwardDelete(state, 0);
+        state.assertEquals("|");
+    }
+}
index d383775..348f8fd 100644 (file)
@@ -25,7 +25,7 @@ import junit.framework.TestCase;
 
 public class PatternsTest extends TestCase {
 
-    //Tests for Patterns.TOP_LEVEL_DOMAIN
+    // Tests for Patterns.TOP_LEVEL_DOMAIN
 
     @SmallTest
     public void testTldPattern() throws Exception {
@@ -56,7 +56,7 @@ public class PatternsTest extends TestCase {
         assertFalse("Matched invalid TLD!", t);
     }
 
-    //Tests for Patterns.IANA_TOP_LEVEL_DOMAINS
+    // Tests for Patterns.IANA_TOP_LEVEL_DOMAINS
 
     @SmallTest
     public void testIanaTopLevelDomains_matchesValidTld() throws Exception {
@@ -94,7 +94,7 @@ public class PatternsTest extends TestCase {
         assertFalse("Should not match invalid Punycode TLD", pattern.matcher("xn").matches());
     }
 
-    //Tests for Patterns.WEB_URL
+    // Tests for Patterns.WEB_URL
 
     @SmallTest
     public void testWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
@@ -208,7 +208,7 @@ public class PatternsTest extends TestCase {
                 Patterns.WEB_URL.matcher(url).matches());
     }
 
-    //Tests for Patterns.AUTOLINK_WEB_URL
+    // Tests for Patterns.AUTOLINK_WEB_URL
 
     @SmallTest
     public void testAutoLinkWebUrl_matchesValidUrlWithSchemeAndHostname() throws Exception {
@@ -419,7 +419,7 @@ public class PatternsTest extends TestCase {
                 Patterns.AUTOLINK_WEB_URL.matcher(url).matches());
     }
 
-    //Tests for Patterns.IP_ADDRESS
+    // Tests for Patterns.IP_ADDRESS
 
     @SmallTest
     public void testIpPattern() throws Exception {
@@ -432,7 +432,7 @@ public class PatternsTest extends TestCase {
         assertFalse("Invalid IP", t);
     }
 
-    //Tests for Patterns.DOMAIN_NAME
+    // Tests for Patterns.DOMAIN_NAME
 
     @SmallTest
     public void testDomain_matchesPunycodeTld() throws Exception {
@@ -508,7 +508,227 @@ public class PatternsTest extends TestCase {
                 Patterns.DOMAIN_NAME.matcher(domain).matches());
     }
 
-    //Tests for Patterns.PHONE
+    // Tests for Patterns.AUTOLINK_EMAIL_ADDRESS
+
+    public void testAutoLinkEmailAddress_matchesShortValidEmail() throws Exception {
+        String email = "a@a.co";
+        assertTrue("Should match short valid email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesRegularEmail() throws Exception {
+        String email = "email@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesEmailWithMultipleSubdomains() throws Exception {
+        String email = "email@e.somelongdomainnameforandroid.abc.uk";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithDot() throws Exception {
+        String email = "e.mail@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithPlus() throws Exception {
+        String email = "e+mail@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithUnderscore() throws Exception {
+        String email = "e_mail@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithDash() throws Exception {
+        String email = "e-mail@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithApostrophe() throws Exception {
+        String email = "e'mail@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithDigits() throws Exception {
+        String email = "123@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesUnicodeLocalPart() throws Exception {
+        String email = "\uD604\uAE08\uC601\uC218\uC99D@android.kr";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithEmoji() throws Exception {
+        String email = "smiley\u263A@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartWithSurrogatePairs() throws Exception {
+        String email = "\uD83C\uDF38@android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesDomainWithDash() throws Exception {
+        String email = "email@an-droid.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesUnicodeDomain() throws Exception {
+        String email = "email@\uD604\uAE08\uC601\uC218\uC99D.kr";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesUnicodeLocalPartAndDomain() throws Exception {
+        String email = "\uD604\uAE08\uC601\uC218\uC99D@\uD604\uAE08\uC601\uC218\uC99D.kr";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesDomainWithEmoji() throws Exception {
+        String email = "smiley@\u263Aandroid.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesDomainWithSurrogatePairs() throws Exception {
+        String email = "email@\uD83C\uDF38android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartAndDomainWithSurrogatePairs()
+            throws Exception {
+        String email = "\uD83C\uDF38@\uD83C\uDF38android.com";
+        assertTrue("Should match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchStringWithoutAtSign() throws Exception {
+        String email = "android.com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchPlainString() throws Exception {
+        String email = "email";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchStringWithMultipleAtSigns() throws Exception {
+        String email = "email@android@android.com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchEmailWithoutTld() throws Exception {
+        String email = "email@android";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchLocalPartEndingWithDot() throws Exception {
+        String email = "email.@android.com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchLocalPartStartingWithDot() throws Exception {
+        String email = ".email@android.com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchDomainStartingWithDash() throws Exception {
+        String email = "email@-android.com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchDomainWithConsecutiveDots() throws Exception {
+        String email = "email@android..com";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchEmailWithIpAsDomain() throws Exception {
+        String email = "email@127.0.0.1";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_doesNotMatchEmailWithInvalidTld() throws Exception {
+        String email = "email@android.c";
+        assertFalse("Should not match email: " + email,
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesLocalPartUpTo64Chars() throws Exception {
+        String localPart = "";
+        for (int i = 0; i < 64; i++) {
+            localPart += "a";
+        }
+        String email = localPart + "@android.com";
+
+        assertTrue("Should match local part of length: " + localPart.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+
+        email = localPart + "a@android.com";
+        assertFalse("Should not match local part of length: " + localPart.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesSubdomainUpTo63Chars() throws Exception {
+        String subdomain = "";
+        for (int i = 0; i < 63; i++) {
+            subdomain += "a";
+        }
+        String email = "email@" + subdomain + ".com";
+
+        assertTrue("Should match subdomain of length: " + subdomain.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+
+        subdomain += "a";
+        email = "email@" + subdomain + ".com";
+        assertFalse("Should not match local part of length: " + subdomain.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    public void testAutoLinkEmailAddress_matchesDomainUpTo255Chars() throws Exception {
+        String longDomain = "";
+        while (longDomain.length() <= 250) {
+            longDomain += "d.";
+        }
+        longDomain += "com";
+        assertEquals(255, longDomain.length());
+        String email = "a@" + longDomain;
+
+        assertTrue("Should match domain of length: " + longDomain.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+
+        email = email + "m";
+        assertEquals(258, email.length());
+        assertFalse("Should not match domain of length: " + longDomain.length(),
+                Patterns.AUTOLINK_EMAIL_ADDRESS.matcher(email).matches());
+    }
+
+    // Tests for Patterns.PHONE
 
     @SmallTest
     public void testPhonePattern() throws Exception {
index ac020e4..719b274 100644 (file)
@@ -70,6 +70,7 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
     private static final Locale LOCALE_TH_TH_TH = new Locale("ht", "TH", "TH");
     private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
     private static final String SUBTYPE_MODE_VOICE = "voice";
+    private static final String SUBTYPE_MODE_HANDWRITING = "handwriting";
     private static final String SUBTYPE_MODE_ANY = null;
     private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
     private static final String EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
@@ -215,6 +216,12 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
         final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja",
                 SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
                 !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoHi = createDummyInputMethodSubtype("hi",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoHandwritingEn = createDummyInputMethodSubtype("en",
+                SUBTYPE_MODE_HANDWRITING, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
         final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype =
                 createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
                         !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
@@ -349,6 +356,57 @@ public class InputMethodUtilsTest extends InstrumentationTestCase {
             verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2, result.get(2));
         }
 
+        // Make sure that if there is no subtype that matches the language requested, then we just
+        // use the first keyboard subtype.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+            subtypes.add(nonAutoHi);
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+                            getResourcesForLocales(LOCALE_JA_JP), imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoHi, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoHi);
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+                            getResourcesForLocales(LOCALE_JA_JP), imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoEnUS, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
+            subtypes.add(nonAutoHandwritingEn);
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoHi);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    InputMethodUtils.getImplicitlyApplicableSubtypesLocked(
+                            getResourcesForLocales(LOCALE_JA_JP), imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoEnUS, result.get(0));
+        }
+
         // Make sure that 3-letter language code can be handled.
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<>();
index d96914f..b981d83 100644 (file)
@@ -23,8 +23,8 @@ key A {
     number:                             '2'
     base:                               'a'
     shift, capslock:                    'A'
-    alt:                                'a'
-    shift+alt, capslock+alt:            'A'
+    alt:                                '\u00e1'
+    shift+alt, capslock+alt:            '\u00c1'
 }
 
 key B {
@@ -41,8 +41,8 @@ key C {
     number:                             '2'
     base:                               'c'
     shift, capslock:                    'C'
-    alt:                                '\u00e7'
-    shift+alt, capslock+alt:            '\u00e7'
+    alt:                                '\u00a9'
+    shift+alt, capslock+alt:            '\u00a2'
 }
 
 key D {
@@ -50,8 +50,8 @@ key D {
     number:                             '3'
     base:                               'd'
     shift, capslock:                    'D'
-    alt:                                '\''
-    shift+alt, capslock+alt:            '\''
+    alt:                                '\u00f0'
+    shift+alt, capslock+alt:            '\u00d0'
 }
 
 key E {
@@ -59,8 +59,8 @@ key E {
     number:                             '3'
     base:                               'e'
     shift, capslock:                    'E'
-    alt:                                '"'
-    shift+alt, capslock+alt:            '\u0301'
+    alt:                                '\u00e9'
+    shift+alt, capslock+alt:            '\u00c9'
 }
 
 key F {
@@ -95,8 +95,8 @@ key I {
     number:                             '4'
     base:                               'i'
     shift, capslock:                    'I'
-    alt:                                '-'
-    shift+alt, capslock+alt:            '\u0302'
+    alt:                                '\u00ed'
+    shift+alt, capslock+alt:            '\u00cd'
 }
 
 key J {
@@ -122,8 +122,8 @@ key L {
     number:                             '5'
     base:                               'l'
     shift, capslock:                    'L'
-    alt:                                ':'
-    shift+alt, capslock+alt:            '`'
+    alt:                                '\u00f8'
+    shift+alt, capslock+alt:            '\u00d8'
 }
 
 key M {
@@ -131,7 +131,7 @@ key M {
     number:                             '6'
     base:                               'm'
     shift, capslock:                    'M'
-    alt:                                '%'
+    alt:                                '\u00b5'
     shift+alt, capslock+alt:            none
 }
 
@@ -140,8 +140,8 @@ key N {
     number:                             '6'
     base:                               'n'
     shift, capslock:                    'N'
-    alt:                                none
-    shift+alt, capslock+alt:            '\u0303'
+    alt:                                '\u00f1'
+    shift+alt, capslock+alt:            '\u00d1'
 }
 
 key O {
@@ -149,8 +149,8 @@ key O {
     number:                             '6'
     base:                               'o'
     shift, capslock:                    'O'
-    alt:                                '+'
-    shift+alt, capslock+alt:            '+'
+    alt:                                '\u00f3'
+    shift+alt, capslock+alt:            '\u00d3'
 }
 
 key P {
@@ -158,8 +158,8 @@ key P {
     number:                             '7'
     base:                               'p'
     shift, capslock:                    'P'
-    alt:                                '='
-    shift+alt, capslock+alt:            '\u00a5'
+    alt:                                '\u00f6'
+    shift+alt, capslock+alt:            '\u00d6'
 }
 
 key Q {
@@ -167,8 +167,8 @@ key Q {
     number:                             '7'
     base:                               'q'
     shift, capslock:                    'Q'
-    alt:                                '|'
-    shift+alt, capslock+alt:            '\u0300'
+    alt:                                '\u00e4'
+    shift+alt, capslock+alt:            '\u00c4'
 }
 
 key R {
@@ -176,8 +176,8 @@ key R {
     number:                             '7'
     base:                               'r'
     shift, capslock:                    'R'
-    alt:                                '`'
-    shift+alt, capslock+alt:            '\u20ac'
+    alt:                                '\u00ae'
+    shift+alt, capslock+alt:            'R'
 }
 
 key S {
@@ -185,8 +185,8 @@ key S {
     number:                             '7'
     base:                               's'
     shift, capslock:                    'S'
-    alt:                                '\\'
-    shift+alt, capslock+alt:            '\u00df'
+    alt:                                '\u00df'
+    shift+alt, capslock+alt:            '\u00a7'
 }
 
 key T {
@@ -194,8 +194,8 @@ key T {
     number:                             '8'
     base:                               't'
     shift, capslock:                    'T'
-    alt:                                '{'
-    shift+alt, capslock+alt:            '\u00a3'
+    alt:                                '\u00fe'
+    shift+alt, capslock+alt:            '\u00de'
 }
 
 key U {
@@ -203,8 +203,8 @@ key U {
     number:                             '8'
     base:                               'u'
     shift, capslock:                    'U'
-    alt:                                '_'
-    shift+alt, capslock+alt:            '\u0308'
+    alt:                                '\u00fa'
+    shift+alt, capslock+alt:            '\u00da'
 }
 
 key V {
@@ -221,8 +221,8 @@ key W {
     number:                             '9'
     base:                               'w'
     shift, capslock:                    'W'
-    alt:                                '~'
-    shift+alt, capslock+alt:            '~'
+    alt:                                '\u00e5'
+    shift+alt, capslock+alt:            '\u00c5'
 }
 
 key X {
@@ -239,8 +239,8 @@ key Y {
     number:                             '9'
     base:                               'y'
     shift, capslock:                    'Y'
-    alt:                                '}'
-    shift+alt, capslock+alt:            '\u00a1'
+    alt:                                '\u00fc'
+    shift+alt, capslock+alt:            '\u00dc'
 }
 
 key Z {
@@ -248,8 +248,8 @@ key Z {
     number:                             '9'
     base:                               'z'
     shift, capslock:                    'Z'
-    alt:                                'z'
-    shift+alt, capslock+alt:            'Z'
+    alt:                                '\u00e6'
+    shift+alt, capslock+alt:            '\u00c6'
 }
 
 key COMMA {
@@ -257,8 +257,8 @@ key COMMA {
     number:                             ','
     base:                               ','
     shift:                              '<'
-    alt:                                ','
-    shift+alt:                          ','
+    alt:                                '\u00e7'
+    shift+alt:                          '\u00c7'
 }
 
 key PERIOD {
@@ -284,7 +284,7 @@ key SLASH {
     number:                             '/'
     base:                               '/'
     shift:                              '?'
-    alt:                                '?'
+    alt:                                '\u00bf'
     shift+alt:                          '?'
 }
 
@@ -320,7 +320,7 @@ key 0 {
     number:                             '0'
     base:                               '0'
     shift:                              ')'
-    alt:                                ')'
+    alt:                                '\u02bc'
     shift+alt:                          ')'
 }
 
@@ -329,8 +329,8 @@ key 1 {
     number:                             '1'
     base:                               '1'
     shift:                              '!'
-    alt:                                '!'
-    shift+alt:                          '!'
+    alt:                                '\u00a1'
+    shift+alt:                          '\u00b9'
 }
 
 key 2 {
@@ -338,7 +338,7 @@ key 2 {
     number:                             '2'
     base:                               '2'
     shift:                              '@'
-    alt:                                '@'
+    alt:                                '\u00b2'
     shift+alt:                          '@'
 }
 
@@ -347,7 +347,7 @@ key 3 {
     number:                             '3'
     base:                               '3'
     shift:                              '#'
-    alt:                                '#'
+    alt:                                '\u00b3'
     shift+alt:                          '#'
 }
 
@@ -356,8 +356,8 @@ key 4 {
     number:                             '4'
     base:                               '4'
     shift:                              '$'
-    alt:                                '$'
-    shift+alt:                          '$'
+    alt:                                '\u00a4'
+    shift+alt:                          '\u00a3'
 }
 
 key 5 {
@@ -365,7 +365,7 @@ key 5 {
     number:                             '5'
     base:                               '5'
     shift:                              '%'
-    alt:                                '%'
+    alt:                                '\u20ac'
     shift+alt:                          '%'
 }
 
@@ -374,8 +374,8 @@ key 6 {
     number:                             '6'
     base:                               '6'
     shift:                              '^'
-    alt:                                '^'
-    shift+alt:                          '^'
+    alt:                                '\u00bc'
+    shift+alt:                          '\u0302'
 }
 
 key 7 {
@@ -383,7 +383,7 @@ key 7 {
     number:                             '7'
     base:                               '7'
     shift:                              '&'
-    alt:                                '&'
+    alt:                                '\u00bd'
     shift+alt:                          '&'
 }
 
@@ -392,7 +392,7 @@ key 8 {
     number:                             '8'
     base:                               '8'
     shift:                              '*'
-    alt:                                '*'
+    alt:                                '\u00be'
     shift+alt:                          '*'
 }
 
@@ -401,7 +401,7 @@ key 9 {
     number:                             '9'
     base:                               '9'
     shift:                              '('
-    alt:                                '('
+    alt:                                '\u02bb'
     shift+alt:                          '('
 }
 
@@ -410,8 +410,8 @@ key GRAVE {
     number:                             '`'
     base:                               '`'
     shift:                              '~'
-    alt:                                '`'
-    shift+alt:                          '~'
+    alt:                                '\u0300'
+    shift+alt:                          '\u0303'
 }
 
 key MINUS {
@@ -419,7 +419,7 @@ key MINUS {
     number:                             '-'
     base:                               '-'
     shift:                              '_'
-    alt:                                '-'
+    alt:                                '\u00a5'
     shift+alt:                          '_'
 }
 
@@ -428,8 +428,8 @@ key EQUALS {
     number:                             '='
     base:                               '='
     shift:                              '+'
-    alt:                                '='
-    shift+alt:                          '+'
+    alt:                                '\u00d7'
+    shift+alt:                          '\u00f7'
 }
 
 key LEFT_BRACKET {
@@ -437,7 +437,7 @@ key LEFT_BRACKET {
     number:                             '['
     base:                               '['
     shift:                              '{'
-    alt:                                '['
+    alt:                                '\u00ab'
     shift+alt:                          '{'
 }
 
@@ -446,7 +446,7 @@ key RIGHT_BRACKET {
     number:                             ']'
     base:                               ']'
     shift:                              '}'
-    alt:                                ']'
+    alt:                                '\u00bb'
     shift+alt:                          '}'
 }
 
@@ -455,8 +455,8 @@ key BACKSLASH {
     number:                             '\\'
     base:                               '\\'
     shift:                              '|'
-    alt:                                '\\'
-    shift+alt:                          '|'
+    alt:                                '\u00ac'
+    shift+alt:                          '\u00a6'
 }
 
 key SEMICOLON {
@@ -464,8 +464,8 @@ key SEMICOLON {
     number:                             ';'
     base:                               ';'
     shift:                              ':'
-    alt:                                ';'
-    shift+alt:                          ':'
+    alt:                                '\u00b6'
+    shift+alt:                          '\u00b0'
 }
 
 key APOSTROPHE {
@@ -473,8 +473,8 @@ key APOSTROPHE {
     number:                             '\''
     base:                               '\''
     shift:                              '"'
-    alt:                                '\''
-    shift+alt:                          '"'
+    alt:                                '\u0301'
+    shift+alt:                          '\u0308'
 }
 
 key STAR {
index 0b3cb2b..53faca0 100644 (file)
@@ -465,6 +465,7 @@ private Sensor mSensor;
 ...
 
 mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
+mSensor = null;
 
 if (mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
   List&lt;Sensor&gt; gravSensors = mSensorManager.getSensorList(Sensor.TYPE_GRAVITY);
@@ -476,7 +477,7 @@ if (mSensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY) != null){
     }
   }
 }
-else{
+if (mSensor == null){
   // Use the accelerometer.
   if (mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER) != null){
     mSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
index d4f745d..af99f79 100644 (file)
@@ -91,8 +91,11 @@ public class Canvas {
     // a Canvas object.
     private static final long NATIVE_ALLOCATION_SIZE = 525;
 
-    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-        getNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+    // Use a Holder to allow static initialization of Canvas in the boot image.
+    private static class NoImagePreloadHolder {
+        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+                getNativeFinalizer(), NATIVE_ALLOCATION_SIZE);
+    }
 
     // This field is used to finalize the native Canvas properly
     private Runnable mFinalizer;
@@ -107,7 +110,8 @@ public class Canvas {
         if (!isHardwareAccelerated()) {
             // 0 means no native bitmap
             mNativeCanvasWrapper = initRaster(null);
-            mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
+            mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+                    this, mNativeCanvasWrapper);
         } else {
             mFinalizer = null;
         }
@@ -128,7 +132,8 @@ public class Canvas {
         }
         throwIfCannotDraw(bitmap);
         mNativeCanvasWrapper = initRaster(bitmap);
-        mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
+        mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+                this, mNativeCanvasWrapper);
         mBitmap = bitmap;
         mDensity = bitmap.mDensity;
     }
@@ -139,7 +144,8 @@ public class Canvas {
             throw new IllegalStateException();
         }
         mNativeCanvasWrapper = nativeCanvas;
-        mFinalizer = sRegistry.registerNativeAllocation(this, mNativeCanvasWrapper);
+        mFinalizer = NoImagePreloadHolder.sRegistry.registerNativeAllocation(
+                this, mNativeCanvasWrapper);
         mDensity = Bitmap.getDefaultDensity();
     }
 
index 534121a..291fdc4 100644 (file)
@@ -44,8 +44,11 @@ public class Paint {
     // The approximate size of a native paint object.
     private static final long NATIVE_PAINT_SIZE = 98;
 
-    private static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
-        nGetNativeFinalizer(), NATIVE_PAINT_SIZE);
+    // Use a Holder to allow static initialization of Paint in the boot image.
+    private static class NoImagePreloadHolder {
+        public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry(
+                nGetNativeFinalizer(), NATIVE_PAINT_SIZE);
+    }
 
     /**
      * @hide
@@ -452,7 +455,7 @@ public class Paint {
      */
     public Paint(int flags) {
         mNativePaint = nInit();
-        sRegistry.registerNativeAllocation(this, mNativePaint);
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint);
         setFlags(flags | HIDDEN_DEFAULT_PAINT_FLAGS);
         // TODO: Turning off hinting has undesirable side effects, we need to
         //       revisit hinting once we add support for subpixel positioning
@@ -471,7 +474,7 @@ public class Paint {
      */
     public Paint(Paint paint) {
         mNativePaint = nInitWithPaint(paint.getNativeInstance());
-        sRegistry.registerNativeAllocation(this, mNativePaint);
+        NoImagePreloadHolder.sRegistry.registerNativeAllocation(this, mNativePaint);
         setClassVariablesFrom(paint);
     }
 
index 3901af3..ca214ab 100644 (file)
@@ -40,6 +40,7 @@ import android.graphics.Rect;
 import android.os.Build;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
+import android.util.IntArray;
 import android.util.Log;
 import android.util.LongArray;
 import android.util.PathParser;
@@ -629,12 +630,24 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
      */
     public void reset() {
         ensureAnimatorSet();
+        if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+            Log.w(LOGTAG, "calling reset on AVD: " +
+                    ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+                    getConstantState()).mVectorDrawable.getConstantState()).mRootName
+                    + ", at: " + this);
+        }
         mAnimatorSet.reset();
     }
 
     @Override
     public void start() {
         ensureAnimatorSet();
+        if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+            Log.w(LOGTAG, "calling start on AVD: " +
+                    ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+                    getConstantState()).mVectorDrawable.getConstantState()).mRootName
+                    + ", at: " + this);
+        }
         mAnimatorSet.start();
     }
 
@@ -652,6 +665,12 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
 
     @Override
     public void stop() {
+        if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+            Log.w(LOGTAG, "calling stop on AVD: " +
+                    ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+                            getConstantState()).mVectorDrawable.getConstantState())
+                            .mRootName + ", at: " + this);
+        }
         mAnimatorSet.end();
     }
 
@@ -864,9 +883,10 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
      * @hide
      */
     public static class VectorDrawableAnimatorRT implements VectorDrawableAnimator {
-        private static final int NONE = 0;
         private static final int START_ANIMATION = 1;
         private static final int REVERSE_ANIMATION = 2;
+        private static final int RESET_ANIMATION = 3;
+        private static final int END_ANIMATION = 4;
         private AnimatorListener mListener = null;
         private final LongArray mStartDelays = new LongArray();
         private PropertyValuesHolder.PropertyValues mTmpValues =
@@ -882,7 +902,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
         private final VirtualRefBasePtr mSetRefBasePtr;
         private WeakReference<RenderNode> mLastSeenTarget = null;
         private int mLastListenerId = 0;
-        private int mPendingAnimationAction = NONE;
+        private final IntArray mPendingAnimationActions = new IntArray();
         private final Drawable mDrawable;
 
         VectorDrawableAnimatorRT(AnimatedVectorDrawable drawable) {
@@ -1139,16 +1159,29 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
         protected void recordLastSeenTarget(DisplayListCanvas canvas) {
             mLastSeenTarget = new WeakReference<RenderNode>(
                     RenderNodeAnimatorSetHelper.getTarget(canvas));
-            if (mPendingAnimationAction != NONE) {
+            if (mPendingAnimationActions.size() > 0 && useLastSeenTarget()) {
                 if (DBG_ANIMATION_VECTOR_DRAWABLE) {
                     Log.d(LOGTAG, "Target is set in the next frame");
                 }
-                if (mPendingAnimationAction == START_ANIMATION) {
-                    start();
-                } else if (mPendingAnimationAction == REVERSE_ANIMATION) {
-                    reverse();
+                for (int i = 0; i < mPendingAnimationActions.size(); i++) {
+                    handlePendingAction(mPendingAnimationActions.get(i));
                 }
-                mPendingAnimationAction = NONE;
+                mPendingAnimationActions.clear();
+            }
+        }
+
+        private void handlePendingAction(int pendingAnimationAction) {
+            if (pendingAnimationAction == START_ANIMATION) {
+                startAnimation();
+            } else if (pendingAnimationAction == REVERSE_ANIMATION) {
+                reverseAnimation();
+            } else if (pendingAnimationAction == RESET_ANIMATION) {
+                resetAnimation();
+            } else if (pendingAnimationAction == END_ANIMATION) {
+                endAnimation();
+            } else {
+                throw new UnsupportedOperationException("Animation action " +
+                        pendingAnimationAction + "is not supported");
             }
         }
 
@@ -1167,45 +1200,51 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
             mDrawable.invalidateSelf();
         }
 
+        private void addPendingAction(int pendingAnimationAction) {
+            invalidateOwningView();
+            mPendingAnimationActions.add(pendingAnimationAction);
+        }
+
         @Override
         public void start() {
             if (!mInitialized) {
                 return;
             }
 
-            if (!useLastSeenTarget()) {
-                invalidateOwningView();
-                mPendingAnimationAction = START_ANIMATION;
-                return;
-            }
-
-            if (DBG_ANIMATION_VECTOR_DRAWABLE) {
-                Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java");
+            if (useLastSeenTarget()) {
+                if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+                    Log.d(LOGTAG, "Target is set. Starting VDAnimatorSet from java");
+                }
+                startAnimation();
+            } else {
+                addPendingAction(START_ANIMATION);
             }
 
-            mStarted = true;
-            nStart(mSetPtr, this, ++mLastListenerId);
-            invalidateOwningView();
-            if (mListener != null) {
-                mListener.onAnimationStart(null);
-            }
         }
 
         @Override
         public void end() {
-            if (mInitialized && useLastSeenTarget()) {
-                // If no target has ever been set, no-op
-                nEnd(mSetPtr);
-                invalidateOwningView();
+            if (!mInitialized) {
+                return;
+            }
+
+            if (useLastSeenTarget()) {
+                endAnimation();
+            } else {
+                addPendingAction(END_ANIMATION);
             }
         }
 
         @Override
         public void reset() {
-            if (mInitialized && useLastSeenTarget()) {
-                // If no target has ever been set, no-op
-                nReset(mSetPtr);
-                invalidateOwningView();
+            if (!mInitialized) {
+                return;
+            }
+
+            if (useLastSeenTarget()) {
+                resetAnimation();
+            } else {
+                addPendingAction(RESET_ANIMATION);
             }
         }
 
@@ -1216,15 +1255,53 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable2 {
             if (!mIsReversible || !mInitialized) {
                 return;
             }
-            if (!useLastSeenTarget()) {
-                invalidateOwningView();
-                mPendingAnimationAction = REVERSE_ANIMATION;
-                return;
+            if (useLastSeenTarget()) {
+                if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+                    Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java");
+                }
+                reverseAnimation();
+            } else {
+                addPendingAction(REVERSE_ANIMATION);
             }
+        }
+
+        // This should only be called after animator has been added to the RenderNode target.
+        private void startAnimation() {
             if (DBG_ANIMATION_VECTOR_DRAWABLE) {
-                Log.d(LOGTAG, "Target is set. Reversing VDAnimatorSet from java");
+                Log.w(LOGTAG, "starting animation on VD: " +
+                        ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+                                mDrawable.getConstantState()).mVectorDrawable.getConstantState())
+                                .mRootName);
             }
             mStarted = true;
+            nStart(mSetPtr, this, ++mLastListenerId);
+            invalidateOwningView();
+            if (mListener != null) {
+                mListener.onAnimationStart(null);
+            }
+        }
+
+        // This should only be called after animator has been added to the RenderNode target.
+        private void endAnimation() {
+            if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+                Log.w(LOGTAG, "ending animation on VD: " +
+                        ((VectorDrawable.VectorDrawableState) ((AnimatedVectorDrawableState)
+                                mDrawable.getConstantState()).mVectorDrawable.getConstantState())
+                                .mRootName);
+            }
+            nEnd(mSetPtr);
+            invalidateOwningView();
+        }
+
+        // This should only be called after animator has been added to the RenderNode target.
+        private void resetAnimation() {
+            nReset(mSetPtr);
+            invalidateOwningView();
+        }
+
+        // This should only be called after animator has been added to the RenderNode target.
+        private void reverseAnimation() {
+            mStarted = true;
             nReverse(mSetPtr, this, ++mLastListenerId);
             invalidateOwningView();
             if (mListener != null) {
index d8801b8..f23fceb 100644 (file)
@@ -1151,9 +1151,13 @@ struct ResTable_config
         uint32_t screenConfig2;
     };
 
-    // If true, it means that the script of the locale was explicitly provided.
-    // If false, it means that the script was automatically computed.
-    bool localeScriptWasProvided;
+    // If false and localeScript is set, it means that the script of the locale
+    // was explicitly provided.
+    //
+    // If true, it means that localeScript was automatically computed.
+    // localeScript may still not be set in this case, which means that we
+    // tried but could not compute a script.
+    bool localeScriptWasComputed;
 
     void copyFromDeviceNoSwap(const ResTable_config& o);
     
@@ -1233,7 +1237,7 @@ struct ResTable_config
 
     inline void clearLocale() {
         locale = 0;
-        localeScriptWasProvided = false;
+        localeScriptWasComputed = false;
         memset(localeScript, 0, sizeof(localeScript));
         memset(localeVariant, 0, sizeof(localeVariant));
     }
@@ -1896,6 +1900,13 @@ private:
 
     mutable Mutex               mLock;
 
+    // Mutex that controls access to the list of pre-filtered configurations
+    // to check when looking up entries.
+    // When iterating over a bag, the mLock mutex is locked. While mLock is locked,
+    // we do resource lookups.
+    // Mutex is not reentrant, so we must use a different lock than mLock.
+    mutable Mutex               mFilteredConfigLock;
+
     status_t                    mError;
 
     ResTable_config             mParams;
index 302b0bd..6830a74 100644 (file)
@@ -217,42 +217,42 @@ public class Credentials {
     }
 
     /**
-     * Delete all types (private key, certificate, CA certificate) for a
+     * Delete all types (private key, user certificate, CA certificate) for a
      * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if there was at least one of those types.
+     * Returns {@code true} if the alias no longer contains any types.
      */
     public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
         return deleteAllTypesForAlias(keystore, alias, KeyStore.UID_SELF);
     }
 
     /**
-     * Delete all types (private key, certificate, CA certificate) for a
+     * Delete all types (private key, user certificate, CA certificate) for a
      * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if there was at least one of those types.
+     * Returns {@code true} if the alias no longer contains any types.
      */
     public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias, int uid) {
         /*
          * Make sure every type is deleted. There can be all three types, so
          * don't use a conditional here.
          */
-        return keystore.delete(Credentials.USER_PRIVATE_KEY + alias, uid)
-                | keystore.delete(Credentials.USER_SECRET_KEY + alias, uid)
-                | deleteCertificateTypesForAlias(keystore, alias, uid);
+        return deletePrivateKeyTypeForAlias(keystore, alias, uid)
+                & deleteSecretKeyTypeForAlias(keystore, alias, uid)
+                & deleteCertificateTypesForAlias(keystore, alias, uid);
     }
 
     /**
-     * Delete all types (private key, certificate, CA certificate) for a
-     * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if there was at least one of those types.
+     * Delete certificate types (user certificate, CA certificate) for a
+     * particular {@code alias}. Both can exist for any given alias.
+     * Returns {@code true} if the alias no longer contains either type.
      */
     public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias) {
         return deleteCertificateTypesForAlias(keystore, alias, KeyStore.UID_SELF);
     }
 
     /**
-     * Delete all types (private key, certificate, CA certificate) for a
-     * particular {@code alias}. All three can exist for any given alias.
-     * Returns {@code true} if there was at least one of those types.
+     * Delete certificate types (user certificate, CA certificate) for a
+     * particular {@code alias}. Both can exist for any given alias.
+     * Returns {@code true} if the alias no longer contains either type.
      */
     public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias, int uid) {
         /*
@@ -260,12 +260,12 @@ public class Credentials {
          * so don't use a conditional here.
          */
         return keystore.delete(Credentials.USER_CERTIFICATE + alias, uid)
-                | keystore.delete(Credentials.CA_CERTIFICATE + alias, uid);
+                & keystore.delete(Credentials.CA_CERTIFICATE + alias, uid);
     }
 
     /**
      * Delete private key for a particular {@code alias}.
-     * Returns {@code true} if an entry was was deleted.
+     * Returns {@code true} if the entry no longer exists.
      */
     static boolean deletePrivateKeyTypeForAlias(KeyStore keystore, String alias) {
         return deletePrivateKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
@@ -273,7 +273,7 @@ public class Credentials {
 
     /**
      * Delete private key for a particular {@code alias}.
-     * Returns {@code true} if an entry was was deleted.
+     * Returns {@code true} if the entry no longer exists.
      */
     static boolean deletePrivateKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
         return keystore.delete(Credentials.USER_PRIVATE_KEY + alias, uid);
@@ -281,7 +281,7 @@ public class Credentials {
 
     /**
      * Delete secret key for a particular {@code alias}.
-     * Returns {@code true} if an entry was was deleted.
+     * Returns {@code true} if the entry no longer exists.
      */
     public static boolean deleteSecretKeyTypeForAlias(KeyStore keystore, String alias) {
         return deleteSecretKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
@@ -289,7 +289,7 @@ public class Credentials {
 
     /**
      * Delete secret key for a particular {@code alias}.
-     * Returns {@code true} if an entry was was deleted.
+     * Returns {@code true} if the entry no longer exists.
      */
     public static boolean deleteSecretKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
         return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
index 7adad8a..0886487 100644 (file)
@@ -547,11 +547,8 @@ public final class KeyChain {
         Intent intent = new Intent(IKeyChainService.class.getName());
         ComponentName comp = intent.resolveSystemService(context.getPackageManager(), 0);
         intent.setComponent(comp);
-        boolean isBound = context.bindServiceAsUser(intent,
-                                                    keyChainServiceConnection,
-                                                    Context.BIND_AUTO_CREATE,
-                                                    user);
-        if (!isBound) {
+        if (comp == null || !context.bindServiceAsUser(
+                intent, keyChainServiceConnection, Context.BIND_AUTO_CREATE, user)) {
             throw new AssertionError("could not bind to KeyChainService");
         }
         return new KeyChainConnection(context, keyChainServiceConnection, q.take());
index 3090ac1..70e4b6f 100644 (file)
@@ -183,7 +183,8 @@ public class KeyStore {
 
     public boolean delete(String key, int uid) {
         try {
-            return mBinder.del(key, uid) == NO_ERROR;
+            int ret = mBinder.del(key, uid);
+            return (ret == NO_ERROR || ret == KEY_NOT_FOUND);
         } catch (RemoteException e) {
             Log.w(TAG, "Cannot connect to keystore", e);
             return false;
index d7d4f1c..fcbb553 100644 (file)
@@ -765,11 +765,6 @@ public class AndroidKeyStoreSpi extends KeyStoreSpi {
 
     @Override
     public void engineDeleteEntry(String alias) throws KeyStoreException {
-        if (!engineContainsAlias(alias)) {
-            return;
-        }
-        // At least one entry corresponding to this alias exists in keystore
-
         if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid)) {
             throw new KeyStoreException("Failed to delete entry: " + alias);
         }
index 3277c36..49b3a51 100644 (file)
@@ -25,6 +25,7 @@
 #include <string.h>
 
 #include <limits>
+#include <memory>
 #include <type_traits>
 
 #include <androidfw/ByteBucketArray.h>
@@ -1869,8 +1870,8 @@ void ResTable_config::swapHtoD() {
 
     // The language & region are equal, so compare the scripts and variants.
     const char emptyScript[sizeof(l.localeScript)] = {'\0', '\0', '\0', '\0'};
-    const char *lScript = l.localeScriptWasProvided ? l.localeScript : emptyScript;
-    const char *rScript = r.localeScriptWasProvided ? r.localeScript : emptyScript;
+    const char *lScript = l.localeScriptWasComputed ? emptyScript : l.localeScript;
+    const char *rScript = r.localeScriptWasComputed ? emptyScript : r.localeScript;
     int script = memcmp(lScript, rScript, sizeof(l.localeScript));
     if (script) {
         return script;
@@ -2015,11 +2016,11 @@ int ResTable_config::isLocaleMoreSpecificThan(const ResTable_config& o) const {
     // scripts since it seems more useful to do so. We will consider
     // "en-US-POSIX" to be more specific than "en-Latn-US".
 
-    const int score = (localeScriptWasProvided ? 1 : 0) +
-        ((localeVariant[0] != 0) ? 2 : 0);
+    const int score = ((localeScript[0] != '\0' && !localeScriptWasComputed) ? 1 : 0) +
+        ((localeVariant[0] != '\0') ? 2 : 0);
 
-    const int oScore = (o.localeScriptWasProvided ? 1 : 0) +
-        ((o.localeVariant[0] != 0) ? 2 : 0);
+    const int oScore = (o.localeScript[0] != '\0' && !o.localeScriptWasComputed ? 1 : 0) +
+        ((o.localeVariant[0] != '\0') ? 2 : 0);
 
     return score - oScore;
 
@@ -2534,7 +2535,8 @@ bool ResTable_config::match(const ResTable_config& settings) const {
         if (settings.localeScript[0] == '\0') { // could not determine the request's script
             countriesMustMatch = true;
         } else {
-            if (localeScript[0] == '\0') { // script was not provided, so we try to compute it
+            if (localeScript[0] == '\0' && !localeScriptWasComputed) {
+                // script was not provided or computed, so we try to compute it
                 localeDataComputeScript(computed_script, language, country);
                 if (computed_script[0] == '\0') { // we could not compute the script
                     countriesMustMatch = true;
@@ -2683,8 +2685,8 @@ void ResTable_config::appendDirLocale(String8& out) const {
     if (!language[0]) {
         return;
     }
-
-    if (!localeScriptWasProvided && !localeVariant[0]) {
+    const bool scriptWasProvided = localeScript[0] != '\0' && !localeScriptWasComputed;
+    if (!scriptWasProvided && !localeVariant[0]) {
         // Legacy format.
         if (out.size() > 0) {
             out.append("-");
@@ -2714,7 +2716,7 @@ void ResTable_config::appendDirLocale(String8& out) const {
     size_t len = unpackLanguage(buf);
     out.append(buf, len);
 
-    if (localeScriptWasProvided) {
+    if (scriptWasProvided) {
         out.append("+");
         out.append(localeScript, sizeof(localeScript));
     }
@@ -2745,7 +2747,7 @@ void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const {
         charsWritten += unpackLanguage(str);
     }
 
-    if (localeScriptWasProvided) {
+    if (localeScript[0] && !localeScriptWasComputed) {
         if (charsWritten) {
             str[charsWritten++] = '-';
         }
@@ -2786,7 +2788,6 @@ void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const {
                for (size_t i = 1; i < 4; ++i) {
                    config->localeScript[i] = tolower(start[i]);
                }
-               config->localeScriptWasProvided = true;
                break;
            }
        case 5:
@@ -2806,7 +2807,6 @@ void ResTable_config::getBcp47Locale(char str[RESTABLE_MAX_LOCALE_LEN]) const {
 
 void ResTable_config::setBcp47Locale(const char* in) {
     locale = 0;
-    localeScriptWasProvided = false;
     memset(localeScript, 0, sizeof(localeScript));
     memset(localeVariant, 0, sizeof(localeVariant));
 
@@ -2823,9 +2823,10 @@ void ResTable_config::setBcp47Locale(const char* in) {
 
     const size_t size = in + strlen(in) - start;
     assignLocaleComponent(this, start, size);
-    if (localeScript[0] == '\0') {
+    localeScriptWasComputed = (localeScript[0] == '\0');
+    if (localeScriptWasComputed) {
         computeScript();
-    };
+    }
 }
 
 String8 ResTable_config::toString() const {
@@ -3146,6 +3147,9 @@ struct ResTable::Entry {
     StringPoolRef keyStr;
 };
 
+template <typename T>
+using SharedVector = std::shared_ptr<Vector<T>>;
+
 struct ResTable::Type
 {
     Type(const Header* _header, const Package* _package, size_t count)
@@ -3158,6 +3162,10 @@ struct ResTable::Type
     const uint32_t*                 typeSpecFlags;
     IdmapEntries                    idmapEntries;
     Vector<const ResTable_type*>    configs;
+
+    // The set of configurations that match the current parameters.
+    // This will be swapped with a new set when the parameters change.
+    SharedVector<const ResTable_type*> filteredConfigs;
 };
 
 struct ResTable::Package
@@ -4430,18 +4438,44 @@ ssize_t ResTable::getBagLocked(uint32_t resID, const bag_entry** outBag,
 
 void ResTable::setParameters(const ResTable_config* params)
 {
-    mLock.lock();
+    AutoMutex _lock(mLock);
+    AutoMutex _lock2(mFilteredConfigLock);
+
     if (kDebugTableGetEntry) {
         ALOGI("Setting parameters: %s\n", params->toString().string());
     }
     mParams = *params;
-    for (size_t i=0; i<mPackageGroups.size(); i++) {
+    for (size_t p = 0; p < mPackageGroups.size(); p++) {
+        PackageGroup* packageGroup = mPackageGroups.editItemAt(p);
         if (kDebugTableNoisy) {
-            ALOGI("CLEARING BAGS FOR GROUP %zu!", i);
+            ALOGI("CLEARING BAGS FOR GROUP %zu!", p);
+        }
+        packageGroup->clearBagCache();
+
+        for (size_t t = 0; t < packageGroup->types.size(); t++) {
+            TypeList& typeList = packageGroup->types.editItemAt(t);
+            for (size_t ts = 0; ts < typeList.size(); ts++) {
+                Type* type = typeList.editItemAt(ts);
+
+                SharedVector<const ResTable_type*> newFilteredConfigs =
+                        std::make_shared<Vector<const ResTable_type*>>();
+                for (size_t ti = 0; ti < type->configs.size(); ti++) {
+                    ResTable_config config;
+                    config.copyFromDtoH(type->configs[ti]->config);
+
+                    if (config.match(mParams)) {
+                        newFilteredConfigs->add(type->configs[ti]);
+                    }
+                }
+
+                if (kDebugTableNoisy) {
+                    ALOGD("Updating pkg=%zu type=%zu with %zu filtered configs",
+                          p, t, newFilteredConfigs->size());
+                }
+                type->filteredConfigs = newFilteredConfigs;
+            }
         }
-        mPackageGroups[i]->clearBagCache();
     }
-    mLock.unlock();
 }
 
 void ResTable::getParameters(ResTable_config* params) const
@@ -5974,9 +6008,29 @@ status_t ResTable::getEntry(
             specFlags = -1;
         }
 
-        const size_t numConfigs = typeSpec->configs.size();
+        const Vector<const ResTable_type*>* candidateConfigs = &typeSpec->configs;
+
+        SharedVector<const ResTable_type*> filteredConfigs;
+        if (config && memcmp(&mParams, config, sizeof(mParams)) == 0) {
+            // Grab the lock first so we can safely get the current filtered list.
+            AutoMutex _lock(mFilteredConfigLock);
+
+            // This configuration is equal to the one we have previously cached for,
+            // so use the filtered configs.
+
+            if (typeSpec->filteredConfigs) {
+                // Grab a reference to the shared_ptr so it doesn't get destroyed while
+                // going through this list.
+                filteredConfigs = typeSpec->filteredConfigs;
+
+                // Use this filtered list.
+                candidateConfigs = filteredConfigs.get();
+            }
+        }
+
+        const size_t numConfigs = candidateConfigs->size();
         for (size_t c = 0; c < numConfigs; c++) {
-            const ResTable_type* const thisType = typeSpec->configs[c];
+            const ResTable_type* const thisType = candidateConfigs->itemAt(c);
             if (thisType == NULL) {
                 continue;
             }
index 4b8d65c..2bf9b12 100644 (file)
@@ -125,10 +125,10 @@ TEST(ConfigLocaleTest, packAndUnpack3LetterRegion) {
 
      if (script != NULL) {
          memcpy(out->localeScript, script, 4);
-         out->localeScriptWasProvided = true;
+         out->localeScriptWasComputed = false;
      } else {
          out->computeScript();
-         out->localeScriptWasProvided = false;
+         out->localeScriptWasComputed = true;
      }
 
      if (variant != NULL) {
@@ -182,7 +182,7 @@ TEST(ConfigLocaleTest, setLocale) {
     EXPECT_EQ('n', test.language[1]);
     EXPECT_EQ('U', test.country[0]);
     EXPECT_EQ('S', test.country[1]);
-    EXPECT_FALSE(test.localeScriptWasProvided);
+    EXPECT_TRUE(test.localeScriptWasComputed);
     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
     EXPECT_EQ(0, test.localeVariant[0]);
 
@@ -203,7 +203,7 @@ TEST(ConfigLocaleTest, setLocale) {
     EXPECT_EQ('e', test.language[0]);
     EXPECT_EQ('n', test.language[1]);
     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
-    EXPECT_TRUE(test.localeScriptWasProvided);
+    EXPECT_FALSE(test.localeScriptWasComputed);
     memset(out, 1, 4);
     test.unpackRegion(out);
     EXPECT_EQ('4', out[0]);
@@ -216,7 +216,7 @@ TEST(ConfigLocaleTest, setLocale) {
     EXPECT_EQ('d', out[0]);
     EXPECT_EQ('e', out[1]);
     EXPECT_EQ('\0', out[2]);
-    EXPECT_FALSE(test.localeScriptWasProvided);
+    EXPECT_TRUE(test.localeScriptWasComputed);
     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
     memset(out, 1, 4);
     test.unpackRegion(out);
@@ -229,7 +229,7 @@ TEST(ConfigLocaleTest, setLocale) {
     EXPECT_EQ('d', out[0]);
     EXPECT_EQ('e', out[1]);
     EXPECT_EQ('\0', out[2]);
-    EXPECT_TRUE(test.localeScriptWasProvided);
+    EXPECT_FALSE(test.localeScriptWasComputed);
     EXPECT_EQ(0, memcmp("Latn", test.localeScript, 4));
     memset(out, 1, 4);
     test.unpackRegion(out);
@@ -270,11 +270,11 @@ TEST(ConfigLocaleTest, getBcp47Locale_script) {
     fillIn("en", NULL, "Latn", NULL, &config);
 
     char out[RESTABLE_MAX_LOCALE_LEN];
-    config.localeScriptWasProvided = true;
+    config.localeScriptWasComputed = false;
     config.getBcp47Locale(out);
     EXPECT_EQ(0, strcmp("en-Latn", out));
 
-    config.localeScriptWasProvided = false;
+    config.localeScriptWasComputed = true;
     config.getBcp47Locale(out);
     EXPECT_EQ(0, strcmp("en", out));
 }
@@ -379,7 +379,7 @@ TEST(ConfigLocaleTest, match_emptyScript) {
 
     // emulate packages built with older AAPT
     memset(supported.localeScript, '\0', 4);
-    supported.localeScriptWasProvided = false;
+    supported.localeScriptWasComputed = false;
 
     EXPECT_TRUE(supported.match(requested));
 }
index 8831baf..70995ac 100644 (file)
@@ -2,7 +2,7 @@ LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
 LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
-HWUI_NEW_OPS := false
+HWUI_NEW_OPS := true
 
 # Enables fine-grained GLES error checking
 # If set to true, every GLES call is wrapped & error checked
@@ -242,6 +242,7 @@ LOCAL_SRC_FILES += \
     tests/unit/GpuMemoryTrackerTests.cpp \
     tests/unit/LayerUpdateQueueTests.cpp \
     tests/unit/LinearAllocatorTests.cpp \
+    tests/unit/MatrixTests.cpp \
     tests/unit/OffscreenBufferPoolTests.cpp \
     tests/unit/SkiaBehaviorTests.cpp \
     tests/unit/StringUtilsTests.cpp \
index 2198fcc..f170e9c 100644 (file)
@@ -95,11 +95,11 @@ void AnimatorManager::onAnimatorTargetChanged(BaseRenderNodeAnimator* animator)
 
 class AnimateFunctor {
 public:
-    AnimateFunctor(TreeInfo& info, AnimationContext& context)
-            : dirtyMask(0), mInfo(info), mContext(context) {}
+    AnimateFunctor(TreeInfo& info, AnimationContext& context, uint32_t* outDirtyMask)
+            : mInfo(info), mContext(context), mDirtyMask(outDirtyMask) {}
 
     bool operator() (sp<BaseRenderNodeAnimator>& animator) {
-        dirtyMask |= animator->dirtyMask();
+        *mDirtyMask |= animator->dirtyMask();
         bool remove = animator->animate(mContext);
         if (remove) {
             animator->detach();
@@ -114,11 +114,10 @@ public:
         return remove;
     }
 
-    uint32_t dirtyMask;
-
 private:
     TreeInfo& mInfo;
     AnimationContext& mContext;
+    uint32_t* mDirtyMask;
 };
 
 uint32_t AnimatorManager::animate(TreeInfo& info) {
@@ -143,12 +142,13 @@ void AnimatorManager::animateNoDamage(TreeInfo& info) {
 }
 
 uint32_t AnimatorManager::animateCommon(TreeInfo& info) {
-    AnimateFunctor functor(info, mAnimationHandle->context());
+    uint32_t dirtyMask;
+    AnimateFunctor functor(info, mAnimationHandle->context(), &dirtyMask);
     auto newEnd = std::remove_if(mAnimators.begin(), mAnimators.end(), functor);
     mAnimators.erase(newEnd, mAnimators.end());
     mAnimationHandle->notifyAnimationsRan();
     mParent.mProperties.updateMatrix();
-    return functor.dirtyMask;
+    return dirtyMask;
 }
 
 static void endStagingAnimator(sp<BaseRenderNodeAnimator>& animator) {
index 78764b5..06b712e 100644 (file)
@@ -30,6 +30,7 @@
 #include <algorithm>
 #include <math.h>
 #include <SkPaintDefaults.h>
+#include <SkPathOps.h>
 
 namespace android {
 namespace uirenderer {
@@ -60,7 +61,10 @@ void BakedOpDispatcher::onMergedBitmapOps(BakedOpRenderer& renderer,
     for (size_t i = 0; i < opList.count; i++) {
         const BakedOpState& state = *(opList.states[i]);
         TextureVertex* rectVerts = &vertices[i * 4];
-        Rect opBounds = state.computedState.clippedBounds;
+
+        // calculate unclipped bounds, since they'll determine texture coordinates
+        Rect opBounds = state.op->unmappedBounds;
+        state.computedState.transform.mapRect(opBounds);
         if (CC_LIKELY(state.computedState.transform.isPureTranslate())) {
             // pure translate, so snap (same behavior as onBitmapOp)
             opBounds.snapToPixelBoundaries();
@@ -368,7 +372,7 @@ void BakedOpDispatcher::onArcOp(BakedOpRenderer& renderer, const ArcOp& op, cons
                 op.startAngle, op.sweepAngle, op.useCenter, op.paint);
         const AutoTexture holder(texture);
         if (CC_LIKELY(holder.texture)) {
-            renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.right,
+            renderPathTexture(renderer, state, op.unmappedBounds.left, op.unmappedBounds.top,
                     *texture, *(op.paint));
         }
     } else {
@@ -527,6 +531,12 @@ void BakedOpDispatcher::onOvalOp(BakedOpRenderer& renderer, const OvalOp& op, co
         SkPath path;
         SkRect rect = getBoundsOfFill(op);
         path.addOval(rect);
+
+        if (state.computedState.localProjectionPathMask != nullptr) {
+            // Mask the ripple path by the local space projection mask in local space.
+            // Note that this can create CCW paths.
+            Op(path, *state.computedState.localProjectionPathMask, kIntersect_SkPathOp, &path);
+        }
         renderConvexPath(renderer, state, path, *(op.paint));
     }
 }
index c147384..98493d7 100644 (file)
@@ -135,17 +135,7 @@ void BakedOpRenderer::endFrame(const Rect& repaintRect) {
         mRenderState.stencil().disable();
     }
 
-    mCaches.clearGarbage();
-    mCaches.pathCache.trim();
-    mCaches.tessellationCache.trim();
-
-#if DEBUG_MEMORY_USAGE
-    mCaches.dumpMemoryUsage();
-#else
-    if (Properties::debugLevel & kDebugMemory) {
-        mCaches.dumpMemoryUsage();
-    }
-#endif
+    // Note: we leave FBO 0 renderable here, for post-frame-content decoration
 }
 
 void BakedOpRenderer::setViewport(uint32_t width, uint32_t height) {
@@ -179,6 +169,38 @@ Texture* BakedOpRenderer::getTexture(const SkBitmap* bitmap) {
     return texture;
 }
 
+void BakedOpRenderer::drawRects(const float* rects, int count, const SkPaint* paint) {
+    std::vector<Vertex> vertices;
+    vertices.reserve(count);
+    Vertex* vertex = vertices.data();
+
+    for (int index = 0; index < count; index += 4) {
+        float l = rects[index + 0];
+        float t = rects[index + 1];
+        float r = rects[index + 2];
+        float b = rects[index + 3];
+
+        Vertex::set(vertex++, l, t);
+        Vertex::set(vertex++, r, t);
+        Vertex::set(vertex++, l, b);
+        Vertex::set(vertex++, r, b);
+    }
+
+    LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "decoration only supported for FBO 0");
+    // TODO: Currently assume full FBO damage, due to FrameInfoVisualizer::unionDirty.
+    // Should should scissor safely.
+    mRenderState.scissor().setEnabled(false);
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setRoundRectClipState(nullptr)
+            .setMeshIndexedQuads(vertices.data(), count / 4)
+            .setFillPaint(*paint, 1.0f)
+            .setTransform(Matrix4::identity(), TransformFlags::None)
+            .setModelViewIdentityEmptyBounds()
+            .build();
+    mRenderState.render(glop, mRenderTarget.orthoMatrix);
+}
+
 // clears and re-fills stencil with provided rendertarget space quads,
 // and then put stencil into test mode
 void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
index 55ea935..4b65255 100644 (file)
@@ -85,6 +85,16 @@ public:
     bool offscreenRenderTarget() { return mRenderTarget.offscreenBuffer != nullptr; }
     void dirtyRenderTarget(const Rect& dirtyRect);
     bool didDraw() const { return mHasDrawn; }
+
+    uint32_t getViewportWidth() const { return mRenderTarget.viewportWidth; }
+    uint32_t getViewportHeight() const { return mRenderTarget.viewportHeight; }
+
+    // simple draw methods, to be used for end frame decoration
+    void drawRect(float left, float top, float right, float bottom, const SkPaint* paint) {
+        float ltrb[4] = { left, top, right, bottom };
+        drawRects(ltrb, 4, paint);
+    }
+    void drawRects(const float* rects, int count, const SkPaint* paint);
 private:
     void setViewport(uint32_t width, uint32_t height);
     void clearColorBuffer(const Rect& clearRect);
index 682bd04..26653f7 100644 (file)
@@ -63,9 +63,22 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s
         clipState = nullptr;
         clippedBounds.setEmpty();
     } else {
-        // Not rejected! compute true clippedBounds and clipSideFlags
+        // Not rejected! compute true clippedBounds, clipSideFlags, and path mask
         clipSideFlags = computeClipSideFlags(clipRect, clippedBounds);
         clippedBounds.doIntersect(clipRect);
+
+        if (CC_UNLIKELY(snapshot.projectionPathMask)) {
+            // map projection path mask from render target space into op space,
+            // so intersection with op geometry is possible
+            Matrix4 inverseTransform;
+            inverseTransform.loadInverse(transform);
+            SkMatrix skInverseTransform;
+            inverseTransform.copyTo(skInverseTransform);
+
+            auto localMask = allocator.create<SkPath>();
+            snapshot.projectionPathMask->transform(skInverseTransform, localMask);
+            localProjectionPathMask = localMask;
+        }
     }
 }
 
@@ -73,13 +86,15 @@ ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& s
         : transform(*snapshot.transform)
         , clipState(snapshot.mutateClipArea().serializeClip(allocator))
         , clippedBounds(clipState->rect)
-        , clipSideFlags(OpClipSideFlags::Full) {}
+        , clipSideFlags(OpClipSideFlags::Full)
+        , localProjectionPathMask(nullptr) {}
 
 ResolvedRenderState::ResolvedRenderState(const ClipRect* clipRect, const Rect& dstRect)
         : transform(Matrix4::identity())
         , clipState(clipRect)
         , clippedBounds(dstRect)
-        , clipSideFlags(computeClipSideFlags(clipRect->rect, dstRect)) {
+        , clipSideFlags(computeClipSideFlags(clipRect->rect, dstRect))
+        , localProjectionPathMask(nullptr) {
     clippedBounds.doIntersect(clipRect->rect);
 }
 
index 4365ef8..ffe2901 100644 (file)
@@ -88,6 +88,7 @@ public:
     const ClipBase* clipState = nullptr;
     Rect clippedBounds;
     int clipSideFlags = 0;
+    const SkPath* localProjectionPathMask = nullptr;
 };
 
 /**
@@ -154,7 +155,6 @@ public:
     // simple state (straight pointer/value storage):
     const float alpha;
     const RoundRectClipState* roundRectClipState;
-    const ProjectionPathMask* projectionPathMask;
     const RecordedOp* op;
 
 private:
@@ -165,21 +165,18 @@ private:
             : computedState(allocator, snapshot, recordedOp, expandForStroke)
             , alpha(snapshot.alpha)
             , roundRectClipState(snapshot.roundRectClipState)
-            , projectionPathMask(snapshot.projectionPathMask)
             , op(&recordedOp) {}
 
     BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr)
             : computedState(allocator, snapshot)
             , alpha(snapshot.alpha)
             , roundRectClipState(snapshot.roundRectClipState)
-            , projectionPathMask(snapshot.projectionPathMask)
             , op(shadowOpPtr) {}
 
     BakedOpState(const ClipRect* clipRect, const Rect& dstRect, const RecordedOp& recordedOp)
             : computedState(clipRect, dstRect)
             , alpha(1.0f)
             , roundRectClipState(nullptr)
-            , projectionPathMask(nullptr)
             , op(&recordedOp) {}
 };
 
index e368537..afe9807 100644 (file)
@@ -375,15 +375,13 @@ const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
             serialization->rect.set(mClipRegion.getBounds());
             break;
         }
+        // TODO: this is only done for draw time, should eventually avoid for record time
+        serialization->rect.snapToPixelBoundaries();
         mLastSerialization = serialization;
     }
     return mLastSerialization;
 }
 
-inline static const Rect& getRect(const ClipBase* scb) {
-    return reinterpret_cast<const ClipRect*>(scb)->rect;
-}
-
 inline static const RectangleList& getRectList(const ClipBase* scb) {
     return reinterpret_cast<const ClipRectList*>(scb)->rectList;
 }
@@ -404,11 +402,17 @@ static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* s
     return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
 }
 
+static const ClipRect sEmptyClipRect(Rect(0, 0));
+
 const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
         const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
+
     // if no recordedClip passed, just serialize current state
     if (!recordedClip) return serializeClip(allocator);
 
+    // if either is empty, clip is empty
+    if (CC_UNLIKELY(recordedClip->rect.isEmpty())|| mClipRect.isEmpty()) return &sEmptyClipRect;
+
     if (!mLastResolutionResult
             || recordedClip != mLastResolutionClip
             || recordedClipTransform != mLastResolutionTransform) {
@@ -419,9 +423,10 @@ const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
                 && recordedClip->mode == ClipMode::Rectangle
                 && recordedClipTransform.rectToRect())) {
             // common case - result is a single rectangle
-            auto rectClip = allocator.create<ClipRect>(getRect(recordedClip));
+            auto rectClip = allocator.create<ClipRect>(recordedClip->rect);
             recordedClipTransform.mapRect(rectClip->rect);
             rectClip->rect.doIntersect(mClipRect);
+            rectClip->rect.snapToPixelBoundaries();
             mLastResolutionResult = rectClip;
         } else if (CC_UNLIKELY(mMode == ClipMode::Region
                 || recordedClip->mode == ClipMode::Region
@@ -432,11 +437,11 @@ const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
             case ClipMode::Rectangle:
                 if (CC_LIKELY(recordedClipTransform.rectToRect())) {
                     // simple transform, skip creating SkPath
-                    Rect resultClip(getRect(recordedClip));
+                    Rect resultClip(recordedClip->rect);
                     recordedClipTransform.mapRect(resultClip);
                     other.setRect(resultClip.toSkIRect());
                 } else {
-                    SkPath transformedRect = pathFromTransformedRectangle(getRect(recordedClip),
+                    SkPath transformedRect = pathFromTransformedRectangle(recordedClip->rect,
                             recordedClipTransform);
                     other.setPath(transformedRect, createViewportRegion());
                 }
@@ -468,6 +473,7 @@ const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
                 regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
                 break;
             }
+            // Don't need to snap, since region's in int bounds
             regionClip->rect.set(regionClip->region.getBounds());
             mLastResolutionResult = regionClip;
         } else {
@@ -478,7 +484,7 @@ const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
             }
 
             if (recordedClip->mode == ClipMode::Rectangle) {
-                rectList.intersectWith(getRect(recordedClip), recordedClipTransform);
+                rectList.intersectWith(recordedClip->rect, recordedClipTransform);
             } else {
                 const RectangleList& other = getRectList(recordedClip);
                 for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
@@ -489,6 +495,7 @@ const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
                 }
             }
             rectListClip->rect = rectList.calculateBounds();
+            rectListClip->rect.snapToPixelBoundaries();
             mLastResolutionResult = rectListClip;
         }
     }
@@ -499,7 +506,7 @@ void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
     if (!clip) return; // nothing to do
 
     if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
-        clipRectWithTransform(getRect(clip), &transform, SkRegion::kIntersect_Op);
+        clipRectWithTransform(clip->rect, &transform, SkRegion::kIntersect_Op);
     } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
         auto&& rectList = getRectList(clip);
         for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
index 04de98a..5642170 100644 (file)
@@ -389,34 +389,38 @@ void FrameBuilder::deferShadow(const RenderNodeOp& casterNodeOp) {
 }
 
 void FrameBuilder::deferProjectedChildren(const RenderNode& renderNode) {
-    const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
     int count = mCanvasState.save(SaveFlags::MatrixClip);
+    const SkPath* projectionReceiverOutline = renderNode.properties().getOutline().getPath();
 
-    // can't be null, since DL=null node rejection happens before deferNodePropsAndOps
-    const DisplayList& displayList = *(renderNode.getDisplayList());
+    SkPath transformedMaskPath; // on stack, since BakedOpState makes a deep copy
+    if (projectionReceiverOutline) {
+        // transform the mask for this projector into render target space
+        // TODO: consider combining both transforms by stashing transform instead of applying
+        SkMatrix skCurrentTransform;
+        mCanvasState.currentTransform()->copyTo(skCurrentTransform);
+        projectionReceiverOutline->transform(
+                skCurrentTransform,
+                &transformedMaskPath);
+        mCanvasState.setProjectionPathMask(mAllocator, &transformedMaskPath);
+    }
 
-    const RecordedOp* op = (displayList.getOps()[displayList.projectionReceiveIndex]);
-    const RenderNodeOp* backgroundOp = static_cast<const RenderNodeOp*>(op);
-    const RenderProperties& backgroundProps = backgroundOp->renderNode->properties();
+    for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) {
+        RenderNodeOp* childOp = renderNode.mProjectedNodes[i];
+        RenderNode& childNode = *childOp->renderNode;
 
-    // Transform renderer to match background we're projecting onto
-    // (by offsetting canvas by translationX/Y of background rendernode, since only those are set)
-    mCanvasState.translate(backgroundProps.getTranslationX(), backgroundProps.getTranslationY());
+        // Draw child if it has content, but ignore state in childOp - matrix already applied to
+        // transformFromCompositingAncestor, and record-time clip is ignored when projecting
+        if (!childNode.nothingToDraw()) {
+            int restoreTo = mCanvasState.save(SaveFlags::MatrixClip);
 
-    // If the projection receiver has an outline, we mask projected content to it
-    // (which we know, apriori, are all tessellated paths)
-    mCanvasState.setProjectionPathMask(mAllocator, projectionReceiverOutline);
+            // Apply transform between ancestor and projected descendant
+            mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor);
 
-    // draw projected nodes
-    for (size_t i = 0; i < renderNode.mProjectedNodes.size(); i++) {
-        RenderNodeOp* childOp = renderNode.mProjectedNodes[i];
+            deferNodePropsAndOps(childNode);
 
-        int restoreTo = mCanvasState.save(SaveFlags::Matrix);
-        mCanvasState.concatMatrix(childOp->transformFromCompositingAncestor);
-        deferRenderNodeOpImpl(*childOp);
-        mCanvasState.restoreToCount(restoreTo);
+            mCanvasState.restoreToCount(restoreTo);
+        }
     }
-
     mCanvasState.restoreToCount(count);
 }
 
@@ -513,10 +517,6 @@ void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
     BakedOpState* bakedState = tryBakeOpState(op);
     if (!bakedState) return; // quick rejected
 
-    currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
-
-    // TODO: Fix this ( b/26569206 )
-/*
     // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
     // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
     // MergingDrawBatch::canMergeWith()
@@ -531,7 +531,6 @@ void FrameBuilder::deferBitmapOp(const BitmapOp& op) {
     } else {
         currentLayer().deferUnmergeableOp(mAllocator, bakedState, OpBatchType::Bitmap);
     }
-*/
 }
 
 void FrameBuilder::deferBitmapMeshOp(const BitmapMeshOp& op) {
index b7dd3b7..adadd32 100644 (file)
  */
 #include "FrameInfoVisualizer.h"
 
+#if HWUI_NEW_OPS
+#include "BakedOpRenderer.h"
+#else
 #include "OpenGLRenderer.h"
+#endif
 #include "utils/Color.h"
 
 #include <cutils/compiler.h>
@@ -88,7 +92,7 @@ void FrameInfoVisualizer::unionDirty(SkRect* dirty) {
     }
 }
 
-void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) {
+void FrameInfoVisualizer::draw(ContentRenderer* renderer) {
     RETURN_IF_DISABLED();
 
     if (mShowDirtyRegions) {
@@ -96,7 +100,7 @@ void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) {
         if (mFlashToggle) {
             SkPaint paint;
             paint.setColor(0x7fff0000);
-            canvas->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
+            renderer->drawRect(mDirtyRegion.fLeft, mDirtyRegion.fTop,
                     mDirtyRegion.fRight, mDirtyRegion.fBottom, &paint);
         }
     }
@@ -111,9 +115,9 @@ void FrameInfoVisualizer::draw(OpenGLRenderer* canvas) {
         info.markSwapBuffers();
         info.markFrameCompleted();
 
-        initializeRects(canvas->getViewportHeight(), canvas->getViewportWidth());
-        drawGraph(canvas);
-        drawThreshold(canvas);
+        initializeRects(renderer->getViewportHeight(), renderer->getViewportWidth());
+        drawGraph(renderer);
+        drawThreshold(renderer);
     }
 }
 
@@ -194,27 +198,26 @@ void FrameInfoVisualizer::nextBarSegment(FrameInfoIndex start, FrameInfoIndex en
     }
 }
 
-void FrameInfoVisualizer::drawGraph(OpenGLRenderer* canvas) {
+void FrameInfoVisualizer::drawGraph(ContentRenderer* renderer) {
     SkPaint paint;
     for (size_t i = 0; i < Bar.size(); i++) {
         nextBarSegment(Bar[i].start, Bar[i].end);
         paint.setColor(Bar[i].color & BAR_FAST_MASK);
-        canvas->drawRects(mFastRects.get(), mNumFastRects * 4, &paint);
+        renderer->drawRects(mFastRects.get(), mNumFastRects * 4, &paint);
         paint.setColor(Bar[i].color & BAR_JANKY_MASK);
-        canvas->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint);
+        renderer->drawRects(mJankyRects.get(), mNumJankyRects * 4, &paint);
     }
 }
 
-void FrameInfoVisualizer::drawThreshold(OpenGLRenderer* canvas) {
+void FrameInfoVisualizer::drawThreshold(ContentRenderer* renderer) {
     SkPaint paint;
     paint.setColor(THRESHOLD_COLOR);
-    paint.setStrokeWidth(mThresholdStroke);
-
-    float pts[4];
-    pts[0] = 0.0f;
-    pts[1] = pts[3] = canvas->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
-    pts[2] = canvas->getViewportWidth();
-    canvas->drawLines(pts, 4, &paint);
+    float yLocation = renderer->getViewportHeight() - (FRAME_THRESHOLD * mVerticalUnit);
+    renderer->drawRect(0.0f,
+            yLocation - mThresholdStroke/2,
+            renderer->getViewportWidth(),
+            yLocation + mThresholdStroke/2,
+            &paint);
 }
 
 bool FrameInfoVisualizer::consumeProperties() {
index cf877c4..83adf19 100644 (file)
 namespace android {
 namespace uirenderer {
 
+#if HWUI_NEW_OPS
+class BakedOpRenderer;
+typedef BakedOpRenderer ContentRenderer;
+#else
 class OpenGLRenderer;
+typedef OpenGLRenderer ContentRenderer;
+#endif
 
 // TODO: This is a bit awkward as it needs to match the thing in CanvasContext
 // A better abstraction here would be nice but iterators are painful
@@ -46,7 +52,7 @@ public:
     void setDensity(float density);
 
     void unionDirty(SkRect* dirty);
-    void draw(OpenGLRenderer* canvas);
+    void draw(ContentRenderer* renderer);
 
     void dumpData(int fd);
 
@@ -56,8 +62,8 @@ private:
 
     void initializeRects(const int baseline, const int width);
     void nextBarSegment(FrameInfoIndex start, FrameInfoIndex end);
-    void drawGraph(OpenGLRenderer* canvas);
-    void drawThreshold(OpenGLRenderer* canvas);
+    void drawGraph(ContentRenderer* renderer);
+    void drawThreshold(ContentRenderer* renderer);
 
     inline float durationMS(size_t index, FrameInfoIndex start, FrameInfoIndex end) {
         float duration = mFrameSource[index].duration(start, end) * 0.000001f;
index bc39621..c5af279 100644 (file)
@@ -140,7 +140,10 @@ public:
         // Identical round rect clip state means both ops will clip in the same way, or not at all.
         // As the state objects are const, we can compare their pointers to determine mergeability
         if (lhs->roundRectClipState != rhs->roundRectClipState) return false;
-        if (lhs->projectionPathMask != rhs->projectionPathMask) return false;
+
+        // Local masks prevent merge, since they're potentially in different coordinate spaces
+        if (lhs->computedState.localProjectionPathMask
+                || rhs->computedState.localProjectionPathMask) return false;
 
         /* Clipping compatibility check
          *
index e04b9a2..5bce8ac 100644 (file)
@@ -353,7 +353,7 @@ void LayerRenderer::flushLayer(RenderState& renderState, Layer* layer) {
 
 bool LayerRenderer::copyLayer(RenderState& renderState, Layer* layer, SkBitmap* bitmap) {
     Caches& caches = Caches::getInstance();
-    if (layer
+    if (layer && layer->getRenderTarget() != GL_NONE
             && bitmap->width() <= caches.maxTextureSize
             && bitmap->height() <= caches.maxTextureSize) {
 
index 73ebd13..deab956 100644 (file)
@@ -438,7 +438,7 @@ void Matrix4::mapPoint(float& x, float& y) const {
 }
 
 void Matrix4::mapRect(Rect& r) const {
-    if (isIdentity()) return;
+    if (isIdentity() || r.isEmpty()) return;
 
     if (isSimple()) {
         MUL_ADD_STORE(r.left, data[kScaleX], data[kTranslateX]);
index b7a5923..7693fdc 100644 (file)
@@ -1148,7 +1148,9 @@ bool OpenGLRenderer::storeDisplayState(DeferredDisplayState& state, int stateDef
 
     // always store/restore, since these are just pointers
     state.mRoundRectClipState = currentSnapshot()->roundRectClipState;
+#if !HWUI_NEW_OPS
     state.mProjectionPathMask = currentSnapshot()->projectionPathMask;
+#endif
     return false;
 }
 
@@ -1156,7 +1158,9 @@ void OpenGLRenderer::restoreDisplayState(const DeferredDisplayState& state, bool
     setGlobalMatrix(state.mMatrix);
     writableSnapshot()->alpha = state.mAlpha;
     writableSnapshot()->roundRectClipState = state.mRoundRectClipState;
+#if !HWUI_NEW_OPS
     writableSnapshot()->projectionPathMask = state.mProjectionPathMask;
+#endif
 
     if (state.mClipValid && !skipClipRestore) {
         writableSnapshot()->setClip(state.mClip.left, state.mClip.top,
@@ -1833,6 +1837,7 @@ void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p
         path.addCircle(x, y, radius);
     }
 
+#if !HWUI_NEW_OPS
     if (CC_UNLIKELY(currentSnapshot()->projectionPathMask != nullptr)) {
         // mask ripples with projection mask
         SkPath maskPath = *(currentSnapshot()->projectionPathMask->projectionMask);
@@ -1852,6 +1857,7 @@ void OpenGLRenderer::drawCircle(float x, float y, float radius, const SkPaint* p
         // in local space. Note that this can create CCW paths.
         Op(path, maskPath, kIntersect_SkPathOp, &path);
     }
+#endif
     drawConvexPath(path, p);
 }
 
index 31de305..ddf0528 100644 (file)
 namespace android {
 namespace uirenderer {
 
+
+static Rect sUnreasonablyLargeBounds(-10000, -10000, 10000, 10000);
+
+static const Rect& getConservativeOpBounds(const ClipBase* clip) {
+    // if op is clipped, that rect can be used, but otherwise just use a conservatively large rect
+    return clip ? clip->rect : sUnreasonablyLargeBounds;
+}
+
 RecordingCanvas::RecordingCanvas(size_t width, size_t height)
         : mState(*this)
         , mResourceCache(ResourceCache::getInstance()) {
@@ -242,10 +250,8 @@ void RecordingCanvas::drawColor(int color, SkXfermode::Mode mode) {
 
 void RecordingCanvas::drawPaint(const SkPaint& paint) {
     const ClipBase* clip = getRecordedClip();
-    // if there's no current clip, draw a big rect and hope we cover the eventual clip bounds
-    Rect bounds = clip ? clip->rect : Rect(-10000, -10000, 10000, 10000);
     addOp(alloc().create_trivial<RectOp>(
-            bounds,
+            getConservativeOpBounds(clip),
             Matrix4::identity(),
             clip,
             refPaint(&paint)));
@@ -534,10 +540,11 @@ void RecordingCanvas::drawTextOnPath(const uint16_t* glyphs, int glyphCount, con
             float hOffset, float vOffset, const SkPaint& paint) {
     if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
     glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
+    auto clip = getRecordedClip();
     addOp(alloc().create_trivial<TextOnPathOp>(
-            mState.getLocalClipBounds(), // TODO: explicitly define bounds
+            getConservativeOpBounds(clip), // TODO: explicitly define bounds
             *(mState.currentSnapshot()->transform),
-            getRecordedClip(),
+            clip,
             refPaint(&paint), glyphs, glyphCount, refPath(&path), hOffset, vOffset));
 }
 
@@ -586,15 +593,23 @@ void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
 
 void RecordingCanvas::callDrawGLFunction(Functor* functor) {
     mDisplayList->functors.push_back(functor);
+    auto clip = getRecordedClip();
     addOp(alloc().create_trivial<FunctorOp>(
-            mState.getLocalClipBounds(), // TODO: explicitly define bounds
+            getConservativeOpBounds(clip), // TODO: explicitly define bounds
             *(mState.currentSnapshot()->transform),
-            getRecordedClip(),
+            clip,
             functor));
 }
 
 size_t RecordingCanvas::addOp(RecordedOp* op) {
-    // TODO: validate if "addDrawOp" quickrejection logic is useful before adding
+    // skip op with empty clip
+    if (op->localClip && op->localClip->rect.isEmpty()) {
+        // NOTE: this rejection happens after op construction/content ref-ing, so content ref'd
+        // and held by renderthread isn't affected by clip rejection.
+        // Could rewind alloc here if desired, but callers would have to not touch op afterwards.
+        return -1;
+    }
+
     int insertIndex = mDisplayList->ops.size();
     mDisplayList->ops.push_back(op);
     if (mDeferredBarrierType != DeferredBarrierType::None) {
index 27fea1f..cf5e69a 100644 (file)
@@ -146,6 +146,9 @@ void Snapshot::resetTransform(float x, float y, float z) {
 }
 
 void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const {
+#if HWUI_NEW_OPS
+    LOG_ALWAYS_FATAL("not supported - not needed by new ops");
+#else
     // build (reverse ordered) list of the stack of snapshots, terminated with a NULL
     Vector<const Snapshot*> snapshotList;
     snapshotList.push(nullptr);
@@ -171,6 +174,7 @@ void Snapshot::buildScreenSpaceTransform(Matrix4* outTransform) const {
             outTransform->multiply(*(current->transform));
         }
     }
+#endif
 }
 
 ///////////////////////////////////////////////////////////////////////////////
@@ -223,15 +227,19 @@ void Snapshot::setClippingRoundRect(LinearAllocator& allocator, const Rect& boun
 }
 
 void Snapshot::setProjectionPathMask(LinearAllocator& allocator, const SkPath* path) {
+#if HWUI_NEW_OPS
+    // TODO: remove allocator param for HWUI_NEW_OPS
+    projectionPathMask = path;
+#else
     if (path) {
         ProjectionPathMask* mask = new (allocator) ProjectionPathMask;
         mask->projectionMask = path;
         buildScreenSpaceTransform(&(mask->projectionMaskTransform));
-
         projectionPathMask = mask;
     } else {
         projectionPathMask = nullptr;
     }
+#endif
 }
 
 ///////////////////////////////////////////////////////////////////////////////
index b03643f..3a01d04 100644 (file)
@@ -63,6 +63,7 @@ public:
     float radius;
 };
 
+// TODO: remove for HWUI_NEW_OPS
 class ProjectionPathMask {
 public:
     static void* operator new(size_t size) = delete;
@@ -219,6 +220,7 @@ public:
      * Fills outTransform with the current, total transform to screen space,
      * across layer boundaries.
      */
+    // TODO: remove for HWUI_NEW_OPS
     void buildScreenSpaceTransform(Matrix4* outTransform) const;
 
     /**
@@ -294,9 +296,13 @@ public:
     const RoundRectClipState* roundRectClipState;
 
     /**
-     * Current projection masking path - used exclusively to mask tessellated circles.
+     * Current projection masking path - used exclusively to mask projected, tessellated circles.
      */
+#if HWUI_NEW_OPS
+    const SkPath* projectionPathMask;
+#else
     const ProjectionPathMask* projectionPathMask;
+#endif
 
     void dump() const;
 
index 249d83f..a496b49 100644 (file)
@@ -348,12 +348,26 @@ void CanvasContext::draw() {
     FrameBuilder frameBuilder(mLayerUpdateQueue, dirty, frame.width(), frame.height(),
             mRenderNodes, mLightGeometry, mContentDrawBounds, &Caches::getInstance());
     mLayerUpdateQueue.clear();
-    BakedOpRenderer renderer(Caches::getInstance(), mRenderThread.renderState(),
+    auto&& caches = Caches::getInstance();
+    BakedOpRenderer renderer(caches, mRenderThread.renderState(),
             mOpaque, mLightInfo);
-    // TODO: profiler().draw(mCanvas);
     frameBuilder.replayBakedOps<BakedOpDispatcher>(renderer);
+    profiler().draw(&renderer);
     bool drew = renderer.didDraw();
 
+    // post frame cleanup
+    caches.clearGarbage();
+    caches.pathCache.trim();
+    caches.tessellationCache.trim();
+
+#if DEBUG_MEMORY_USAGE
+    mCaches.dumpMemoryUsage();
+#else
+    if (CC_UNLIKELY(Properties::debugLevel & kDebugMemory)) {
+        caches.dumpMemoryUsage();
+    }
+#endif
+
 #else
     mCanvas->prepareDirty(frame.width(), frame.height(),
             dirty.fLeft, dirty.fTop, dirty.fRight, dirty.fBottom, mOpaque);
index 679569e..822d04f 100644 (file)
@@ -27,7 +27,7 @@
 namespace android {
 namespace uirenderer {
 
-static Rect kViewportBounds(0, 0, 2048, 2048);
+static Rect kViewportBounds(2048, 2048);
 
 static ClipArea createClipArea() {
     ClipArea area;
@@ -140,17 +140,15 @@ TEST(ClipArea, serializeClip) {
 
     // rect list
     Matrix4 rotate;
-    rotate.loadRotate(2.0f);
-    area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
+    rotate.loadRotate(5.0f);
+    area.clipRectWithTransform(Rect(50, 50, 150, 150), &rotate, SkRegion::kIntersect_Op);
     {
         auto serializedClip = area.serializeClip(allocator);
         ASSERT_NE(nullptr, serializedClip);
         ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
         auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
         EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
-        EXPECT_FALSE(clipRectList->rect.isEmpty());
-        EXPECT_FLOAT_EQ(199.87817f, clipRectList->rect.right)
-            << "Right side should be clipped by rotated rect";
+        EXPECT_EQ(Rect(37, 54, 145, 163), clipRectList->rect);
         EXPECT_EQ(serializedClip, area.serializeClip(allocator))
                 << "Requery of clip on unmodified ClipArea must return same pointer.";
     }
@@ -228,6 +226,7 @@ TEST(ClipArea, serializeIntersectedClip) {
 
         ClipRegion recordedClip;
         recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200)));
+        recordedClip.rect = Rect(200, 200);
 
         Matrix4 translate10x20;
         translate10x20.loadTranslate(10, 20, 0);
@@ -240,5 +239,28 @@ TEST(ClipArea, serializeIntersectedClip) {
     }
 }
 
+TEST(ClipArea, serializeIntersectedClip_snap) {
+    ClipArea area(createClipArea());
+    area.setClip(100.2, 100.4, 500.6, 500.8);
+    LinearAllocator allocator;
+
+    {
+        // no recorded clip case
+        auto resolvedClip = area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity());
+        EXPECT_EQ(Rect(100, 100, 501, 501), resolvedClip->rect);
+    }
+    {
+        // recorded clip case
+        ClipRect recordedClip(Rect(100.12, 100.74));
+        Matrix4 translateScale;
+        translateScale.loadTranslate(100, 100, 0);
+        translateScale.scale(2, 3, 1); // recorded clip will have non-int coords, even after transform
+        auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
+        ASSERT_NE(nullptr, resolvedClip);
+        EXPECT_EQ(ClipMode::Rectangle, resolvedClip->mode);
+        EXPECT_EQ(Rect(100, 100, 300, 402), resolvedClip->rect);
+    }
+}
+
 } // namespace uirenderer
 } // namespace android
index f86898f..4c56a22 100644 (file)
@@ -216,8 +216,7 @@ TEST(FrameBuilder, simpleBatching) {
             << "Expect number of ops = 2 * loop count";
 }
 
-// TODO: Disabled due to b/26793764
-TEST(FrameBuilder, DISABLED_clippedMerging) {
+TEST(FrameBuilder, clippedMerging) {
     class ClippedMergingTestRenderer : public TestRendererBase {
     public:
         void onMergedBitmapOps(const MergedBakedOpList& opList) override {
@@ -990,21 +989,26 @@ TEST(FrameBuilder, projectionReorder) {
                 EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
                 EXPECT_EQ(SK_ColorWHITE, op.paint->getColor());
                 expectedMatrix.loadIdentity();
+                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
                 break;
             case 1:
                 EXPECT_EQ(Rect(-10, -10, 60, 60), op.unmappedBounds);
                 EXPECT_EQ(SK_ColorDKGRAY, op.paint->getColor());
-                expectedMatrix.loadTranslate(50, 50, 0); // TODO: should scroll be respected here?
+                expectedMatrix.loadTranslate(50 - scrollX, 50 - scrollY, 0);
+                ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
+                EXPECT_EQ(Rect(-35, -30, 45, 50),
+                        Rect(state.computedState.localProjectionPathMask->getBounds()));
                 break;
             case 2:
                 EXPECT_EQ(Rect(100, 50), op.unmappedBounds);
                 EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
                 expectedMatrix.loadTranslate(-scrollX, 50 - scrollY, 0);
+                EXPECT_EQ(nullptr, state.computedState.localProjectionPathMask);
                 break;
             default:
                 ADD_FAILURE();
             }
-            EXPECT_MATRIX_APPROX_EQ(expectedMatrix, state.computedState.transform);
+            EXPECT_EQ(expectedMatrix, state.computedState.transform);
         }
     };
 
@@ -1045,6 +1049,9 @@ TEST(FrameBuilder, projectionReorder) {
     });
     auto parent = TestUtils::createNode(0, 0, 100, 100,
             [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
+        // Set a rect outline for the projecting ripple to be masked against.
+        properties.mutableOutline().setRoundRect(10, 10, 90, 90, 5, 1.0f);
+
         canvas.save(SaveFlags::MatrixClip);
         canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
         canvas.drawRenderNode(receiverBackground.get());
@@ -1059,6 +1066,145 @@ TEST(FrameBuilder, projectionReorder) {
     EXPECT_EQ(3, renderer.getIndex());
 }
 
+RENDERTHREAD_TEST(FrameBuilder, projectionHwLayer) {
+    static const int scrollX = 5;
+    static const int scrollY = 10;
+    class ProjectionHwLayerTestRenderer : public TestRendererBase {
+    public:
+        void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect) override {
+            EXPECT_EQ(0, mIndex++);
+        }
+        void onArcOp(const ArcOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
+        }
+        void endLayer() override {
+            EXPECT_EQ(2, mIndex++);
+        }
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(3, mIndex++);
+            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
+        }
+        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(4, mIndex++);
+            ASSERT_NE(nullptr, state.computedState.localProjectionPathMask);
+            Matrix4 expected;
+            expected.loadTranslate(100 - scrollX, 100 - scrollY, 0);
+            EXPECT_EQ(expected, state.computedState.transform);
+            EXPECT_EQ(Rect(-85, -80, 295, 300),
+                    Rect(state.computedState.localProjectionPathMask->getBounds()));
+        }
+        void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(5, mIndex++);
+            ASSERT_EQ(nullptr, state.computedState.localProjectionPathMask);
+        }
+    };
+    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
+            [](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.setProjectionReceiver(true);
+        // scroll doesn't apply to background, so undone via translationX/Y
+        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
+        properties.setTranslationX(scrollX);
+        properties.setTranslationY(scrollY);
+
+        canvas.drawRect(0, 0, 400, 400, SkPaint());
+    });
+    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.setProjectBackwards(true);
+        properties.setClipToBounds(false);
+        canvas.drawOval(100, 100, 300, 300, SkPaint()); // drawn mostly out of layer bounds
+    });
+    auto child = TestUtils::createNode(100, 100, 300, 300,
+            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.mutateLayerProperties().setType(LayerType::RenderLayer);
+        canvas.drawRenderNode(projectingRipple.get());
+        canvas.drawArc(0, 0, 200, 200, 0.0f, 280.0f, true, SkPaint());
+    });
+    auto parent = TestUtils::createNode(0, 0, 400, 400,
+            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
+        // Set a rect outline for the projecting ripple to be masked against.
+        properties.mutableOutline().setRoundRect(10, 10, 390, 390, 0, 1.0f);
+        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
+        canvas.drawRenderNode(receiverBackground.get());
+        canvas.drawRenderNode(child.get());
+    });
+
+    OffscreenBuffer** layerHandle = child->getLayerHandle();
+
+    // create RenderNode's layer here in same way prepareTree would, setting windowTransform
+    OffscreenBuffer layer(renderThread.renderState(), Caches::getInstance(), 200, 200);
+    Matrix4 windowTransform;
+    windowTransform.loadTranslate(100, 100, 0); // total transform of layer's origin
+    layer.setWindowTransform(windowTransform);
+    *layerHandle = &layer;
+
+    auto syncedList = TestUtils::createSyncedNodeList(parent);
+    LayerUpdateQueue layerUpdateQueue; // Note: enqueue damage post-sync, so bounds are valid
+    layerUpdateQueue.enqueueLayerWithDamage(child.get(), Rect(200, 200));
+    FrameBuilder frameBuilder(layerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+            syncedList, sLightGeometry, nullptr);
+    ProjectionHwLayerTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(6, renderer.getIndex());
+
+    // clean up layer pointer, so we can safely destruct RenderNode
+    *layerHandle = nullptr;
+}
+
+RENDERTHREAD_TEST(FrameBuilder, projectionChildScroll) {
+    static const int scrollX = 500000;
+    static const int scrollY = 0;
+    class ProjectionChildScrollTestRenderer : public TestRendererBase {
+    public:
+        void onRectOp(const RectOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(0, mIndex++);
+            EXPECT_TRUE(state.computedState.transform.isIdentity());
+        }
+        void onOvalOp(const OvalOp& op, const BakedOpState& state) override {
+            EXPECT_EQ(1, mIndex++);
+            ASSERT_NE(nullptr, state.computedState.clipState);
+            ASSERT_EQ(ClipMode::Rectangle, state.computedState.clipState->mode);
+            ASSERT_EQ(Rect(400, 400), state.computedState.clipState->rect);
+            EXPECT_TRUE(state.computedState.transform.isIdentity());
+        }
+    };
+    auto receiverBackground = TestUtils::createNode(0, 0, 400, 400,
+            [](RenderProperties& properties, RecordingCanvas& canvas) {
+        properties.setProjectionReceiver(true);
+        canvas.drawRect(0, 0, 400, 400, SkPaint());
+    });
+    auto projectingRipple = TestUtils::createNode(0, 0, 200, 200,
+            [](RenderProperties& properties, RecordingCanvas& canvas) {
+        // scroll doesn't apply to background, so undone via translationX/Y
+        // NOTE: translationX/Y only! no other transform properties may be set for a proj receiver!
+        properties.setTranslationX(scrollX);
+        properties.setTranslationY(scrollY);
+        properties.setProjectBackwards(true);
+        properties.setClipToBounds(false);
+        canvas.drawOval(0, 0, 200, 200, SkPaint());
+    });
+    auto child = TestUtils::createNode(0, 0, 400, 400,
+            [&projectingRipple](RenderProperties& properties, RecordingCanvas& canvas) {
+        // Record time clip will be ignored by projectee
+        canvas.clipRect(100, 100, 300, 300, SkRegion::kIntersect_Op);
+
+        canvas.translate(-scrollX, -scrollY); // Apply scroll (note: bg undoes this internally)
+        canvas.drawRenderNode(projectingRipple.get());
+    });
+    auto parent = TestUtils::createNode(0, 0, 400, 400,
+            [&receiverBackground, &child](RenderProperties& properties, RecordingCanvas& canvas) {
+        canvas.drawRenderNode(receiverBackground.get());
+        canvas.drawRenderNode(child.get());
+    });
+
+    FrameBuilder frameBuilder(sEmptyLayerUpdateQueue, SkRect::MakeWH(400, 400), 400, 400,
+            TestUtils::createSyncedNodeList(parent), sLightGeometry, nullptr);
+    ProjectionChildScrollTestRenderer renderer;
+    frameBuilder.replayBakedOps<TestDispatcher>(renderer);
+    EXPECT_EQ(2, renderer.getIndex());
+}
+
 // creates a 100x100 shadow casting node with provided translationZ
 static sp<RenderNode> createWhiteRectShadowCaster(float translationZ) {
     return TestUtils::createNode(0, 0, 100, 100,
diff --git a/libs/hwui/tests/unit/MatrixTests.cpp b/libs/hwui/tests/unit/MatrixTests.cpp
new file mode 100644 (file)
index 0000000..da22637
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <gtest/gtest.h>
+
+#include "Matrix.h"
+#include "Rect.h"
+
+using namespace android::uirenderer;
+
+TEST(Matrix, mapRect) {
+    // Skew, so we don't hit identity/translate/simple fast paths
+    Matrix4 matrix;
+    matrix.skew(0.1f, 0.1f);
+
+    // non-zero empty rect, so sorting x/y would make rect non-empty
+    Rect empty(100, 100, -100, -100);
+    ASSERT_TRUE(empty.isEmpty());
+    matrix.mapRect(empty);
+    EXPECT_TRUE(empty.isEmpty())
+        << "Empty rect should always remain empty, regardless of mapping.";
+}
index f988da3..d35b1f9 100644 (file)
@@ -58,6 +58,17 @@ TEST(RecordingCanvas, clipRect) {
             << "Clip should be serialized once";
 }
 
+TEST(RecordingCanvas, emptyClipRect) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
+        canvas.save(SaveFlags::MatrixClip);
+        canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
+        canvas.clipRect(100, 100, 200, 200, SkRegion::kIntersect_Op);
+        canvas.drawRect(0, 0, 50, 50, SkPaint()); // rejected at record time
+        canvas.restore();
+    });
+    ASSERT_EQ(0u, dl->getOps().size()) << "Must be zero ops. Rect should be rejected.";
+}
+
 TEST(RecordingCanvas, drawArc) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(200, 200, [](RecordingCanvas& canvas) {
         canvas.drawArc(0, 0, 200, 200, 0, 180, true, SkPaint());
@@ -431,9 +442,7 @@ TEST(RecordingCanvas, saveLayer_rotateClipped) {
             // since the same clip will be computed at draw time. If such a change is made, this
             // check could be done at record time by querying the clip, or the clip could be altered
             // slightly so that it is serialized.
-            EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136),
-                    (reinterpret_cast<const ClipRect*>(op.localClip))->rect);
-
+            EXPECT_EQ(Rect(59, 59, 341, 341), op.localClip->rect);
             EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
             expectedMatrix.loadIdentity();
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
index 3c8a78d..6a7801e 100644 (file)
@@ -26,26 +26,26 @@ import android.os.Parcelable;
 public final class GnssClock implements Parcelable {
     // The following enumerations must be in sync with the values declared in gps.h
 
-    private static final short HAS_NO_FLAGS = 0;
-    private static final short HAS_LEAP_SECOND = (1<<0);
-    private static final short HAS_TIME_UNCERTAINTY = (1<<1);
-    private static final short HAS_FULL_BIAS = (1<<2);
-    private static final short HAS_BIAS = (1<<3);
-    private static final short HAS_BIAS_UNCERTAINTY = (1<<4);
-    private static final short HAS_DRIFT = (1<<5);
-    private static final short HAS_DRIFT_UNCERTAINTY = (1<<6);
+    private static final int HAS_NO_FLAGS = 0;
+    private static final int HAS_LEAP_SECOND = (1<<0);
+    private static final int HAS_TIME_UNCERTAINTY = (1<<1);
+    private static final int HAS_FULL_BIAS = (1<<2);
+    private static final int HAS_BIAS = (1<<3);
+    private static final int HAS_BIAS_UNCERTAINTY = (1<<4);
+    private static final int HAS_DRIFT = (1<<5);
+    private static final int HAS_DRIFT_UNCERTAINTY = (1<<6);
 
     // End enumerations in sync with gps.h
 
-    private short mFlags;
-    private short mLeapSecond;
-    private long mTimeInNs;
-    private double mTimeUncertaintyInNs;
-    private long mFullBiasInNs;
-    private double mBiasInNs;
-    private double mBiasUncertaintyInNs;
-    private double mDriftInNsPerSec;
-    private double mDriftUncertaintyInNsPerSec;
+    private int mFlags;
+    private int mLeapSecond;
+    private long mTimeNanos;
+    private double mTimeUncertaintyNanos;
+    private long mFullBiasNanos;
+    private double mBiasNanos;
+    private double mBiasUncertaintyNanos;
+    private double mDriftNanosPerSecond;
+    private double mDriftUncertaintyNanosPerSecond;
     private int mHardwareClockDiscontinuityCount;
 
     GnssClock() {
@@ -58,13 +58,13 @@ public final class GnssClock implements Parcelable {
     public void set(GnssClock clock) {
         mFlags = clock.mFlags;
         mLeapSecond = clock.mLeapSecond;
-        mTimeInNs = clock.mTimeInNs;
-        mTimeUncertaintyInNs = clock.mTimeUncertaintyInNs;
-        mFullBiasInNs = clock.mFullBiasInNs;
-        mBiasInNs = clock.mBiasInNs;
-        mBiasUncertaintyInNs = clock.mBiasUncertaintyInNs;
-        mDriftInNsPerSec = clock.mDriftInNsPerSec;
-        mDriftUncertaintyInNsPerSec = clock.mDriftUncertaintyInNsPerSec;
+        mTimeNanos = clock.mTimeNanos;
+        mTimeUncertaintyNanos = clock.mTimeUncertaintyNanos;
+        mFullBiasNanos = clock.mFullBiasNanos;
+        mBiasNanos = clock.mBiasNanos;
+        mBiasUncertaintyNanos = clock.mBiasUncertaintyNanos;
+        mDriftNanosPerSecond = clock.mDriftNanosPerSecond;
+        mDriftUncertaintyNanosPerSecond = clock.mDriftUncertaintyNanosPerSecond;
         mHardwareClockDiscontinuityCount = clock.mHardwareClockDiscontinuityCount;
     }
 
@@ -89,14 +89,14 @@ public final class GnssClock implements Parcelable {
      *
      * The value is only available if {@link #hasLeapSecond()} is true.
      */
-    public short getLeapSecond() {
+    public int getLeapSecond() {
         return mLeapSecond;
     }
 
     /**
      * Sets the leap second associated with the clock's time.
      */
-    public void setLeapSecond(short leapSecond) {
+    public void setLeapSecond(int leapSecond) {
         setFlag(HAS_LEAP_SECOND);
         mLeapSecond = leapSecond;
     }
@@ -106,7 +106,7 @@ public final class GnssClock implements Parcelable {
      */
     public void resetLeapSecond() {
         resetFlag(HAS_LEAP_SECOND);
-        mLeapSecond = Short.MIN_VALUE;
+        mLeapSecond = Integer.MIN_VALUE;
     }
 
     /**
@@ -114,30 +114,30 @@ public final class GnssClock implements Parcelable {
      *
      * For 'local hardware clock' this value is expected to be monotonically increasing during the
      * reporting session. The real GPS time can be derived by compensating
-     * {@link #getFullBiasInNs()} (when it is available) from this value.
+     * {@link #getFullBiasNanos()} (when it is available) from this value.
      *
      * For 'GPS time' this value is expected to be the best estimation of current GPS time that GPS
-     * receiver can achieve. {@link #getTimeUncertaintyInNs()} should be available when GPS time is
+     * receiver can achieve. {@link #getTimeUncertaintyNanos()} should be available when GPS time is
      * specified.
      *
-     * Sub-nanosecond accuracy can be provided by means of {@link #getBiasInNs()}.
-     * The reported time includes {@link #getTimeUncertaintyInNs()}.
+     * Sub-nanosecond accuracy can be provided by means of {@link #getBiasNanos()}.
+     * The reported time includes {@link #getTimeUncertaintyNanos()}.
      */
-    public long getTimeInNs() {
-        return mTimeInNs;
+    public long getTimeNanos() {
+        return mTimeNanos;
     }
 
     /**
-     * Sets the GPS receiver internal clock in nanoseconds.
+     * Sets the GNSS receiver internal clock in nanoseconds.
      */
-    public void setTimeInNs(long timeInNs) {
-        mTimeInNs = timeInNs;
+    public void setTimeNanos(long timeNanos) {
+        mTimeNanos = timeNanos;
     }
 
     /**
-     * Returns true if {@link #getTimeUncertaintyInNs()} is available, false otherwise.
+     * Returns true if {@link #getTimeUncertaintyNanos()} is available, false otherwise.
      */
-    public boolean hasTimeUncertaintyInNs() {
+    public boolean hasTimeUncertaintyNanos() {
         return isFlagSet(HAS_TIME_UNCERTAINTY);
     }
 
@@ -145,189 +145,189 @@ public final class GnssClock implements Parcelable {
      * Gets the clock's time Uncertainty (1-Sigma) in nanoseconds.
      * The uncertainty is represented as an absolute (single sided) value.
      *
-     * The value is only available if {@link #hasTimeUncertaintyInNs()} is true.
+     * The value is only available if {@link #hasTimeUncertaintyNanos()} is true.
      */
-    public double getTimeUncertaintyInNs() {
-        return mTimeUncertaintyInNs;
+    public double getTimeUncertaintyNanos() {
+        return mTimeUncertaintyNanos;
     }
 
     /**
      * Sets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
      */
-    public void setTimeUncertaintyInNs(double timeUncertaintyInNs) {
+    public void setTimeUncertaintyNanos(double timeUncertaintyNanos) {
         setFlag(HAS_TIME_UNCERTAINTY);
-        mTimeUncertaintyInNs = timeUncertaintyInNs;
+        mTimeUncertaintyNanos = timeUncertaintyNanos;
     }
 
     /**
      * Resets the clock's Time Uncertainty (1-Sigma) in nanoseconds.
      */
-    public void resetTimeUncertaintyInNs() {
+    public void resetTimeUncertaintyNanos() {
         resetFlag(HAS_TIME_UNCERTAINTY);
-        mTimeUncertaintyInNs = Double.NaN;
+        mTimeUncertaintyNanos = Double.NaN;
     }
 
     /**
-     * Returns true if {@link #getFullBiasInNs()} is available, false otherwise.
+     * Returns true if {@link #getFullBiasNanos()} is available, false otherwise.
      */
-    public boolean hasFullBiasInNs() {
+    public boolean hasFullBiasNanos() {
         return isFlagSet(HAS_FULL_BIAS);
     }
 
     /**
-     * Gets the difference between hardware clock ({@link #getTimeInNs()}) inside GPS receiver and
+     * Gets the difference between hardware clock ({@link #getTimeNanos()}) inside GPS receiver and
      * the true GPS time since 0000Z, January 6, 1980, in nanoseconds.
      *
      * This value is available if the receiver has estimated GPS time. If the computed time is for a
      * non-GPS constellation, the time offset of that constellation to GPS has to be applied to fill
-     * this value. The value contains the 'bias uncertainty' {@link #getBiasUncertaintyInNs()} in
+     * this value. The value contains the 'bias uncertainty' {@link #getBiasUncertaintyNanos()} in
      * it, and it should be used for quality check. The value is only available if
-     * {@link #hasFullBiasInNs()} is true.
+     * {@link #hasFullBiasNanos()} is true.
      *
      * The sign of the value is defined by the following equation:
      *      local estimate of GPS time = time_ns + (full_bias_ns + bias_ns)
      */
-    public long getFullBiasInNs() {
-        return mFullBiasInNs;
+    public long getFullBiasNanos() {
+        return mFullBiasNanos;
     }
 
     /**
      * Sets the full bias in nanoseconds.
      */
-    public void setFullBiasInNs(long value) {
+    public void setFullBiasNanos(long value) {
         setFlag(HAS_FULL_BIAS);
-        mFullBiasInNs = value;
+        mFullBiasNanos = value;
     }
 
     /**
      * Resets the full bias in nanoseconds.
      */
-    public void resetFullBiasInNs() {
+    public void resetFullBiasNanos() {
         resetFlag(HAS_FULL_BIAS);
-        mFullBiasInNs = Long.MIN_VALUE;
+        mFullBiasNanos = Long.MIN_VALUE;
     }
 
     /**
-     * Returns true if {@link #getBiasInNs()} is available, false otherwise.
+     * Returns true if {@link #getBiasNanos()} is available, false otherwise.
      */
-    public boolean hasBiasInNs() {
+    public boolean hasBiasNanos() {
         return isFlagSet(HAS_BIAS);
     }
 
     /**
      * Gets the clock's sub-nanosecond bias.
-     * The reported bias includes {@link #getBiasUncertaintyInNs()}.
+     * The reported bias includes {@link #getBiasUncertaintyNanos()}.
      *
-     * The value is only available if {@link #hasBiasInNs()} is true.
+     * The value is only available if {@link #hasBiasNanos()} is true.
      */
-    public double getBiasInNs() {
-        return mBiasInNs;
+    public double getBiasNanos() {
+        return mBiasNanos;
     }
 
     /**
      * Sets the sub-nanosecond bias.
      */
-    public void setBiasInNs(double biasInNs) {
+    public void setBiasNanos(double biasNanos) {
         setFlag(HAS_BIAS);
-        mBiasInNs = biasInNs;
+        mBiasNanos = biasNanos;
     }
 
     /**
      * Resets the clock's Bias in nanoseconds.
      */
-    public void resetBiasInNs() {
+    public void resetBiasNanos() {
         resetFlag(HAS_BIAS);
-        mBiasInNs = Double.NaN;
+        mBiasNanos = Double.NaN;
     }
 
     /**
-     * Returns true if {@link #getBiasUncertaintyInNs()} is available, false otherwise.
+     * Returns true if {@link #getBiasUncertaintyNanos()} is available, false otherwise.
      */
-    public boolean hasBiasUncertaintyInNs() {
+    public boolean hasBiasUncertaintyNanos() {
         return isFlagSet(HAS_BIAS_UNCERTAINTY);
     }
 
     /**
      * Gets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
      *
-     * The value is only available if {@link #hasBiasUncertaintyInNs()} is true.
+     * The value is only available if {@link #hasBiasUncertaintyNanos()} is true.
      */
-    public double getBiasUncertaintyInNs() {
-        return mBiasUncertaintyInNs;
+    public double getBiasUncertaintyNanos() {
+        return mBiasUncertaintyNanos;
     }
 
     /**
      * Sets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
      */
-    public void setBiasUncertaintyInNs(double biasUncertaintyInNs) {
+    public void setBiasUncertaintyNanos(double biasUncertaintyNanos) {
         setFlag(HAS_BIAS_UNCERTAINTY);
-        mBiasUncertaintyInNs = biasUncertaintyInNs;
+        mBiasUncertaintyNanos = biasUncertaintyNanos;
     }
 
     /**
      * Resets the clock's Bias Uncertainty (1-Sigma) in nanoseconds.
      */
-    public void resetBiasUncertaintyInNs() {
+    public void resetBiasUncertaintyNanos() {
         resetFlag(HAS_BIAS_UNCERTAINTY);
-        mBiasUncertaintyInNs = Double.NaN;
+        mBiasUncertaintyNanos = Double.NaN;
     }
 
     /**
-     * Returns true if {@link #getDriftInNsPerSec()} is available, false otherwise.
+     * Returns true if {@link #getDriftNanosPerSecond()} is available, false otherwise.
      */
-    public boolean hasDriftInNsPerSec() {
+    public boolean hasDriftNanosPerSecond() {
         return isFlagSet(HAS_DRIFT);
     }
 
     /**
      * Gets the clock's Drift in nanoseconds per second.
      * A positive value indicates that the frequency is higher than the nominal frequency.
-     * The reported drift includes {@link #getDriftUncertaintyInNsPerSec()}.
+     * The reported drift includes {@link #getDriftUncertaintyNanosPerSecond()}.
      *
-     * The value is only available if {@link #hasDriftInNsPerSec()} is true.
+     * The value is only available if {@link #hasDriftNanosPerSecond()} is true.
      */
-    public double getDriftInNsPerSec() {
-        return mDriftInNsPerSec;
+    public double getDriftNanosPerSecond() {
+        return mDriftNanosPerSecond;
     }
 
     /**
      * Sets the clock's Drift in nanoseconds per second.
      */
-    public void setDriftInNsPerSec(double driftInNsPerSec) {
+    public void setDriftNanosPerSecond(double driftNanosPerSecond) {
         setFlag(HAS_DRIFT);
-        mDriftInNsPerSec = driftInNsPerSec;
+        mDriftNanosPerSecond = driftNanosPerSecond;
     }
 
     /**
      * Resets the clock's Drift in nanoseconds per second.
      */
-    public void resetDriftInNsPerSec() {
+    public void resetDriftNanosPerSecond() {
         resetFlag(HAS_DRIFT);
-        mDriftInNsPerSec = Double.NaN;
+        mDriftNanosPerSecond = Double.NaN;
     }
 
     /**
-     * Returns true if {@link #getDriftUncertaintyInNsPerSec()} is available, false otherwise.
+     * Returns true if {@link #getDriftUncertaintyNanosPerSecond()} is available, false otherwise.
      */
-    public boolean hasDriftUncertaintyInNsPerSec() {
+    public boolean hasDriftUncertaintyNanosPerSecond() {
         return isFlagSet(HAS_DRIFT_UNCERTAINTY);
     }
 
     /**
      * Gets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
      *
-     * The value is only available if {@link #hasDriftUncertaintyInNsPerSec()} is true.
+     * The value is only available if {@link #hasDriftUncertaintyNanosPerSecond()} is true.
      */
-    public double getDriftUncertaintyInNsPerSec() {
-        return mDriftUncertaintyInNsPerSec;
+    public double getDriftUncertaintyNanosPerSecond() {
+        return mDriftUncertaintyNanosPerSecond;
     }
 
     /**
      * Sets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
      */
-    public void setDriftUncertaintyInNsPerSec(double driftUncertaintyInNsPerSec) {
+    public void setDriftUncertaintyNanosPerSecond(double driftUncertaintyNanosPerSecond) {
         setFlag(HAS_DRIFT_UNCERTAINTY);
-        mDriftUncertaintyInNsPerSec = driftUncertaintyInNsPerSec;
+        mDriftUncertaintyNanosPerSecond = driftUncertaintyNanosPerSecond;
     }
 
     /**
@@ -347,9 +347,9 @@ public final class GnssClock implements Parcelable {
     /**
      * Resets the clock's Drift Uncertainty (1-Sigma) in nanoseconds per second.
      */
-    public void resetDriftUncertaintyInNsPerSec() {
+    public void resetDriftUncertaintyNanosPerSecond() {
         resetFlag(HAS_DRIFT_UNCERTAINTY);
-        mDriftUncertaintyInNsPerSec = Double.NaN;
+        mDriftUncertaintyNanosPerSecond = Double.NaN;
     }
 
     public static final Creator<GnssClock> CREATOR = new Creator<GnssClock>() {
@@ -357,15 +357,15 @@ public final class GnssClock implements Parcelable {
         public GnssClock createFromParcel(Parcel parcel) {
             GnssClock gpsClock = new GnssClock();
 
-            gpsClock.mFlags = (short) parcel.readInt();
-            gpsClock.mLeapSecond = (short) parcel.readInt();
-            gpsClock.mTimeInNs = parcel.readLong();
-            gpsClock.mTimeUncertaintyInNs = parcel.readDouble();
-            gpsClock.mFullBiasInNs = parcel.readLong();
-            gpsClock.mBiasInNs = parcel.readDouble();
-            gpsClock.mBiasUncertaintyInNs = parcel.readDouble();
-            gpsClock.mDriftInNsPerSec = parcel.readDouble();
-            gpsClock.mDriftUncertaintyInNsPerSec = parcel.readDouble();
+            gpsClock.mFlags = parcel.readInt();
+            gpsClock.mLeapSecond = parcel.readInt();
+            gpsClock.mTimeNanos = parcel.readLong();
+            gpsClock.mTimeUncertaintyNanos = parcel.readDouble();
+            gpsClock.mFullBiasNanos = parcel.readLong();
+            gpsClock.mBiasNanos = parcel.readDouble();
+            gpsClock.mBiasUncertaintyNanos = parcel.readDouble();
+            gpsClock.mDriftNanosPerSecond = parcel.readDouble();
+            gpsClock.mDriftUncertaintyNanosPerSecond = parcel.readDouble();
             gpsClock.mHardwareClockDiscontinuityCount = parcel.readInt();
 
             return gpsClock;
@@ -381,13 +381,13 @@ public final class GnssClock implements Parcelable {
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mFlags);
         parcel.writeInt(mLeapSecond);
-        parcel.writeLong(mTimeInNs);
-        parcel.writeDouble(mTimeUncertaintyInNs);
-        parcel.writeLong(mFullBiasInNs);
-        parcel.writeDouble(mBiasInNs);
-        parcel.writeDouble(mBiasUncertaintyInNs);
-        parcel.writeDouble(mDriftInNsPerSec);
-        parcel.writeDouble(mDriftUncertaintyInNsPerSec);
+        parcel.writeLong(mTimeNanos);
+        parcel.writeDouble(mTimeUncertaintyNanos);
+        parcel.writeLong(mFullBiasNanos);
+        parcel.writeDouble(mBiasNanos);
+        parcel.writeDouble(mBiasUncertaintyNanos);
+        parcel.writeDouble(mDriftNanosPerSecond);
+        parcel.writeDouble(mDriftUncertaintyNanosPerSecond);
         parcel.writeInt(mHardwareClockDiscontinuityCount);
     }
 
@@ -406,29 +406,29 @@ public final class GnssClock implements Parcelable {
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "TimeInNs",
-                mTimeInNs,
-                "TimeUncertaintyInNs",
-                hasTimeUncertaintyInNs() ? mTimeUncertaintyInNs : null));
+                "TimeNanos",
+                mTimeNanos,
+                "TimeUncertaintyNanos",
+                hasTimeUncertaintyNanos() ? mTimeUncertaintyNanos : null));
 
         builder.append(String.format(
                 format,
-                "FullBiasInNs",
-                hasFullBiasInNs() ? mFullBiasInNs : null));
+                "FullBiasNanos",
+                hasFullBiasNanos() ? mFullBiasNanos : null));
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "BiasInNs",
-                hasBiasInNs() ? mBiasInNs : null,
-                "BiasUncertaintyInNs",
-                hasBiasUncertaintyInNs() ? mBiasUncertaintyInNs : null));
+                "BiasNanos",
+                hasBiasNanos() ? mBiasNanos : null,
+                "BiasUncertaintyNanos",
+                hasBiasUncertaintyNanos() ? mBiasUncertaintyNanos : null));
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "DriftInNsPerSec",
-                hasDriftInNsPerSec() ? mDriftInNsPerSec : null,
-                "DriftUncertaintyInNsPerSec",
-                hasDriftUncertaintyInNsPerSec() ? mDriftUncertaintyInNsPerSec : null));
+                "DriftNanosPerSecond",
+                hasDriftNanosPerSecond() ? mDriftNanosPerSecond : null,
+                "DriftUncertaintyNanosPerSecond",
+                hasDriftUncertaintyNanosPerSecond() ? mDriftUncertaintyNanosPerSecond : null));
 
         return builder.toString();
     }
@@ -436,25 +436,25 @@ public final class GnssClock implements Parcelable {
     private void initialize() {
         mFlags = HAS_NO_FLAGS;
         resetLeapSecond();
-        setTimeInNs(Long.MIN_VALUE);
-        resetTimeUncertaintyInNs();
-        resetFullBiasInNs();
-        resetBiasInNs();
-        resetBiasUncertaintyInNs();
-        resetDriftInNsPerSec();
-        resetDriftUncertaintyInNsPerSec();
+        setTimeNanos(Long.MIN_VALUE);
+        resetTimeUncertaintyNanos();
+        resetFullBiasNanos();
+        resetBiasNanos();
+        resetBiasUncertaintyNanos();
+        resetDriftNanosPerSecond();
+        resetDriftUncertaintyNanosPerSecond();
         setHardwareClockDiscontinuityCount(Integer.MIN_VALUE);
     }
 
-    private void setFlag(short flag) {
+    private void setFlag(int flag) {
         mFlags |= flag;
     }
 
-    private void resetFlag(short flag) {
+    private void resetFlag(int flag) {
         mFlags &= ~flag;
     }
 
-    private boolean isFlagSet(short flag) {
+    private boolean isFlagSet(int flag) {
         return (mFlags & flag) == flag;
     }
 }
index abdc13c..367c52f 100644 (file)
@@ -28,82 +28,35 @@ import java.lang.annotation.RetentionPolicy;
  */
 public final class GnssMeasurement implements Parcelable {
     private int mFlags;
-    private short mSvid;
-    private byte mConstellationType;
-    private double mTimeOffsetInNs;
-    private short mState;
-    private long mReceivedSvTimeInNs;
-    private long mReceivedSvTimeUncertaintyInNs;
-    private double mCn0InDbHz;
-    private double mPseudorangeRateInMetersPerSec;
-    private double mPseudorangeRateUncertaintyInMetersPerSec;
-    private short mAccumulatedDeltaRangeState;
-    private double mAccumulatedDeltaRangeInMeters;
-    private double mAccumulatedDeltaRangeUncertaintyInMeters;
-    private double mPseudorangeInMeters;
-    private double mPseudorangeUncertaintyInMeters;
-    private double mCodePhaseInChips;
-    private double mCodePhaseUncertaintyInChips;
-    private float mCarrierFrequencyInHz;
+    private int mSvid;
+    private int mConstellationType;
+    private double mTimeOffsetNanos;
+    private int mState;
+    private long mReceivedSvTimeNanos;
+    private long mReceivedSvTimeUncertaintyNanos;
+    private double mCn0DbHz;
+    private double mPseudorangeRateMetersPerSecond;
+    private double mPseudorangeRateUncertaintyMetersPerSecond;
+    private int mAccumulatedDeltaRangeState;
+    private double mAccumulatedDeltaRangeMeters;
+    private double mAccumulatedDeltaRangeUncertaintyMeters;
+    private float mCarrierFrequencyHz;
     private long mCarrierCycles;
     private double mCarrierPhase;
     private double mCarrierPhaseUncertainty;
-    private byte mLossOfLock;
-    private int mBitNumber;
-    private short mTimeFromLastBitInMs;
-    private double mDopplerShiftInHz;
-    private double mDopplerShiftUncertaintyInHz;
-    private byte mMultipathIndicator;
+    private int mMultipathIndicator;
     private double mSnrInDb;
-    private double mElevationInDeg;
-    private double mElevationUncertaintyInDeg;
-    private double mAzimuthInDeg;
-    private double mAzimuthUncertaintyInDeg;
-    private boolean mUsedInFix;
 
     // The following enumerations must be in sync with the values declared in gps.h
 
     private static final int HAS_NO_FLAGS = 0;
     private static final int HAS_SNR = (1<<0);
-    private static final int HAS_ELEVATION = (1<<1);
-    private static final int HAS_ELEVATION_UNCERTAINTY = (1<<2);
-    private static final int HAS_AZIMUTH = (1<<3);
-    private static final int HAS_AZIMUTH_UNCERTAINTY = (1<<4);
-    private static final int HAS_PSEUDORANGE = (1<<5);
-    private static final int HAS_PSEUDORANGE_UNCERTAINTY = (1<<6);
-    private static final int HAS_CODE_PHASE = (1<<7);
-    private static final int HAS_CODE_PHASE_UNCERTAINTY = (1<<8);
     private static final int HAS_CARRIER_FREQUENCY = (1<<9);
     private static final int HAS_CARRIER_CYCLES = (1<<10);
     private static final int HAS_CARRIER_PHASE = (1<<11);
     private static final int HAS_CARRIER_PHASE_UNCERTAINTY = (1<<12);
-    private static final int HAS_BIT_NUMBER = (1<<13);
-    private static final int HAS_TIME_FROM_LAST_BIT = (1<<14);
-    private static final int HAS_DOPPLER_SHIFT = (1<<15);
-    private static final int HAS_DOPPLER_SHIFT_UNCERTAINTY = (1<<16);
-    // private static final int HAS_USED_IN_FIX = (1<<17);
     private static final int HAS_UNCORRECTED_PSEUDORANGE_RATE = (1<<18);
 
-    /** The status of 'loss of lock'. */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({LOSS_OF_LOCK_UNKNOWN, LOSS_OF_LOCK_OK, LOSS_OF_LOCK_CYCLE_SLIP})
-    public @interface LossOfLockStatus {}
-
-    /**
-     * The indicator is not available or it is unknown.
-     */
-    public static final byte LOSS_OF_LOCK_UNKNOWN = 0;
-
-    /**
-     * The measurement does not present any indication of 'loss of lock'.
-     */
-    public static final byte LOSS_OF_LOCK_OK = 1;
-
-    /**
-     * 'Loss of lock' detected between the previous and current observation: cycle slip possible.
-     */
-    public static final byte LOSS_OF_LOCK_CYCLE_SLIP = 2;
-
     /** The status of multipath. */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({MULTIPATH_INDICATOR_UNKNOWN, MULTIPATH_INDICATOR_DETECTED,
@@ -113,78 +66,78 @@ public final class GnssMeasurement implements Parcelable {
     /**
      * The indicator is not available or it is unknown.
      */
-    public static final byte MULTIPATH_INDICATOR_UNKNOWN = 0;
+    public static final int MULTIPATH_INDICATOR_UNKNOWN = 0;
 
     /**
      * The measurement has been indicated to use multi-path.
      */
-    public static final byte MULTIPATH_INDICATOR_DETECTED = 1;
+    public static final int MULTIPATH_INDICATOR_DETECTED = 1;
 
     /**
      * The measurement has been indicated not tu use multi-path.
      */
-    public static final byte MULTIPATH_INDICATOR_NOT_USED = 2;
+    public static final int MULTIPATH_INDICATOR_NOT_USED = 2;
 
     /**
      * The state of GNSS receiver the measurement is invalid or unknown.
      */
-    public static final short STATE_UNKNOWN = 0;
+    public static final int STATE_UNKNOWN = 0;
 
     /**
      * The state of the GNSS receiver is ranging code lock.
      */
-    public static final short STATE_CODE_LOCK = (1<<0);
+    public static final int STATE_CODE_LOCK = (1<<0);
 
     /**
      * The state of the GNSS receiver is in bit sync.
      */
-    public static final short STATE_BIT_SYNC = (1<<1);
+    public static final int STATE_BIT_SYNC = (1<<1);
 
     /**
      *The state of the GNSS receiver is in sub-frame sync.
      */
-    public static final short STATE_SUBFRAME_SYNC = (1<<2);
+    public static final int STATE_SUBFRAME_SYNC = (1<<2);
 
     /**
      * The state of the GNSS receiver has TOW decoded.
      */
-    public static final short STATE_TOW_DECODED = (1<<3);
+    public static final int STATE_TOW_DECODED = (1<<3);
 
     /**
      * The state of the GNSS receiver contains millisecond ambiguity.
      */
-    public static final short STATE_MSEC_AMBIGUOUS = (1<<4);
+    public static final int STATE_MSEC_AMBIGUOUS = (1<<4);
 
     /**
      * All the GNSS receiver state flags.
      */
-    private static final short STATE_ALL = STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC
+    private static final int STATE_ALL = STATE_CODE_LOCK | STATE_BIT_SYNC | STATE_SUBFRAME_SYNC
             | STATE_TOW_DECODED | STATE_MSEC_AMBIGUOUS;
 
     /**
      * The state of the 'Accumulated Delta Range' is invalid or unknown.
      */
-    public static final short ADR_STATE_UNKNOWN = 0;
+    public static final int ADR_STATE_UNKNOWN = 0;
 
     /**
      * The state of the 'Accumulated Delta Range' is valid.
      */
-    public static final short ADR_STATE_VALID = (1<<0);
+    public static final int ADR_STATE_VALID = (1<<0);
 
     /**
      * The state of the 'Accumulated Delta Range' has detected a reset.
      */
-    public static final short ADR_STATE_RESET = (1<<1);
+    public static final int ADR_STATE_RESET = (1<<1);
 
     /**
      * The state of the 'Accumulated Delta Range' has a cycle slip detected.
      */
-    public static final short ADR_STATE_CYCLE_SLIP = (1<<2);
+    public static final int ADR_STATE_CYCLE_SLIP = (1<<2);
 
     /**
      * All the 'Accumulated Delta Range' flags.
      */
-    private static final short ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP;
+    private static final int ADR_ALL = ADR_STATE_VALID | ADR_STATE_RESET | ADR_STATE_CYCLE_SLIP;
 
     // End enumerations in sync with gps.h
 
@@ -199,38 +152,24 @@ public final class GnssMeasurement implements Parcelable {
         mFlags = measurement.mFlags;
         mSvid = measurement.mSvid;
         mConstellationType = measurement.mConstellationType;
-        mTimeOffsetInNs = measurement.mTimeOffsetInNs;
+        mTimeOffsetNanos = measurement.mTimeOffsetNanos;
         mState = measurement.mState;
-        mReceivedSvTimeInNs = measurement.mReceivedSvTimeInNs;
-        mReceivedSvTimeUncertaintyInNs = measurement.mReceivedSvTimeUncertaintyInNs;
-        mCn0InDbHz = measurement.mCn0InDbHz;
-        mPseudorangeRateInMetersPerSec = measurement.mPseudorangeRateInMetersPerSec;
-        mPseudorangeRateUncertaintyInMetersPerSec =
-                measurement.mPseudorangeRateUncertaintyInMetersPerSec;
+        mReceivedSvTimeNanos = measurement.mReceivedSvTimeNanos;
+        mReceivedSvTimeUncertaintyNanos = measurement.mReceivedSvTimeUncertaintyNanos;
+        mCn0DbHz = measurement.mCn0DbHz;
+        mPseudorangeRateMetersPerSecond = measurement.mPseudorangeRateMetersPerSecond;
+        mPseudorangeRateUncertaintyMetersPerSecond =
+                measurement.mPseudorangeRateUncertaintyMetersPerSecond;
         mAccumulatedDeltaRangeState = measurement.mAccumulatedDeltaRangeState;
-        mAccumulatedDeltaRangeInMeters = measurement.mAccumulatedDeltaRangeInMeters;
-        mAccumulatedDeltaRangeUncertaintyInMeters =
-                measurement.mAccumulatedDeltaRangeUncertaintyInMeters;
-        mPseudorangeInMeters = measurement.mPseudorangeInMeters;
-        mPseudorangeUncertaintyInMeters = measurement.mPseudorangeUncertaintyInMeters;
-        mCodePhaseInChips = measurement.mCodePhaseInChips;
-        mCodePhaseUncertaintyInChips = measurement.mCodePhaseUncertaintyInChips;
-        mCarrierFrequencyInHz = measurement.mCarrierFrequencyInHz;
+        mAccumulatedDeltaRangeMeters = measurement.mAccumulatedDeltaRangeMeters;
+        mAccumulatedDeltaRangeUncertaintyMeters =
+                measurement.mAccumulatedDeltaRangeUncertaintyMeters;
+        mCarrierFrequencyHz = measurement.mCarrierFrequencyHz;
         mCarrierCycles = measurement.mCarrierCycles;
         mCarrierPhase = measurement.mCarrierPhase;
         mCarrierPhaseUncertainty = measurement.mCarrierPhaseUncertainty;
-        mLossOfLock = measurement.mLossOfLock;
-        mBitNumber = measurement.mBitNumber;
-        mTimeFromLastBitInMs = measurement.mTimeFromLastBitInMs;
-        mDopplerShiftInHz = measurement.mDopplerShiftInHz;
-        mDopplerShiftUncertaintyInHz = measurement.mDopplerShiftUncertaintyInHz;
         mMultipathIndicator = measurement.mMultipathIndicator;
         mSnrInDb = measurement.mSnrInDb;
-        mElevationInDeg = measurement.mElevationInDeg;
-        mElevationUncertaintyInDeg = measurement.mElevationUncertaintyInDeg;
-        mAzimuthInDeg = measurement.mAzimuthInDeg;
-        mAzimuthUncertaintyInDeg = measurement.mAzimuthUncertaintyInDeg;
-        mUsedInFix = measurement.mUsedInFix;
     }
 
     /**
@@ -244,14 +183,14 @@ public final class GnssMeasurement implements Parcelable {
      * Gets the Pseudo-random number (PRN).
      * Range: [1, 32]
      */
-    public short getSvid() {
+    public int getSvid() {
         return mSvid;
     }
 
     /**
      * Sets the Pseud-random number (PRN).
      */
-    public void setSvid(short value) {
+    public void setSvid(int value) {
         mSvid = value;
     }
 
@@ -259,14 +198,14 @@ public final class GnssMeasurement implements Parcelable {
      * Getst the constellation type.
      */
     @GnssStatus.ConstellationType
-    public byte getConstellationType() {
+    public int getConstellationType() {
         return mConstellationType;
     }
 
     /**
      * Sets the constellation type.
      */
-    public void setConstellationType(@GnssStatus.ConstellationType byte value) {
+    public void setConstellationType(@GnssStatus.ConstellationType int value) {
         mConstellationType = value;
     }
 
@@ -274,7 +213,7 @@ public final class GnssMeasurement implements Parcelable {
      * Gets the time offset at which the measurement was taken in nanoseconds.
      *
      * The reference receiver's time from which this is offset is specified by
-     * {@link GnssClock#getTimeInNs()}.
+     * {@link GnssClock#getTimeNanos()}.
      *
      * The sign of this value is given by the following equation:
      *      measurement time = time_ns + time_offset_ns
@@ -282,31 +221,31 @@ public final class GnssMeasurement implements Parcelable {
      * The value provides an individual time-stamp for the measurement, and allows sub-nanosecond
      * accuracy.
      */
-    public double getTimeOffsetInNs() {
-        return mTimeOffsetInNs;
+    public double getTimeOffsetNanos() {
+        return mTimeOffsetNanos;
     }
 
     /**
      * Sets the time offset at which the measurement was taken in nanoseconds.
      */
-    public void setTimeOffsetInNs(double value) {
-        mTimeOffsetInNs = value;
+    public void setTimeOffsetNanos(double value) {
+        mTimeOffsetNanos = value;
     }
 
     /**
      * Gets per-satellite sync state.
      * It represents the current sync state for the associated satellite.
      *
-     * This value helps interpret {@link #getReceivedSvTimeInNs()}.
+     * This value helps interpret {@link #getReceivedSvTimeNanos()}.
      */
-    public short getState() {
+    public int getState() {
         return mState;
     }
 
     /**
      * Sets the sync state.
      */
-    public void setState(short value) {
+    public void setState(int value) {
         mState = value;
     }
 
@@ -408,29 +347,29 @@ public final class GnssMeasurement implements Parcelable {
      *     Symbol sync     : [ 0   2ms ]   : STATE_SYMBOL_SYNC is set
      *     Message         : [ 0    1s ]   : STATE_SBAS_SYNC is set
      */
-    public long getReceivedSvTimeInNs() {
-        return mReceivedSvTimeInNs;
+    public long getReceivedSvTimeNanos() {
+        return mReceivedSvTimeNanos;
     }
 
     /**
      * Sets the received GNSS time in nanoseconds.
      */
-    public void setReceivedSvTimeInNs(long value) {
-        mReceivedSvTimeInNs = value;
+    public void setReceivedSvTimeNanos(long value) {
+        mReceivedSvTimeNanos = value;
     }
 
     /**
      * Gets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
      */
-    public long getReceivedSvTimeUncertaintyInNs() {
-        return mReceivedSvTimeUncertaintyInNs;
+    public long getReceivedSvTimeUncertaintyNanos() {
+        return mReceivedSvTimeUncertaintyNanos;
     }
 
     /**
      * Sets the received GNSS time uncertainty (1-Sigma) in nanoseconds.
      */
-    public void setReceivedSvTimeUncertaintyInNs(long value) {
-        mReceivedSvTimeUncertaintyInNs = value;
+    public void setReceivedSvTimeUncertaintyNanos(long value) {
+        mReceivedSvTimeUncertaintyNanos = value;
     }
 
     /**
@@ -439,45 +378,46 @@ public final class GnssMeasurement implements Parcelable {
      *
      * The value contains the measured C/N0 for the signal at the antenna input.
      */
-    public double getCn0InDbHz() {
-        return mCn0InDbHz;
+    public double getCn0DbHz() {
+        return mCn0DbHz;
     }
 
     /**
      * Sets the carrier-to-noise density in dB-Hz.
      */
-    public void setCn0InDbHz(double value) {
-        mCn0InDbHz = value;
+    public void setCn0DbHz(double value) {
+        mCn0DbHz = value;
     }
 
     /**
      * Gets the Pseudorange rate at the timestamp in m/s.
-     * The reported value includes {@link #getPseudorangeRateUncertaintyInMetersPerSec()}.
      *
-     * The correction of a given Pseudorange Rate value includes corrections from receiver and
-     * satellite clock frequency errors.
-     * {@link #isPseudorangeRateCorrected()} identifies the type of value reported.
+     * The reported value includes {@link #getPseudorangeRateUncertaintyMetersPerSecond()}.
+     *
+     * The value is uncorrected, hence corrections for receiver and satellite clock frequency errors
+     * should not be included.
+     *
+     * A positive 'uncorrected' value indicates that the SV is moving away from the receiver. The
+     * sign of the 'uncorrected' 'pseudorange rate' and its relation to the sign of 'doppler shift'
+     * is given by the equation:
      *
-     * A positive 'uncorrected' value indicates that the SV is moving away from the receiver.
-     * The sign of the 'uncorrected' Pseudorange Rate and its relation to the sign of
-     * {@link #getDopplerShiftInHz()} is given by the equation:
      *      pseudorange rate = -k * doppler shift   (where k is a constant)
      */
-    public double getPseudorangeRateInMetersPerSec() {
-        return mPseudorangeRateInMetersPerSec;
+    public double getPseudorangeRateMetersPerSecond() {
+        return mPseudorangeRateMetersPerSecond;
     }
 
     /**
      * Sets the pseudorange rate at the timestamp in m/s.
      */
-    public void setPseudorangeRateInMetersPerSec(double value) {
-        mPseudorangeRateInMetersPerSec = value;
+    public void setPseudorangeRateMetersPerSecond(double value) {
+        mPseudorangeRateMetersPerSecond = value;
     }
 
     /**
-     * See {@link #getPseudorangeRateInMetersPerSec()} for more details.
+     * See {@link #getPseudorangeRateMetersPerSecond()} for more details.
      *
-     * @return {@code true} if {@link #getPseudorangeRateInMetersPerSec()} contains a corrected
+     * @return {@code true} if {@link #getPseudorangeRateMetersPerSecond()} contains a corrected
      *         value, {@code false} if it contains an uncorrected value.
      */
     public boolean isPseudorangeRateCorrected() {
@@ -488,30 +428,30 @@ public final class GnssMeasurement implements Parcelable {
      * Gets the pseudorange's rate uncertainty (1-Sigma) in m/s.
      * The uncertainty is represented as an absolute (single sided) value.
      */
-    public double getPseudorangeRateUncertaintyInMetersPerSec() {
-        return mPseudorangeRateUncertaintyInMetersPerSec;
+    public double getPseudorangeRateUncertaintyMetersPerSecond() {
+        return mPseudorangeRateUncertaintyMetersPerSecond;
     }
 
     /**
      * Sets the pseudorange's rate uncertainty (1-Sigma) in m/s.
      */
-    public void setPseudorangeRateUncertaintyInMetersPerSec(double value) {
-        mPseudorangeRateUncertaintyInMetersPerSec = value;
+    public void setPseudorangeRateUncertaintyMetersPerSecond(double value) {
+        mPseudorangeRateUncertaintyMetersPerSecond = value;
     }
 
     /**
      * Gets 'Accumulated Delta Range' state.
-     * It indicates whether {@link #getAccumulatedDeltaRangeInMeters()} is reset or there is a
+     * It indicates whether {@link #getAccumulatedDeltaRangeMeters()} is reset or there is a
      * cycle slip (indicating 'loss of lock').
      */
-    public short getAccumulatedDeltaRangeState() {
+    public int getAccumulatedDeltaRangeState() {
         return mAccumulatedDeltaRangeState;
     }
 
     /**
      * Sets the 'Accumulated Delta Range' state.
      */
-    public void setAccumulatedDeltaRangeState(short value) {
+    public void setAccumulatedDeltaRangeState(int value) {
         mAccumulatedDeltaRangeState = value;
     }
 
@@ -545,24 +485,24 @@ public final class GnssMeasurement implements Parcelable {
 
     /**
      * Gets the accumulated delta range since the last channel reset, in meters.
-     * The reported value includes {@link #getAccumulatedDeltaRangeUncertaintyInMeters()}.
+     * The reported value includes {@link #getAccumulatedDeltaRangeUncertaintyMeters()}.
      *
      * The availability of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
      *
      * A positive value indicates that the SV is moving away from the receiver.
-     * The sign of {@link #getAccumulatedDeltaRangeInMeters()} and its relation to the sign of
+     * The sign of {@link #getAccumulatedDeltaRangeMeters()} and its relation to the sign of
      * {@link #getCarrierPhase()} is given by the equation:
      *          accumulated delta range = -k * carrier phase    (where k is a constant)
      */
-    public double getAccumulatedDeltaRangeInMeters() {
-        return mAccumulatedDeltaRangeInMeters;
+    public double getAccumulatedDeltaRangeMeters() {
+        return mAccumulatedDeltaRangeMeters;
     }
 
     /**
      * Sets the accumulated delta range in meters.
      */
-    public void setAccumulatedDeltaRangeInMeters(double value) {
-        mAccumulatedDeltaRangeInMeters = value;
+    public void setAccumulatedDeltaRangeMeters(double value) {
+        mAccumulatedDeltaRangeMeters = value;
     }
 
     /**
@@ -571,8 +511,8 @@ public final class GnssMeasurement implements Parcelable {
      *
      * The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
      */
-    public double getAccumulatedDeltaRangeUncertaintyInMeters() {
-        return mAccumulatedDeltaRangeUncertaintyInMeters;
+    public double getAccumulatedDeltaRangeUncertaintyMeters() {
+        return mAccumulatedDeltaRangeUncertaintyMeters;
     }
 
     /**
@@ -580,149 +520,14 @@ public final class GnssMeasurement implements Parcelable {
      *
      * The status of the value is represented by {@link #getAccumulatedDeltaRangeState()}.
      */
-    public void setAccumulatedDeltaRangeUncertaintyInMeters(double value) {
-        mAccumulatedDeltaRangeUncertaintyInMeters = value;
-    }
-
-    /**
-     * Returns true if {@link #getPseudorangeInMeters()} is available, false otherwise.
-     */
-    public boolean hasPseudorangeInMeters() {
-        return isFlagSet(HAS_PSEUDORANGE);
-    }
-
-    /**
-     * Gets the best derived pseudorange by the chipset, in meters.
-     * The reported pseudorange includes {@link #getPseudorangeUncertaintyInMeters()}.
-     *
-     * The value is only available if {@link #hasPseudorangeInMeters()} is true.
-     */
-    public double getPseudorangeInMeters() {
-        return mPseudorangeInMeters;
-    }
-
-    /**
-     * Sets the Pseudo-range in meters.
-     */
-    public void setPseudorangeInMeters(double value) {
-        setFlag(HAS_PSEUDORANGE);
-        mPseudorangeInMeters = value;
-    }
-
-    /**
-     * Resets the Pseudo-range in meters.
-     */
-    public void resetPseudorangeInMeters() {
-        resetFlag(HAS_PSEUDORANGE);
-        mPseudorangeInMeters = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getPseudorangeUncertaintyInMeters()} is available, false otherwise.
-     */
-    public boolean hasPseudorangeUncertaintyInMeters() {
-        return isFlagSet(HAS_PSEUDORANGE_UNCERTAINTY);
-    }
-
-    /**
-     * Gets the pseudorange's uncertainty (1-Sigma) in meters.
-     * The value contains the 'pseudorange' and 'clock' uncertainty in it.
-     * The uncertainty is represented as an absolute (single sided) value.
-     *
-     * The value is only available if {@link #hasPseudorangeUncertaintyInMeters()} is true.
-     */
-    public double getPseudorangeUncertaintyInMeters() {
-        return mPseudorangeUncertaintyInMeters;
-    }
-
-    /**
-     * Sets the pseudo-range's uncertainty (1-Sigma) in meters.
-     */
-    public void setPseudorangeUncertaintyInMeters(double value) {
-        setFlag(HAS_PSEUDORANGE_UNCERTAINTY);
-        mPseudorangeUncertaintyInMeters = value;
-    }
-
-    /**
-     * Resets the pseudo-range's uncertainty (1-Sigma) in meters.
-     */
-    public void resetPseudorangeUncertaintyInMeters() {
-        resetFlag(HAS_PSEUDORANGE_UNCERTAINTY);
-        mPseudorangeUncertaintyInMeters = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getCodePhaseInChips()} is available, false otherwise.
-     */
-    public boolean hasCodePhaseInChips() {
-        return isFlagSet(HAS_CODE_PHASE);
-    }
-
-    /**
-     * Gets the fraction of the current C/A code cycle.
-     * Range: [0, 1023]
-     * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
-     * The reported code-phase includes {@link #getCodePhaseUncertaintyInChips()}.
-     *
-     * The value is only available if {@link #hasCodePhaseInChips()} is true.
-     */
-    public double getCodePhaseInChips() {
-        return mCodePhaseInChips;
-    }
-
-    /**
-     * Sets the Code-phase in chips.
-     */
-    public void setCodePhaseInChips(double value) {
-        setFlag(HAS_CODE_PHASE);
-        mCodePhaseInChips = value;
-    }
-
-    /**
-     * Resets the Code-phase in chips.
-     */
-    public void resetCodePhaseInChips() {
-        resetFlag(HAS_CODE_PHASE);
-        mCodePhaseInChips = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getCodePhaseUncertaintyInChips()} is available, false otherwise.
-     */
-    public boolean hasCodePhaseUncertaintyInChips() {
-        return isFlagSet(HAS_CODE_PHASE_UNCERTAINTY);
-    }
-
-    /**
-     * Gets the code-phase's uncertainty (1-Sigma) as a fraction of chips.
-     * The uncertainty is represented as an absolute (single sided) value.
-     *
-     * The value is only available if {@link #hasCodePhaseUncertaintyInChips()} is true.
-     */
-    public double getCodePhaseUncertaintyInChips() {
-        return mCodePhaseUncertaintyInChips;
-    }
-
-    /**
-     * Sets the Code-phase's uncertainty (1-Sigma) in fractions of chips.
-     */
-    public void setCodePhaseUncertaintyInChips(double value) {
-        setFlag(HAS_CODE_PHASE_UNCERTAINTY);
-        mCodePhaseUncertaintyInChips = value;
+    public void setAccumulatedDeltaRangeUncertaintyMeters(double value) {
+        mAccumulatedDeltaRangeUncertaintyMeters = value;
     }
 
     /**
-     * Resets the Code-phase's uncertainty (1-Sigma) in fractions of chips.
+     * Returns true if {@link #getCarrierFrequencyHz()} is available, false otherwise.
      */
-    public void resetCodePhaseUncertaintyInChips() {
-        resetFlag(HAS_CODE_PHASE_UNCERTAINTY);
-        mCodePhaseUncertaintyInChips = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getCarrierFrequencyInHz()} is available, false otherwise.
-     */
-    public boolean hasCarrierFrequencyInHz() {
+    public boolean hasCarrierFrequencyHz() {
         return isFlagSet(HAS_CARRIER_FREQUENCY);
     }
 
@@ -730,26 +535,26 @@ public final class GnssMeasurement implements Parcelable {
      * Gets the carrier frequency at which codes and messages are modulated, it can be L1 or L2.
      * If the field is not set, the carrier frequency corresponds to L1.
      *
-     * The value is only available if {@link #hasCarrierFrequencyInHz()} is true.
+     * The value is only available if {@link #hasCarrierFrequencyHz()} is true.
      */
-    public float getCarrierFrequencyInHz() {
-        return mCarrierFrequencyInHz;
+    public float getCarrierFrequencyHz() {
+        return mCarrierFrequencyHz;
     }
 
     /**
      * Sets the Carrier frequency (L1 or L2) in Hz.
      */
-    public void setCarrierFrequencyInHz(float carrierFrequencyInHz) {
+    public void setCarrierFrequencyHz(float carrierFrequencyHz) {
         setFlag(HAS_CARRIER_FREQUENCY);
-        mCarrierFrequencyInHz = carrierFrequencyInHz;
+        mCarrierFrequencyHz = carrierFrequencyHz;
     }
 
     /**
      * Resets the Carrier frequency (L1 or L2) in Hz.
      */
-    public void resetCarrierFrequencyInHz() {
+    public void resetCarrierFrequencyHz() {
         resetFlag(HAS_CARRIER_FREQUENCY);
-        mCarrierFrequencyInHz = Float.NaN;
+        mCarrierFrequencyHz = Float.NaN;
     }
 
     /**
@@ -761,7 +566,7 @@ public final class GnssMeasurement implements Parcelable {
 
     /**
      * The number of full carrier cycles between the satellite and the receiver.
-     * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
+     * The reference frequency is given by the value of {@link #getCarrierFrequencyHz()}.
      *
      * The value is only available if {@link #hasCarrierCycles()} is true.
      */
@@ -797,7 +602,7 @@ public final class GnssMeasurement implements Parcelable {
      * Range: [0.0, 1.0].
      * This is usually the fractional part of the complete carrier phase measurement.
      *
-     * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
+     * The reference frequency is given by the value of {@link #getCarrierFrequencyHz()}.
      * The reported carrier-phase includes {@link #getCarrierPhaseUncertainty()}.
      *
      * The value is only available if {@link #hasCarrierPhase()} is true.
@@ -856,183 +661,17 @@ public final class GnssMeasurement implements Parcelable {
     }
 
     /**
-     * Gets a value indicating the 'loss of lock' state of the event.
-     */
-    @LossOfLockStatus
-    public byte getLossOfLock() {
-        return mLossOfLock;
-    }
-
-    /**
-     * Sets the 'loss of lock' status.
-     */
-    public void setLossOfLock(@LossOfLockStatus byte value) {
-        mLossOfLock = value;
-    }
-
-    /**
-     * Gets a string representation of the 'loss of lock'.
-     * For internal and logging use only.
-     */
-    private String getLossOfLockString() {
-        switch (mLossOfLock) {
-            case LOSS_OF_LOCK_UNKNOWN:
-                return "Unknown";
-            case LOSS_OF_LOCK_OK:
-                return "Ok";
-            case LOSS_OF_LOCK_CYCLE_SLIP:
-                return "CycleSlip";
-            default:
-                return "<Invalid:" + mLossOfLock + ">";
-        }
-    }
-
-    /**
-     * Returns true if {@link #getBitNumber()} is available, false otherwise.
-     */
-    public boolean hasBitNumber() {
-        return isFlagSet(HAS_BIT_NUMBER);
-    }
-
-    /**
-     * Gets the number of GPS bits transmitted since Sat-Sun midnight (GPS week).
-     *
-     * The value is only available if {@link #hasBitNumber()} is true.
-     */
-    public int getBitNumber() {
-        return mBitNumber;
-    }
-
-    /**
-     * Sets the bit number within the broadcast frame.
-     */
-    public void setBitNumber(int bitNumber) {
-        setFlag(HAS_BIT_NUMBER);
-        mBitNumber = bitNumber;
-    }
-
-    /**
-     * Resets the bit number within the broadcast frame.
-     */
-    public void resetBitNumber() {
-        resetFlag(HAS_BIT_NUMBER);
-        mBitNumber = Integer.MIN_VALUE;
-    }
-
-    /**
-     * Returns true if {@link #getTimeFromLastBitInMs()} is available, false otherwise.
-     */
-    public boolean hasTimeFromLastBitInMs() {
-        return isFlagSet(HAS_TIME_FROM_LAST_BIT);
-    }
-
-    /**
-     * Gets the elapsed time since the last received bit in milliseconds.
-     * Range: [0, 20].
-     *
-     * The value is only available if {@link #hasTimeFromLastBitInMs()} is true.
-     */
-    public short getTimeFromLastBitInMs() {
-        return mTimeFromLastBitInMs;
-    }
-
-    /**
-     * Sets the elapsed time since the last received bit in milliseconds.
-     */
-    public void setTimeFromLastBitInMs(short value) {
-        setFlag(HAS_TIME_FROM_LAST_BIT);
-        mTimeFromLastBitInMs = value;
-    }
-
-    /**
-     * Resets the elapsed time since the last received bit in milliseconds.
-     */
-    public void resetTimeFromLastBitInMs() {
-        resetFlag(HAS_TIME_FROM_LAST_BIT);
-        mTimeFromLastBitInMs = Short.MIN_VALUE;
-    }
-
-    /**
-     * Returns true if {@link #getDopplerShiftInHz()} is available, false otherwise.
-     */
-    public boolean hasDopplerShiftInHz() {
-        return isFlagSet(HAS_DOPPLER_SHIFT);
-    }
-
-    /**
-     * Gets the Doppler Shift in Hz.
-     * A positive value indicates that the SV is moving toward the receiver.
-     *
-     * The reference frequency is given by the value of {@link #getCarrierFrequencyInHz()}.
-     * The reported doppler shift includes {@link #getDopplerShiftUncertaintyInHz()}.
-     *
-     * The value is only available if {@link #hasDopplerShiftInHz()} is true.
-     */
-    public double getDopplerShiftInHz() {
-        return mDopplerShiftInHz;
-    }
-
-    /**
-     * Sets the Doppler shift in Hz.
-     */
-    public void setDopplerShiftInHz(double value) {
-        setFlag(HAS_DOPPLER_SHIFT);
-        mDopplerShiftInHz = value;
-    }
-
-    /**
-     * Resets the Doppler shift in Hz.
-     */
-    public void resetDopplerShiftInHz() {
-        resetFlag(HAS_DOPPLER_SHIFT);
-        mDopplerShiftInHz = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getDopplerShiftUncertaintyInHz()} is available, false otherwise.
-     */
-    public boolean hasDopplerShiftUncertaintyInHz() {
-        return isFlagSet(HAS_DOPPLER_SHIFT_UNCERTAINTY);
-    }
-
-    /**
-     * Gets the Doppler's Shift uncertainty (1-Sigma) in Hz.
-     * The uncertainty is represented as an absolute (single sided) value.
-     *
-     * The value is only available if {@link #hasDopplerShiftUncertaintyInHz()} is true.
-     */
-    public double getDopplerShiftUncertaintyInHz() {
-        return mDopplerShiftUncertaintyInHz;
-    }
-
-    /**
-     * Sets the Doppler's shift uncertainty (1-Sigma) in Hz.
-     */
-    public void setDopplerShiftUncertaintyInHz(double value) {
-        setFlag(HAS_DOPPLER_SHIFT_UNCERTAINTY);
-        mDopplerShiftUncertaintyInHz = value;
-    }
-
-    /**
-     * Resets the Doppler's shift uncertainty (1-Sigma) in Hz.
-     */
-    public void resetDopplerShiftUncertaintyInHz() {
-        resetFlag(HAS_DOPPLER_SHIFT_UNCERTAINTY);
-        mDopplerShiftUncertaintyInHz = Double.NaN;
-    }
-
-    /**
      * Gets a value indicating the 'multipath' state of the event.
      */
     @MultipathIndicator
-    public byte getMultipathIndicator() {
+    public int getMultipathIndicator() {
         return mMultipathIndicator;
     }
 
     /**
      * Sets the 'multi-path' indicator.
      */
-    public void setMultipathIndicator(@MultipathIndicator byte value) {
+    public void setMultipathIndicator(@MultipathIndicator int value) {
         mMultipathIndicator = value;
     }
 
@@ -1085,200 +724,30 @@ public final class GnssMeasurement implements Parcelable {
         mSnrInDb = Double.NaN;
     }
 
-    /**
-     * Returns true if {@link #getElevationInDeg()} is available, false otherwise.
-     */
-    public boolean hasElevationInDeg() {
-        return isFlagSet(HAS_ELEVATION);
-    }
-
-    /**
-     * Gets the Elevation in degrees.
-     * Range: [-90, 90]
-     * The reported elevation includes {@link #getElevationUncertaintyInDeg()}.
-     *
-     * The value is only available if {@link #hasElevationInDeg()} is true.
-     */
-    public double getElevationInDeg() {
-        return mElevationInDeg;
-    }
-
-    /**
-     * Sets the Elevation in degrees.
-     */
-    public void setElevationInDeg(double elevationInDeg) {
-        setFlag(HAS_ELEVATION);
-        mElevationInDeg = elevationInDeg;
-    }
-
-    /**
-     * Resets the Elevation in degrees.
-     */
-    public void resetElevationInDeg() {
-        resetFlag(HAS_ELEVATION);
-        mElevationInDeg = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getElevationUncertaintyInDeg()} is available, false otherwise.
-     */
-    public boolean hasElevationUncertaintyInDeg() {
-        return isFlagSet(HAS_ELEVATION_UNCERTAINTY);
-    }
-
-    /**
-     * Gets the elevation's uncertainty (1-Sigma) in degrees.
-     * Range: [0, 90]
-     *
-     * The uncertainty is represented as an absolute (single sided) value.
-     *
-     * The value is only available if {@link #hasElevationUncertaintyInDeg()} is true.
-     */
-    public double getElevationUncertaintyInDeg() {
-        return mElevationUncertaintyInDeg;
-    }
-
-    /**
-     * Sets the elevation's uncertainty (1-Sigma) in degrees.
-     */
-    public void setElevationUncertaintyInDeg(double value) {
-        setFlag(HAS_ELEVATION_UNCERTAINTY);
-        mElevationUncertaintyInDeg = value;
-    }
-
-    /**
-     * Resets the elevation's uncertainty (1-Sigma) in degrees.
-     */
-    public void resetElevationUncertaintyInDeg() {
-        resetFlag(HAS_ELEVATION_UNCERTAINTY);
-        mElevationUncertaintyInDeg = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getAzimuthInDeg()} is available, false otherwise.
-     */
-    public boolean hasAzimuthInDeg() {
-        return isFlagSet(HAS_AZIMUTH);
-    }
-
-    /**
-     * Gets the azimuth in degrees.
-     * Range: [0, 360).
-     *
-     * The reported azimuth includes {@link #getAzimuthUncertaintyInDeg()}.
-     *
-     * The value is only available if {@link #hasAzimuthInDeg()} is true.
-     */
-    public double getAzimuthInDeg() {
-        return mAzimuthInDeg;
-    }
-
-    /**
-     * Sets the Azimuth in degrees.
-     */
-    public void setAzimuthInDeg(double value) {
-        setFlag(HAS_AZIMUTH);
-        mAzimuthInDeg = value;
-    }
-
-    /**
-     * Resets the Azimuth in degrees.
-     */
-    public void resetAzimuthInDeg() {
-        resetFlag(HAS_AZIMUTH);
-        mAzimuthInDeg = Double.NaN;
-    }
-
-    /**
-     * Returns true if {@link #getAzimuthUncertaintyInDeg()} is available, false otherwise.
-     */
-    public boolean hasAzimuthUncertaintyInDeg() {
-        return isFlagSet(HAS_AZIMUTH_UNCERTAINTY);
-    }
-
-    /**
-     * Gets the azimuth's uncertainty (1-Sigma) in degrees.
-     * Range: [0, 180].
-     *
-     * The uncertainty is represented as an absolute (single sided) value.
-     *
-     * The value is only available if {@link #hasAzimuthUncertaintyInDeg()} is true.
-     */
-    public double getAzimuthUncertaintyInDeg() {
-        return mAzimuthUncertaintyInDeg;
-    }
-
-    /**
-     * Sets the Azimuth's uncertainty (1-Sigma) in degrees.
-     */
-    public void setAzimuthUncertaintyInDeg(double value) {
-        setFlag(HAS_AZIMUTH_UNCERTAINTY);
-        mAzimuthUncertaintyInDeg = value;
-    }
-
-    /**
-     * Resets the Azimuth's uncertainty (1-Sigma) in degrees.
-     */
-    public void resetAzimuthUncertaintyInDeg() {
-        resetFlag(HAS_AZIMUTH_UNCERTAINTY);
-        mAzimuthUncertaintyInDeg = Double.NaN;
-    }
-
-    /**
-     * Gets a flag indicating whether the GNSS represented by the measurement was used for computing
-     * the most recent fix.
-     *
-     * @return A non-null value if the data is available, null otherwise.
-     */
-    public boolean isUsedInFix() {
-        return mUsedInFix;
-    }
-
-    /**
-     * Sets the Used-in-Fix flag.
-     */
-    public void setUsedInFix(boolean value) {
-        mUsedInFix = value;
-    }
-
     public static final Creator<GnssMeasurement> CREATOR = new Creator<GnssMeasurement>() {
         @Override
         public GnssMeasurement createFromParcel(Parcel parcel) {
             GnssMeasurement gnssMeasurement = new GnssMeasurement();
 
             gnssMeasurement.mFlags = parcel.readInt();
-            gnssMeasurement.mSvid = (short) parcel.readInt();
-            gnssMeasurement.mConstellationType = parcel.readByte();
-            gnssMeasurement.mTimeOffsetInNs = parcel.readDouble();
-            gnssMeasurement.mState = (short) parcel.readInt();
-            gnssMeasurement.mReceivedSvTimeInNs = parcel.readLong();
-            gnssMeasurement.mReceivedSvTimeUncertaintyInNs = parcel.readLong();
-            gnssMeasurement.mCn0InDbHz = parcel.readDouble();
-            gnssMeasurement.mPseudorangeRateInMetersPerSec = parcel.readDouble();
-            gnssMeasurement.mPseudorangeRateUncertaintyInMetersPerSec = parcel.readDouble();
-            gnssMeasurement.mAccumulatedDeltaRangeState = (short) parcel.readInt();
-            gnssMeasurement.mAccumulatedDeltaRangeInMeters = parcel.readDouble();
-            gnssMeasurement.mAccumulatedDeltaRangeUncertaintyInMeters = parcel.readDouble();
-            gnssMeasurement.mPseudorangeInMeters = parcel.readDouble();
-            gnssMeasurement.mPseudorangeUncertaintyInMeters = parcel.readDouble();
-            gnssMeasurement.mCodePhaseInChips = parcel.readDouble();
-            gnssMeasurement.mCodePhaseUncertaintyInChips = parcel.readDouble();
-            gnssMeasurement.mCarrierFrequencyInHz = parcel.readFloat();
+            gnssMeasurement.mSvid = parcel.readInt();
+            gnssMeasurement.mConstellationType = parcel.readInt();
+            gnssMeasurement.mTimeOffsetNanos = parcel.readDouble();
+            gnssMeasurement.mState = parcel.readInt();
+            gnssMeasurement.mReceivedSvTimeNanos = parcel.readLong();
+            gnssMeasurement.mReceivedSvTimeUncertaintyNanos = parcel.readLong();
+            gnssMeasurement.mCn0DbHz = parcel.readDouble();
+            gnssMeasurement.mPseudorangeRateMetersPerSecond = parcel.readDouble();
+            gnssMeasurement.mPseudorangeRateUncertaintyMetersPerSecond = parcel.readDouble();
+            gnssMeasurement.mAccumulatedDeltaRangeState = parcel.readInt();
+            gnssMeasurement.mAccumulatedDeltaRangeMeters = parcel.readDouble();
+            gnssMeasurement.mAccumulatedDeltaRangeUncertaintyMeters = parcel.readDouble();
+            gnssMeasurement.mCarrierFrequencyHz = parcel.readFloat();
             gnssMeasurement.mCarrierCycles = parcel.readLong();
             gnssMeasurement.mCarrierPhase = parcel.readDouble();
             gnssMeasurement.mCarrierPhaseUncertainty = parcel.readDouble();
-            gnssMeasurement.mLossOfLock = parcel.readByte();
-            gnssMeasurement.mBitNumber = parcel.readInt();
-            gnssMeasurement.mTimeFromLastBitInMs = (short) parcel.readInt();
-            gnssMeasurement.mDopplerShiftInHz = parcel.readDouble();
-            gnssMeasurement.mDopplerShiftUncertaintyInHz = parcel.readDouble();
-            gnssMeasurement.mMultipathIndicator = parcel.readByte();
+            gnssMeasurement.mMultipathIndicator = parcel.readInt();
             gnssMeasurement.mSnrInDb = parcel.readDouble();
-            gnssMeasurement.mElevationInDeg = parcel.readDouble();
-            gnssMeasurement.mElevationUncertaintyInDeg = parcel.readDouble();
-            gnssMeasurement.mAzimuthInDeg = parcel.readDouble();
-            gnssMeasurement.mAzimuthUncertaintyInDeg = parcel.readDouble();
-            gnssMeasurement.mUsedInFix = parcel.readInt() != 0;
 
             return gnssMeasurement;
         }
@@ -1293,37 +762,23 @@ public final class GnssMeasurement implements Parcelable {
     public void writeToParcel(Parcel parcel, int flags) {
         parcel.writeInt(mFlags);
         parcel.writeInt(mSvid);
-        parcel.writeByte(mConstellationType);
-        parcel.writeDouble(mTimeOffsetInNs);
+        parcel.writeInt(mConstellationType);
+        parcel.writeDouble(mTimeOffsetNanos);
         parcel.writeInt(mState);
-        parcel.writeLong(mReceivedSvTimeInNs);
-        parcel.writeLong(mReceivedSvTimeUncertaintyInNs);
-        parcel.writeDouble(mCn0InDbHz);
-        parcel.writeDouble(mPseudorangeRateInMetersPerSec);
-        parcel.writeDouble(mPseudorangeRateUncertaintyInMetersPerSec);
+        parcel.writeLong(mReceivedSvTimeNanos);
+        parcel.writeLong(mReceivedSvTimeUncertaintyNanos);
+        parcel.writeDouble(mCn0DbHz);
+        parcel.writeDouble(mPseudorangeRateMetersPerSecond);
+        parcel.writeDouble(mPseudorangeRateUncertaintyMetersPerSecond);
         parcel.writeInt(mAccumulatedDeltaRangeState);
-        parcel.writeDouble(mAccumulatedDeltaRangeInMeters);
-        parcel.writeDouble(mAccumulatedDeltaRangeUncertaintyInMeters);
-        parcel.writeDouble(mPseudorangeInMeters);
-        parcel.writeDouble(mPseudorangeUncertaintyInMeters);
-        parcel.writeDouble(mCodePhaseInChips);
-        parcel.writeDouble(mCodePhaseUncertaintyInChips);
-        parcel.writeFloat(mCarrierFrequencyInHz);
+        parcel.writeDouble(mAccumulatedDeltaRangeMeters);
+        parcel.writeDouble(mAccumulatedDeltaRangeUncertaintyMeters);
+        parcel.writeFloat(mCarrierFrequencyHz);
         parcel.writeLong(mCarrierCycles);
         parcel.writeDouble(mCarrierPhase);
         parcel.writeDouble(mCarrierPhaseUncertainty);
-        parcel.writeByte(mLossOfLock);
-        parcel.writeInt(mBitNumber);
-        parcel.writeInt(mTimeFromLastBitInMs);
-        parcel.writeDouble(mDopplerShiftInHz);
-        parcel.writeDouble(mDopplerShiftUncertaintyInHz);
-        parcel.writeByte(mMultipathIndicator);
+        parcel.writeInt(mMultipathIndicator);
         parcel.writeDouble(mSnrInDb);
-        parcel.writeDouble(mElevationInDeg);
-        parcel.writeDouble(mElevationUncertaintyInDeg);
-        parcel.writeDouble(mAzimuthInDeg);
-        parcel.writeDouble(mAzimuthUncertaintyInDeg);
-        parcel.writeInt(mUsedInFix ? 1 : 0);
     }
 
     @Override
@@ -1339,25 +794,25 @@ public final class GnssMeasurement implements Parcelable {
 
         builder.append(String.format(format, "Svid", mSvid));
         builder.append(String.format(format, "ConstellationType", mConstellationType));
-        builder.append(String.format(format, "TimeOffsetInNs", mTimeOffsetInNs));
+        builder.append(String.format(format, "TimeOffsetNanos", mTimeOffsetNanos));
 
         builder.append(String.format(format, "State", getStateString()));
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "ReceivedSvTimeInNs",
-                mReceivedSvTimeInNs,
-                "ReceivedSvTimeUncertaintyInNs",
-                mReceivedSvTimeUncertaintyInNs));
+                "ReceivedSvTimeNanos",
+                mReceivedSvTimeNanos,
+                "ReceivedSvTimeUncertaintyNanos",
+                mReceivedSvTimeUncertaintyNanos));
 
-        builder.append(String.format(format, "Cn0InDbHz", mCn0InDbHz));
+        builder.append(String.format(format, "Cn0DbHz", mCn0DbHz));
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "PseudorangeRateInMetersPerSec",
-                mPseudorangeRateInMetersPerSec,
-                "PseudorangeRateUncertaintyInMetersPerSec",
-                mPseudorangeRateUncertaintyInMetersPerSec));
+                "PseudorangeRateMetersPerSecond",
+                mPseudorangeRateMetersPerSecond,
+                "PseudorangeRateUncertaintyMetersPerSecond",
+                mPseudorangeRateUncertaintyMetersPerSecond));
         builder.append(String.format(
                 format,
                 "PseudorangeRateIsCorrected",
@@ -1370,29 +825,15 @@ public final class GnssMeasurement implements Parcelable {
 
         builder.append(String.format(
                 formatWithUncertainty,
-                "AccumulatedDeltaRangeInMeters",
-                mAccumulatedDeltaRangeInMeters,
-                "AccumulatedDeltaRangeUncertaintyInMeters",
-                mAccumulatedDeltaRangeUncertaintyInMeters));
-
-        builder.append(String.format(
-                formatWithUncertainty,
-                "PseudorangeInMeters",
-                hasPseudorangeInMeters() ? mPseudorangeInMeters : null,
-                "PseudorangeUncertaintyInMeters",
-                hasPseudorangeUncertaintyInMeters() ? mPseudorangeUncertaintyInMeters : null));
-
-        builder.append(String.format(
-                formatWithUncertainty,
-                "CodePhaseInChips",
-                hasCodePhaseInChips() ? mCodePhaseInChips : null,
-                "CodePhaseUncertaintyInChips",
-                hasCodePhaseUncertaintyInChips() ? mCodePhaseUncertaintyInChips : null));
+                "AccumulatedDeltaRangeMeters",
+                mAccumulatedDeltaRangeMeters,
+                "AccumulatedDeltaRangeUncertaintyMeters",
+                mAccumulatedDeltaRangeUncertaintyMeters));
 
         builder.append(String.format(
                 format,
-                "CarrierFrequencyInHz",
-                hasCarrierFrequencyInHz() ? mCarrierFrequencyInHz : null));
+                "CarrierFrequencyHz",
+                hasCarrierFrequencyHz() ? mCarrierFrequencyHz : null));
 
         builder.append(String.format(
                 format,
@@ -1406,25 +847,6 @@ public final class GnssMeasurement implements Parcelable {
                 "CarrierPhaseUncertainty",
                 hasCarrierPhaseUncertainty() ? mCarrierPhaseUncertainty : null));
 
-        builder.append(String.format(format, "LossOfLock", getLossOfLockString()));
-
-        builder.append(String.format(
-                format,
-                "BitNumber",
-                hasBitNumber() ? mBitNumber : null));
-
-        builder.append(String.format(
-                format,
-                "TimeFromLastBitInMs",
-                hasTimeFromLastBitInMs() ? mTimeFromLastBitInMs : null));
-
-        builder.append(String.format(
-                formatWithUncertainty,
-                "DopplerShiftInHz",
-                hasDopplerShiftInHz() ? mDopplerShiftInHz : null,
-                "DopplerShiftUncertaintyInHz",
-                hasDopplerShiftUncertaintyInHz() ? mDopplerShiftUncertaintyInHz : null));
-
         builder.append(String.format(format, "MultipathIndicator", getMultipathIndicatorString()));
 
         builder.append(String.format(
@@ -1432,58 +854,28 @@ public final class GnssMeasurement implements Parcelable {
                 "SnrInDb",
                 hasSnrInDb() ? mSnrInDb : null));
 
-        builder.append(String.format(
-                formatWithUncertainty,
-                "ElevationInDeg",
-                hasElevationInDeg() ? mElevationInDeg : null,
-                "ElevationUncertaintyInDeg",
-                hasElevationUncertaintyInDeg() ? mElevationUncertaintyInDeg : null));
-
-        builder.append(String.format(
-                formatWithUncertainty,
-                "AzimuthInDeg",
-                hasAzimuthInDeg() ? mAzimuthInDeg : null,
-                "AzimuthUncertaintyInDeg",
-                hasAzimuthUncertaintyInDeg() ? mAzimuthUncertaintyInDeg : null));
-
-        builder.append(String.format(format, "UsedInFix", mUsedInFix));
-
         return builder.toString();
     }
 
     private void initialize() {
         mFlags = HAS_NO_FLAGS;
-        setSvid((short) 0);
-        setTimeOffsetInNs(Long.MIN_VALUE);
+        setSvid(0);
+        setTimeOffsetNanos(Long.MIN_VALUE);
         setState(STATE_UNKNOWN);
-        setReceivedSvTimeInNs(Long.MIN_VALUE);
-        setReceivedSvTimeUncertaintyInNs(Long.MAX_VALUE);
-        setCn0InDbHz(Double.MIN_VALUE);
-        setPseudorangeRateInMetersPerSec(Double.MIN_VALUE);
-        setPseudorangeRateUncertaintyInMetersPerSec(Double.MIN_VALUE);
+        setReceivedSvTimeNanos(Long.MIN_VALUE);
+        setReceivedSvTimeUncertaintyNanos(Long.MAX_VALUE);
+        setCn0DbHz(Double.MIN_VALUE);
+        setPseudorangeRateMetersPerSecond(Double.MIN_VALUE);
+        setPseudorangeRateUncertaintyMetersPerSecond(Double.MIN_VALUE);
         setAccumulatedDeltaRangeState(ADR_STATE_UNKNOWN);
-        setAccumulatedDeltaRangeInMeters(Double.MIN_VALUE);
-        setAccumulatedDeltaRangeUncertaintyInMeters(Double.MIN_VALUE);
-        resetPseudorangeInMeters();
-        resetPseudorangeUncertaintyInMeters();
-        resetCodePhaseInChips();
-        resetCodePhaseUncertaintyInChips();
-        resetCarrierFrequencyInHz();
+        setAccumulatedDeltaRangeMeters(Double.MIN_VALUE);
+        setAccumulatedDeltaRangeUncertaintyMeters(Double.MIN_VALUE);
+        resetCarrierFrequencyHz();
         resetCarrierCycles();
         resetCarrierPhase();
         resetCarrierPhaseUncertainty();
-        setLossOfLock(LOSS_OF_LOCK_UNKNOWN);
-        resetBitNumber();
-        resetTimeFromLastBitInMs();
-        resetDopplerShiftInHz();
-        resetDopplerShiftUncertaintyInHz();
         setMultipathIndicator(MULTIPATH_INDICATOR_UNKNOWN);
         resetSnrInDb();
-        resetElevationInDeg();
-        resetElevationUncertaintyInDeg();
-        resetAzimuthInDeg();
-        resetAzimuthUncertaintyInDeg();
-        setUsedInFix(false);
     }
 
     private void setFlag(int flag) {
index b744a03..86841ff 100644 (file)
@@ -33,46 +33,46 @@ import java.util.Collections;
  * Events are delivered to registered instances of {@link Callback}.
  */
 public final class GnssMeasurementsEvent implements Parcelable {
-    /** The status of GPS measurements event. */
+    /** The status of GNSS measurements event. */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GNSS_LOCATION_DISABLED})
     public @interface GnssMeasurementsStatus {}
 
     /**
-     * The system does not support tracking of GPS Measurements. This status will not change in the
+     * The system does not support tracking of GNSS Measurements. This status will not change in the
      * future.
      */
     public static final int STATUS_NOT_SUPPORTED = 0;
 
     /**
-     * GPS Measurements are successfully being tracked, it will receive updates once they are
+     * GNSS Measurements are successfully being tracked, it will receive updates once they are
      * available.
      */
     public static final int STATUS_READY = 1;
 
     /**
-     * GPS provider or Location is disabled, updates will not be received until they are enabled.
+     * GNSS provider or Location is disabled, updates will not be received until they are enabled.
      */
-    public static final int STATUS_GPS_LOCATION_DISABLED = 2;
+    public static final int STATUS_GNSS_LOCATION_DISABLED = 2;
 
     private final GnssClock mClock;
     private final Collection<GnssMeasurement> mReadOnlyMeasurements;
 
     /**
-     * Used for receiving GPS satellite measurements from the GPS engine.
+     * Used for receiving GNSS satellite measurements from the GNSS engine.
      * Each measurement contains raw and computed data identifying a satellite.
      * You can implement this interface and call
-     * {@link LocationManager#registerGnssMeasurementCallback}.
+     * {@link LocationManager#registerGnssMeasurementsCallback}.
      */
     public static abstract class Callback {
 
         /**
-         * Returns the latest collected GPS Measurements.
+         * Reports the latest collected GNSS Measurements.
          */
         public void onGnssMeasurementsReceived(GnssMeasurementsEvent eventArgs) {}
 
         /**
-         * Returns the latest status of the GPS Measurements sub-system.
+         * Reports the latest status of the GNSS Measurements sub-system.
          */
         public void onStatusChanged(@GnssMeasurementsStatus int status) {}
     }
index faefd0b..c0608e0 100644 (file)
@@ -34,58 +34,57 @@ public final class GnssNavigationMessage implements Parcelable {
 
     /** The type of the GPS Clock. */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({MESSAGE_TYPE_UNKNOWN, MESSAGE_TYPE_GPS_L1CA, MESSAGE_TYPE_GPS_L2CNAV,
-        MESSAGE_TYPE_GPS_L5CNAV, MESSAGE_TYPE_GPS_CNAV2, MESSAGE_TYPE_GLO_L1CA, MESSAGE_TYPE_BDS_D1,
-        MESSAGE_TYPE_BDS_D2, MESSAGE_TYPE_GAL_I, MESSAGE_TYPE_GAL_F})
+    @IntDef({TYPE_UNKNOWN, TYPE_GPS_L1CA, TYPE_GPS_L2CNAV, TYPE_GPS_L5CNAV, TYPE_GPS_CNAV2,
+        TYPE_GLO_L1CA, TYPE_BDS_D1, TYPE_BDS_D2, TYPE_GAL_I, TYPE_GAL_F})
     public @interface GnssNavigationMessageType {}
 
     // The following enumerations must be in sync with the values declared in gps.h
 
     /** Message type unknown */
-    public static final short MESSAGE_TYPE_UNKNOWN = 0;
+    public static final int TYPE_UNKNOWN = 0;
     /** GPS L1 C/A message contained in the structure.  */
-    public static final short MESSAGE_TYPE_GPS_L1CA = 0x0101;
+    public static final int TYPE_GPS_L1CA = 0x0101;
     /** GPS L2-CNAV message contained in the structure. */
-    public static final short MESSAGE_TYPE_GPS_L2CNAV = 0x0102;
+    public static final int TYPE_GPS_L2CNAV = 0x0102;
     /** GPS L5-CNAV message contained in the structure. */
-    public static final short MESSAGE_TYPE_GPS_L5CNAV = 0x0103;
+    public static final int TYPE_GPS_L5CNAV = 0x0103;
     /** GPS CNAV-2 message contained in the structure. */
-    public static final short MESSAGE_TYPE_GPS_CNAV2 = 0x0104;
+    public static final int TYPE_GPS_CNAV2 = 0x0104;
     /** Glonass L1 CA message contained in the structure. */
-    public static final short MESSAGE_TYPE_GLO_L1CA = 0x0301;
+    public static final int TYPE_GLO_L1CA = 0x0301;
     /** Beidou D1 message contained in the structure. */
-    public static final short MESSAGE_TYPE_BDS_D1 = 0x0501;
+    public static final int TYPE_BDS_D1 = 0x0501;
     /** Beidou D2 message contained in the structure. */
-    public static final short MESSAGE_TYPE_BDS_D2 = 0x0502;
+    public static final int TYPE_BDS_D2 = 0x0502;
     /** Galileo I/NAV message contained in the structure. */
-    public static final short MESSAGE_TYPE_GAL_I = 0x0601;
+    public static final int TYPE_GAL_I = 0x0601;
     /** Galileo F/NAV message contained in the structure. */
-    public static final short MESSAGE_TYPE_GAL_F = 0x0602;
+    public static final int TYPE_GAL_F = 0x0602;
 
     /**
      * The Navigation Message Status is 'unknown'.
      */
-    public static final short STATUS_UNKNOWN = 0;
+    public static final int STATUS_UNKNOWN = 0;
 
     /**
      * The Navigation Message was received without any parity error in its navigation words.
      */
-    public static final short STATUS_PARITY_PASSED = (1<<0);
+    public static final int STATUS_PARITY_PASSED = (1<<0);
 
     /**
      * The Navigation Message was received with words that failed parity check, but the receiver was
      * able to correct those words.
      */
-    public static final short STATUS_PARITY_REBUILT = (1<<1);
+    public static final int STATUS_PARITY_REBUILT = (1<<1);
 
     // End enumerations in sync with gps.h
 
-    private short mType;
-    private short mSvid;
-    private short mMessageId;
-    private short mSubmessageId;
+    private int mType;
+    private int mSvid;
+    private int mMessageId;
+    private int mSubmessageId;
     private byte[] mData;
-    private short mStatus;
+    private int mStatus;
 
     GnssNavigationMessage() {
         initialize();
@@ -114,14 +113,14 @@ public final class GnssNavigationMessage implements Parcelable {
      * Gets the type of the navigation message contained in the object.
      */
     @GnssNavigationMessageType
-    public short getType() {
+    public int getType() {
         return mType;
     }
 
     /**
      * Sets the type of the navigation message.
      */
-    public void setType(@GnssNavigationMessageType short value) {
+    public void setType(@GnssNavigationMessageType int value) {
         mType = value;
     }
 
@@ -131,25 +130,25 @@ public final class GnssNavigationMessage implements Parcelable {
      */
     private String getTypeString() {
         switch (mType) {
-            case MESSAGE_TYPE_UNKNOWN:
+            case TYPE_UNKNOWN:
                 return "Unknown";
-            case MESSAGE_TYPE_GPS_L1CA:
+            case TYPE_GPS_L1CA:
                 return "GPS L1 C/A";
-            case MESSAGE_TYPE_GPS_L2CNAV:
+            case TYPE_GPS_L2CNAV:
                 return "GPS L2-CNAV";
-            case MESSAGE_TYPE_GPS_L5CNAV:
+            case TYPE_GPS_L5CNAV:
                 return "GPS L5-CNAV";
-            case MESSAGE_TYPE_GPS_CNAV2:
+            case TYPE_GPS_CNAV2:
                 return "GPS CNAV2";
-            case MESSAGE_TYPE_GLO_L1CA:
+            case TYPE_GLO_L1CA:
                 return "Glonass L1 C/A";
-            case MESSAGE_TYPE_BDS_D1:
+            case TYPE_BDS_D1:
                 return "Beidou D1";
-            case MESSAGE_TYPE_BDS_D2:
+            case TYPE_BDS_D2:
                 return "Beidou D2";
-            case MESSAGE_TYPE_GAL_I:
+            case TYPE_GAL_I:
                 return "Galileo I";
-            case MESSAGE_TYPE_GAL_F:
+            case TYPE_GAL_F:
                 return "Galileo F";
             default:
                 return "<Invalid:" + mType + ">";
@@ -160,14 +159,14 @@ public final class GnssNavigationMessage implements Parcelable {
      * Gets the Pseudo-random number.
      * Range: [1, 32].
      */
-    public short getSvid() {
+    public int getSvid() {
         return mSvid;
     }
 
     /**
      * Sets the Pseud-random number.
      */
-    public void setSvid(short value) {
+    public void setSvid(int value) {
         mSvid = value;
     }
 
@@ -177,14 +176,14 @@ public final class GnssNavigationMessage implements Parcelable {
      * subframe 4 and 5, this value corresponds to the 'frame id' of the navigation message.
      * Subframe 1, 2, 3 does not contain a 'frame id' and this might be reported as -1.
      */
-    public short getMessageId() {
+    public int getMessageId() {
         return mMessageId;
     }
 
     /**
      * Sets the Message Identifier.
      */
-    public void setMessageId(short value) {
+    public void setMessageId(int value) {
         mMessageId = value;
     }
 
@@ -194,14 +193,14 @@ public final class GnssNavigationMessage implements Parcelable {
      * (or frame) that is being transmitted. i.e. for L1 C/A the sub-message identifier corresponds
      * to the sub-frame Id of the navigation message.
      */
-    public short getSubmessageId() {
+    public int getSubmessageId() {
         return mSubmessageId;
     }
 
     /**
      * Sets the Sub-message identifier.
      */
-    public void setSubmessageId(short value) {
+    public void setSubmessageId(int value) {
         mSubmessageId = value;
     }
 
@@ -228,14 +227,14 @@ public final class GnssNavigationMessage implements Parcelable {
     /**
      * Gets the Status of the navigation message contained in the object.
      */
-    public short getStatus() {
+    public int getStatus() {
         return mStatus;
     }
 
     /**
      * Sets the status of the navigation message.
      */
-    public void setStatus(short value) {
+    public void setStatus(int value) {
         mStatus = value;
     }
 
@@ -262,10 +261,10 @@ public final class GnssNavigationMessage implements Parcelable {
         public GnssNavigationMessage createFromParcel(Parcel parcel) {
             GnssNavigationMessage navigationMessage = new GnssNavigationMessage();
 
-            navigationMessage.setType((short) parcel.readInt());
-            navigationMessage.setSvid((short) parcel.readInt());
-            navigationMessage.setMessageId((short) parcel.readInt());
-            navigationMessage.setSubmessageId((short) parcel.readInt());
+            navigationMessage.setType(parcel.readInt());
+            navigationMessage.setSvid(parcel.readInt());
+            navigationMessage.setMessageId(parcel.readInt());
+            navigationMessage.setSubmessageId(parcel.readInt());
 
             int dataLength = parcel.readInt();
             byte[] data = new byte[dataLength];
@@ -274,7 +273,7 @@ public final class GnssNavigationMessage implements Parcelable {
 
             if (parcel.dataAvail() >= Integer.SIZE) {
                 int status = parcel.readInt();
-                navigationMessage.setStatus((short) status);
+                navigationMessage.setStatus(status);
             } else {
                 navigationMessage.setStatus(STATUS_UNKNOWN);
             }
@@ -328,7 +327,7 @@ public final class GnssNavigationMessage implements Parcelable {
     }
 
     private void initialize() {
-        mType = MESSAGE_TYPE_UNKNOWN;
+        mType = TYPE_UNKNOWN;
         mSvid = 0;
         mMessageId = -1;
         mSubmessageId = -1;
index 19c82e9..0df730d 100644 (file)
@@ -32,7 +32,7 @@ import java.security.InvalidParameterException;
 public final class GnssNavigationMessageEvent implements Parcelable {
     /** The status of GPS measurements event. */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GPS_LOCATION_DISABLED})
+    @IntDef({STATUS_NOT_SUPPORTED, STATUS_READY, STATUS_GNSS_LOCATION_DISABLED})
     public @interface GnssNavigationMessageStatus {}
 
     /**
@@ -50,7 +50,7 @@ public final class GnssNavigationMessageEvent implements Parcelable {
     /**
      * GPS provider or Location is disabled, updated will not be received until they are enabled.
      */
-    public static final int STATUS_GPS_LOCATION_DISABLED = 2;
+    public static final int STATUS_GNSS_LOCATION_DISABLED = 2;
 
     private final GnssNavigationMessage mNavigationMessage;
 
index 06ce30c..2a42fc6 100644 (file)
@@ -27,19 +27,19 @@ import java.lang.annotation.RetentionPolicy;
  */
 public final class GnssStatus {
     /** Unknown constellation type. */
-    public static final byte CONSTELLATION_UNKNOWN = 0;
+    public static final int CONSTELLATION_UNKNOWN = 0;
     /** Constellation type constant for GPS. */
-    public static final byte CONSTELLATION_GPS = 1;
+    public static final int CONSTELLATION_GPS = 1;
     /** Constellation type constant for SBAS. */
-    public static final byte CONSTELLATION_SBAS = 2;
+    public static final int CONSTELLATION_SBAS = 2;
     /** Constellation type constant for Glonass. */
-    public static final byte CONSTELLATION_GLONASS = 3;
+    public static final int CONSTELLATION_GLONASS = 3;
     /** Constellation type constant for QZSS. */
-    public static final byte CONSTELLATION_QZSS = 4;
+    public static final int CONSTELLATION_QZSS = 4;
     /** Constellation type constant for Beidou. */
-    public static final byte CONSTELLATION_BEIDOU = 5;
+    public static final int CONSTELLATION_BEIDOU = 5;
     /** Constellation type constant for Galileo. */
-    public static final byte CONSTELLATION_GALILEO = 6;
+    public static final int CONSTELLATION_GALILEO = 6;
 
     /** Constellation type. */
     @Retention(RetentionPolicy.SOURCE)
@@ -66,16 +66,16 @@ public final class GnssStatus {
 
     /* These package private values are modified by the LocationManager class */
     /* package */ int[] mSvidWithFlags;
-    /* package */ float[] mSnrs;
+    /* package */ float[] mCn0DbHz;
     /* package */ float[] mElevations;
     /* package */ float[] mAzimuths;
     /* package */ int mSvCount;
 
-    GnssStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+    GnssStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations,
             float[] azimuths) {
         mSvCount = svCount;
         mSvidWithFlags = svidWithFlags;
-        mSnrs = snrs;
+        mCn0DbHz = cn0s;
         mElevations = elevations;
         mAzimuths = azimuths;
     }
@@ -92,8 +92,8 @@ public final class GnssStatus {
      * @param satIndex the index of the satellite in the list.
      */
     @ConstellationType
-    public byte getConstellationType(int satIndex) {
-        return (byte) ((mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
+    public int getConstellationType(int satIndex) {
+        return ((mSvidWithFlags[satIndex] >> CONSTELLATION_TYPE_SHIFT_WIDTH)
                 & CONSTELLATION_TYPE_MASK);
     }
 
@@ -109,15 +109,15 @@ public final class GnssStatus {
      * Retrieves the signal-noise ration of the satellite at the specified position.
      * @param satIndex the index of the satellite in the list.
      */
-    public float getSnr(int satIndex) {
-        return mSnrs[satIndex];
+    public float getCn0DbHz(int satIndex) {
+        return mCn0DbHz[satIndex];
     }
 
     /**
      * Retrieves the elevation of the satellite at the specified position.
      * @param satIndex the index of the satellite in the list.
      */
-    public float getElevation(int satIndex) {
+    public float getElevationDegrees(int satIndex) {
         return 0f;
     }
 
@@ -125,7 +125,7 @@ public final class GnssStatus {
      * Retrieves the azimuth the satellite at the specified position.
      * @param satIndex the index of the satellite in the list.
      */
-    public float getAzimuth(int satIndex) {
+    public float getAzimuthDegrees(int satIndex) {
         return mAzimuths[satIndex];
     }
 
index b86171b..0d2955a 100644 (file)
@@ -32,13 +32,13 @@ public abstract class GnssStatusCallback {
 
     /**
      * Called when the GNSS system has received its first fix since starting.
-     * @param ttff the time from start to first fix.
+     * @param ttffMillis the time from start to first fix in milliseconds.
      */
-    public void onFirstFix(int ttff) {}
+    public void onFirstFix(int ttffMillis) {}
 
     /**
      * Called periodically to report GNSS satellite status.
      * @param status the current status of all satellites.
      */
     public void onSatelliteStatusChanged(GnssStatus status) {}
-}
\ No newline at end of file
+}
index 7b3dd7d..bc518f9 100644 (file)
@@ -138,7 +138,7 @@ public final class GpsStatus {
     // For API-compat a public ctor() is not available
     GpsStatus() {}
 
-    private void setStatus(int svCount, int[] svidWithFlags, float[] snrs, float[] elevations,
+    private void setStatus(int svCount, int[] svidWithFlags, float[] cn0s, float[] elevations,
             float[] azimuths) {
         clearSatellites();
         for (int i = 0; i < svCount; i++) {
@@ -158,7 +158,7 @@ public final class GpsStatus {
                 }
 
                 satellite.mValid = true;
-                satellite.mSnr = snrs[i];
+                satellite.mSnr = cn0s[i];
                 satellite.mElevation = elevations[i];
                 satellite.mAzimuth = azimuths[i];
                 satellite.mHasEphemeris =
@@ -179,7 +179,7 @@ public final class GpsStatus {
      */
     void setStatus(GnssStatus status, int timeToFirstFix) {
         mTimeToFirstFix = timeToFirstFix;
-        setStatus(status.mSvCount, status.mSvidWithFlags, status.mSnrs, status.mElevations,
+        setStatus(status.mSvCount, status.mSvidWithFlags, status.mCn0DbHz, status.mElevations,
                 status.mAzimuths);
     }
 
index 8c7d06e..d84614f 100644 (file)
@@ -26,7 +26,7 @@ oneway interface IGnssStatusListener
     void onGnssStarted();
     void onGnssStopped();
     void onFirstFix(int ttff);
-    void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] snrs,
+    void onSvStatusChanged(int svCount, in int[] svidWithFlags, in float[] cn0s,
             in float[] elevations, in float[] azimuths);
     void onNmeaReceived(long timestamp, String nmea);
 }
index 3cd47e7..28db099 100644 (file)
@@ -1554,9 +1554,9 @@ public class LocationManager {
 
         @Override
         public void onSvStatusChanged(int svCount, int[] prnWithFlags,
-                float[] snrs, float[] elevations, float[] azimuths) {
+                float[] cn0s, float[] elevations, float[] azimuths) {
             if (mGnssCallback != null) {
-                mGnssStatus = new GnssStatus(svCount, prnWithFlags, snrs, elevations, azimuths);
+                mGnssStatus = new GnssStatus(svCount, prnWithFlags, cn0s, elevations, azimuths);
 
                 Message msg = Message.obtain();
                 msg.what = GpsStatus.GPS_EVENT_SATELLITE_STATUS;
@@ -1805,7 +1805,7 @@ public class LocationManager {
 
     /**
      * No-op method to keep backward-compatibility.
-     * Don't use it. Use {@link #registerGnssMeasurementCallback} instead.
+     * Don't use it. Use {@link #registerGnssMeasurementsCallback} instead.
      * @hide
      * @deprecated
      */
@@ -1822,8 +1822,8 @@ public class LocationManager {
      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
      */
     @RequiresPermission(ACCESS_FINE_LOCATION)
-    public boolean registerGnssMeasurementCallback(GnssMeasurementsEvent.Callback callback) {
-        return registerGnssMeasurementCallback(callback, null);
+    public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) {
+        return registerGnssMeasurementsCallback(callback, null);
     }
 
     /**
@@ -1834,14 +1834,14 @@ public class LocationManager {
      * @return {@code true} if the callback was added successfully, {@code false} otherwise.
      */
     @RequiresPermission(ACCESS_FINE_LOCATION)
-    public boolean registerGnssMeasurementCallback(GnssMeasurementsEvent.Callback callback,
+    public boolean registerGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback,
             Handler handler) {
         return mGnssMeasurementCallbackTransport.add(callback, handler);
     }
 
     /**
      * No-op method to keep backward-compatibility.
-     * Don't use it. Use {@link #unregisterGnssMeasurementCallback} instead.
+     * Don't use it. Use {@link #unregisterGnssMeasurementsCallback} instead.
      * @hide
      * @deprecated
      */
@@ -1855,7 +1855,7 @@ public class LocationManager {
      *
      * @param callback a {@link GnssMeasurementsEvent.Callback} object to remove.
      */
-    public void unregisterGnssMeasurementCallback(GnssMeasurementsEvent.Callback callback) {
+    public void unregisterGnssMeasurementsCallback(GnssMeasurementsEvent.Callback callback) {
         mGnssMeasurementCallbackTransport.remove(callback);
     }
 
index 4808faf..316e88d 100644 (file)
@@ -40,7 +40,7 @@ public class GpsStatusTest extends TestCase {
     private GpsStatus mStatus;
     private int mCount;
     private int[] mPrns;
-    private float[] mSnrs;
+    private float[] mCn0s;
     private float[] mElevations;
     private float[] mAzimuth;
     private int mEphemerisMask;
@@ -179,7 +179,7 @@ public class GpsStatusTest extends TestCase {
 
     private void verifySatellites(GpsStatus status) {
         verifySatelliteCount(status, mCount);
-        verifySatellites(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask,
+        verifySatellites(status, mCount, mPrns, mCn0s, mElevations, mAzimuth, mEphemerisMask,
                 mAlmanacMask, mUsedInFixMask);
     }
 
@@ -187,7 +187,7 @@ public class GpsStatusTest extends TestCase {
             GpsStatus status,
             int count,
             int[] prns,
-            float[] snrs,
+            float[] cn0s,
             float[] elevations,
             float[] azimuth,
             int ephemerisMask,
@@ -197,7 +197,7 @@ public class GpsStatusTest extends TestCase {
             int prn = prns[i];
             GpsSatellite satellite = getSatellite(status, prn);
             assertNotNull(getSatelliteAssertInfo(i, prn, "non-null"), satellite);
-            assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), snrs[i], satellite.getSnr());
+            assertEquals(getSatelliteAssertInfo(i, prn, "Snr"), cn0s[i], satellite.getSnr());
             assertEquals(
                     getSatelliteAssertInfo(i, prn, "Elevation"),
                     elevations[i],
@@ -247,7 +247,7 @@ public class GpsStatusTest extends TestCase {
     }
 
     private void setSatellites(GpsStatus status) throws Exception {
-        set(status, mCount, mPrns, mSnrs, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask,
+        set(status, mCount, mPrns, mCn0s, mElevations, mAzimuth, mEphemerisMask, mAlmanacMask,
                 mUsedInFixMask);
     }
 
@@ -255,7 +255,7 @@ public class GpsStatusTest extends TestCase {
             GpsStatus status,
             int count,
             int[] prns,
-            float[] snrs,
+            float[] cn0s,
             float[] elevations,
             float[] azimuth,
             int ephemerisMask,
@@ -279,7 +279,7 @@ public class GpsStatusTest extends TestCase {
                 status,
                 count,
                 prns,
-                snrs,
+                cn0s,
                 elevations,
                 azimuth,
                 ephemerisMask,
@@ -333,7 +333,7 @@ public class GpsStatusTest extends TestCase {
         if (!reusePrns) {
             mPrns = generateIntArray(count);
         }
-        mSnrs = generateFloatArray(count);
+        mCn0s = generateFloatArray(count);
         mElevations = generateFloatArray(count);
         mAzimuth = generateFloatArray(count);
         mEphemerisMask = generateMask(mPrns);
index b0411a2..abb6f4e 100644 (file)
@@ -212,7 +212,7 @@ import java.util.Objects;
  * AudioTrack.getPlaybackHeadPosition()}),
  * depending on the context where audio frame is used.
  */
-public class AudioFormat implements Parcelable {
+public final class AudioFormat implements Parcelable {
 
     //---------------------------------------------------------
     // Constants
index c7e96cf..8206d23 100644 (file)
@@ -2147,9 +2147,10 @@ public class AudioManager {
                                 }
                                 break;
                             case MSSG_RECORDING_CONFIG_CHANGE:
-                                final AudioRecordingCallback cb = (AudioRecordingCallback) msg.obj;
-                                if (cb != null) {
-                                    cb.onRecordConfigChanged();
+                                final RecordConfigChangeCallbackData cbData =
+                                        (RecordConfigChangeCallbackData) msg.obj;
+                                if (cbData.mCb != null) {
+                                    cbData.mCb.onRecordConfigChanged(cbData.mConfigs);
                                 }
                                 break;
                             default:
@@ -2734,8 +2735,10 @@ public class AudioManager {
     public static abstract class AudioRecordingCallback {
         /**
          * Called whenever the device recording configuration has changed.
+         * @param configs array containing the results of
+         *      {@link AudioManager#getActiveRecordConfigurations()}.
          */
-        public void onRecordConfigChanged() {}
+        public void onRecordConfigChanged(AudioRecordConfiguration[] configs) {}
     }
 
     private static class AudioRecordingCallbackInfo {
@@ -2747,6 +2750,17 @@ public class AudioManager {
         }
     }
 
+    private final static class RecordConfigChangeCallbackData {
+        final AudioRecordingCallback mCb;
+        final AudioRecordConfiguration[] mConfigs;
+
+        RecordConfigChangeCallbackData(AudioRecordingCallback cb,
+                AudioRecordConfiguration[] configs) {
+            mCb = cb;
+            mConfigs = configs;
+        }
+    }
+
     /**
      * Register a callback to be notified of audio recording changes through
      * {@link AudioRecordingCallback}
@@ -2882,14 +2896,15 @@ public class AudioManager {
 
     private final IRecordingConfigDispatcher mRecCb = new IRecordingConfigDispatcher.Stub() {
 
-        public void dispatchRecordingConfigChange() {
+        public void dispatchRecordingConfigChange(AudioRecordConfiguration[] configs) {
             synchronized(mRecordCallbackLock) {
                 if (mRecordCallbackList != null) {
                     for (int i=0 ; i < mRecordCallbackList.size() ; i++) {
                         final AudioRecordingCallbackInfo arci = mRecordCallbackList.get(i);
                         if (arci.mHandler != null) {
                             final Message m = arci.mHandler.obtainMessage(
-                                    MSSG_RECORDING_CONFIG_CHANGE/*what*/, arci.mCb/*obj*/);
+                                    MSSG_RECORDING_CONFIG_CHANGE/*what*/,
+                                    new RecordConfigChangeCallbackData(arci.mCb, configs)/*obj*/);
                             arci.mHandler.sendMessage(m);
                         }
                     }
index c2cd9b3..de78a5a 100644 (file)
 
 package android.media;
 
+import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Objects;
 
@@ -29,7 +32,7 @@ import java.util.Objects;
  * {@link AudioManager#getActiveRecordConfigurations()} method.
  *
  */
-public class AudioRecordConfiguration implements Parcelable {
+public final class AudioRecordConfiguration implements Parcelable {
     private final static String TAG = new String("AudioRecordConfiguration");
 
     private final int mSessionId;
@@ -53,6 +56,19 @@ public class AudioRecordConfiguration implements Parcelable {
         mPatchHandle = patchHandle;
     }
 
+    /** @hide */
+    @IntDef({
+        MediaRecorder.AudioSource.DEFAULT,
+        MediaRecorder.AudioSource.VOICE_UPLINK,
+        MediaRecorder.AudioSource.VOICE_DOWNLINK,
+        MediaRecorder.AudioSource.VOICE_CALL,
+        MediaRecorder.AudioSource.CAMCORDER,
+        MediaRecorder.AudioSource.VOICE_RECOGNITION,
+        MediaRecorder.AudioSource.VOICE_COMMUNICATION
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface AudioSource {}
+
     /**
      * Returns the audio source being used for the recording.
      * @return one of {@link MediaRecorder.AudioSource#MIC},
@@ -63,7 +79,7 @@ public class AudioRecordConfiguration implements Parcelable {
      *       {@link MediaRecorder.AudioSource#VOICE_RECOGNITION},
      *       {@link MediaRecorder.AudioSource#VOICE_COMMUNICATION}.
      */
-    public int getClientAudioSource() { return mClientSource; }
+    public @AudioSource int getClientAudioSource() { return mClientSource; }
 
     /**
      * Returns the session number of the recording, see {@link AudioRecord#getAudioSessionId()}.
index 247c4ae..f597440 100644 (file)
@@ -638,7 +638,7 @@ public class AudioSystem
     public static final int PHONE_STATE_RINGING = 1;
     public static final int PHONE_STATE_INCALL = 2;
 
-    // device categories config for setForceUse, must match AudioSystem::forced_config
+    // device categories config for setForceUse, must match audio_policy_forced_cfg_t
     public static final int FORCE_NONE = 0;
     public static final int FORCE_SPEAKER = 1;
     public static final int FORCE_HEADPHONES = 2;
@@ -652,17 +652,20 @@ public class AudioSystem
     public static final int FORCE_NO_BT_A2DP = 10;
     public static final int FORCE_SYSTEM_ENFORCED = 11;
     public static final int FORCE_HDMI_SYSTEM_AUDIO_ENFORCED = 12;
-    private static final int NUM_FORCE_CONFIG = 13;
+    public static final int FORCE_ENCODED_SURROUND_NEVER = 13;
+    public static final int FORCE_ENCODED_SURROUND_ALWAYS = 14;
+    public static final int NUM_FORCE_CONFIG = 15;
     public static final int FORCE_DEFAULT = FORCE_NONE;
 
-    // usage for setForceUse, must match AudioSystem::force_use
+    // usage for setForceUse, must match audio_policy_force_use_t
     public static final int FOR_COMMUNICATION = 0;
     public static final int FOR_MEDIA = 1;
     public static final int FOR_RECORD = 2;
     public static final int FOR_DOCK = 3;
     public static final int FOR_SYSTEM = 4;
     public static final int FOR_HDMI_SYSTEM_AUDIO = 5;
-    private static final int NUM_FORCE_USE = 6;
+    public static final int FOR_ENCODED_SURROUND = 6;
+    private static final int NUM_FORCE_USE = 7;
 
     // usage for AudioRecord.startRecordingSync(), must match AudioSystem::sync_event_t
     public static final int SYNC_EVENT_NONE = 0;
index f02e837..c48bfc5 100644 (file)
@@ -1214,13 +1214,12 @@ public class AudioTrack implements AudioRouting
      * An underrun occurs if the application does not write audio
      * data quickly enough, causing the buffer to underflow
      * and a potential audio glitch or pop.
+     * <p>
      * Underruns are less likely when buffer sizes are large.
-     * <p> Though the "int" type is signed 32-bits, the value should be reinterpreted
-     * as if it is unsigned 32-bits.
-     * That is, the next position after 0x7FFFFFFF is (int) 0x80000000.
-     * This is a continuously advancing counter. It can wrap around to zero
-     * if there are too many underruns. If there were, for example, 68 underruns per
-     * second then the counter would wrap in 2 years.
+     * It may be possible to eliminate underruns by recreating the AudioTrack with
+     * a larger buffer.
+     * Or by using {@link #setBufferSizeInFrames(int)} to dynamically increase the
+     * effective size of the buffer.
      */
     public int getUnderrunCount() {
         return native_get_underrun_count();
index a5eb8b9..eaa92ca 100644 (file)
@@ -16,6 +16,8 @@
 
 package android.media;
 
+import android.media.AudioRecordConfiguration;
+
 /**
  * AIDL for the RecordingActivity monitor in AudioService to signal audio recording updates.
  *
@@ -23,6 +25,6 @@ package android.media;
  */
 oneway interface IRecordingConfigDispatcher {
 
-    void dispatchRecordingConfigChange();
+    void dispatchRecordingConfigChange(in AudioRecordConfiguration[] configs);
 
 }
index f1f8437..4c6f0e6 100644 (file)
@@ -2221,7 +2221,10 @@ final public class MediaCodec {
         public int mode;
 
         /**
-         * Metadata describing encryption pattern for the protected bytes in a subsample.
+         * Metadata describing an encryption pattern for the protected bytes in
+         * a subsample.  An encryption pattern consists of a repeating sequence
+         * of crypto blocks comprised of a number of encrypted blocks followed
+         * by a number of unencrypted, or skipped, blocks.
          */
         public final static class Pattern {
             /**
@@ -2273,6 +2276,10 @@ final public class MediaCodec {
          */
         private Pattern pattern;
 
+        /**
+         * Set the subsample count, clear/encrypted sizes, key, IV and mode fields of
+         * a {@link MediaCodec.CryptoInfo} instance.
+         */
         public void set(
                 int newNumSubSamples,
                 @NonNull int[] newNumBytesOfClearData,
@@ -2289,6 +2296,10 @@ final public class MediaCodec {
             pattern = new Pattern(0, 0);
         }
 
+        /**
+         * Set the encryption pattern on a {@link MediaCodec.CryptoInfo} instance.
+         * See {@link MediaCodec.CryptoInfo.Pattern}.
+         */
         public void setPattern(Pattern newPattern) {
             pattern = newPattern;
         }
@@ -3339,14 +3350,6 @@ final public class MediaCodec {
         }
 
 
-        private int readInt(@NonNull ByteBuffer buffer, boolean asLong) {
-            if (asLong) {
-                return (int)buffer.getLong();
-            } else {
-                return buffer.getInt();
-            }
-        }
-
         public MediaImage(
                 @NonNull ByteBuffer buffer, @NonNull ByteBuffer info, boolean readOnly,
                 long timestamp, int xOffset, int yOffset, @Nullable Rect cropRect) {
@@ -3361,39 +3364,46 @@ final public class MediaCodec {
             mYOffset = yOffset;
             mInfo = info;
 
-            // read media-info.  the size of media info can be 80 or 156/160 depending on
-            // whether it was created on a 32- or 64-bit process.  See MediaImage
-            if (info.remaining() == 80 || info.remaining() == 156 || info.remaining() == 160) {
-                boolean sizeIsLong = info.remaining() != 80;
-                int type = readInt(info, info.remaining() == 160);
+            // read media-info.  See MediaImage2
+            if (info.remaining() == 104) {
+                int type = info.getInt();
                 if (type != TYPE_YUV) {
                     throw new UnsupportedOperationException("unsupported type: " + type);
                 }
-                int numPlanes = readInt(info, sizeIsLong);
+                int numPlanes = info.getInt();
                 if (numPlanes != 3) {
                     throw new RuntimeException("unexpected number of planes: " + numPlanes);
                 }
-                mWidth = readInt(info, sizeIsLong);
-                mHeight = readInt(info, sizeIsLong);
+                mWidth = info.getInt();
+                mHeight = info.getInt();
                 if (mWidth < 1 || mHeight < 1) {
                     throw new UnsupportedOperationException(
                             "unsupported size: " + mWidth + "x" + mHeight);
                 }
-                int bitDepth = readInt(info, sizeIsLong);
+                int bitDepth = info.getInt();
                 if (bitDepth != 8) {
                     throw new UnsupportedOperationException("unsupported bit depth: " + bitDepth);
                 }
+                int bitDepthAllocated = info.getInt();
+                if (bitDepthAllocated != 8) {
+                    throw new UnsupportedOperationException(
+                            "unsupported allocated bit depth: " + bitDepthAllocated);
+                }
                 mPlanes = new MediaPlane[numPlanes];
                 for (int ix = 0; ix < numPlanes; ix++) {
-                    int planeOffset = readInt(info, sizeIsLong);
-                    int colInc = readInt(info, sizeIsLong);
-                    int rowInc = readInt(info, sizeIsLong);
-                    int horiz = readInt(info, sizeIsLong);
-                    int vert = readInt(info, sizeIsLong);
+                    int planeOffset = info.getInt();
+                    int colInc = info.getInt();
+                    int rowInc = info.getInt();
+                    int horiz = info.getInt();
+                    int vert = info.getInt();
                     if (horiz != vert || horiz != (ix == 0 ? 1 : 2)) {
                         throw new UnsupportedOperationException("unexpected subsampling: "
                                 + horiz + "x" + vert + " on plane " + ix);
                     }
+                    if (colInc < 1 || rowInc < 1) {
+                        throw new UnsupportedOperationException("unexpected strides: "
+                                + colInc + " pixel, " + rowInc + " row on plane " + ix);
+                    }
 
                     buffer.clear();
                     buffer.position(mBuffer.position() + planeOffset
index d9690f0..b1c1b79 100644 (file)
@@ -2231,6 +2231,7 @@ public final class MediaCodecInfo {
                     switch (profileLevel.profile) {
                         case CodecProfileLevel.HEVCProfileMain:
                         case CodecProfileLevel.HEVCProfileMain10:
+                        case CodecProfileLevel.HEVCProfileMain10HDR10:
                             break;
                         default:
                             Log.w(TAG, "Unrecognized profile "
@@ -2632,8 +2633,9 @@ public final class MediaCodecInfo {
         public static final int VP9Level62 = 0x1000;
 
         // from OMX_VIDEO_HEVCPROFILETYPE
-        public static final int HEVCProfileMain   = 0x01;
-        public static final int HEVCProfileMain10 = 0x02;
+        public static final int HEVCProfileMain        = 0x01;
+        public static final int HEVCProfileMain10      = 0x02;
+        public static final int HEVCProfileMain10HDR10 = 0x1000;
 
         // from OMX_VIDEO_HEVCLEVELTYPE
         public static final int HEVCMainTierLevel1  = 0x1;
index 646ab4e..a0e2481 100644 (file)
@@ -644,6 +644,21 @@ public final class MediaFormat {
     /** Full range. Y, Cr and Cb component values range from 0 to 255 for 8-bit content. */
     public static final int COLOR_RANGE_FULL = 1;
 
+    /**
+     * A key describing a unique ID for the content of a media track.
+     *
+     * <p>This key is used by {@link MediaExtractor}. Some extractors provide multiple encodings
+     * of the same track (e.g. float audio tracks for FLAC and WAV may be expressed as two
+     * tracks via MediaExtractor: a normal PCM track for backward compatibility, and a float PCM
+     * track for added fidelity. Similarly, Dolby Vision extractor may provide a baseline SDR
+     * version of a DV track.) This key can be used to identify which MediaExtractor tracks refer
+     * to the same underlying content.
+     * </p>
+     *
+     * The associated value is an integer.
+     */
+    public static final String KEY_TRACK_ID = "track-id";
+
     /* package private */ MediaFormat(Map<String, Object> map) {
         mMap = map;
     }
index 39bcef5..722605f 100644 (file)
@@ -16,6 +16,7 @@
 package android.media;
 
 import android.annotation.NonNull;
+import android.annotation.StringDef;
 import android.content.ContentResolver;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -30,6 +31,8 @@ import android.util.ArrayMap;
 import android.util.Log;
 import android.util.SparseArray;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Set;
 
 /**
@@ -39,6 +42,40 @@ public final class MediaMetadata implements Parcelable {
     private static final String TAG = "MediaMetadata";
 
     /**
+     * @hide
+     */
+    @StringDef({METADATA_KEY_TITLE, METADATA_KEY_ARTIST, METADATA_KEY_ALBUM, METADATA_KEY_AUTHOR,
+            METADATA_KEY_WRITER, METADATA_KEY_COMPOSER, METADATA_KEY_COMPILATION,
+            METADATA_KEY_DATE, METADATA_KEY_GENRE, METADATA_KEY_ALBUM_ARTIST, METADATA_KEY_ART_URI,
+            METADATA_KEY_ALBUM_ART_URI, METADATA_KEY_DISPLAY_TITLE, METADATA_KEY_DISPLAY_SUBTITLE,
+            METADATA_KEY_DISPLAY_DESCRIPTION, METADATA_KEY_DISPLAY_ICON_URI,
+            METADATA_KEY_MEDIA_ID})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TextKey {}
+
+    /**
+     * @hide
+     */
+    @StringDef({METADATA_KEY_DURATION, METADATA_KEY_YEAR, METADATA_KEY_TRACK_NUMBER,
+            METADATA_KEY_NUM_TRACKS, METADATA_KEY_DISC_NUMBER})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface LongKey {}
+
+    /**
+     * @hide
+     */
+    @StringDef({METADATA_KEY_ART, METADATA_KEY_ALBUM_ART, METADATA_KEY_DISPLAY_ICON})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface BitmapKey {}
+
+    /**
+     * @hide
+     */
+    @StringDef({METADATA_KEY_USER_RATING, METADATA_KEY_RATING})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface RatingKey {}
+
+    /**
      * The title of the media.
      */
     public static final String METADATA_KEY_TITLE = "android.media.metadata.TITLE";
@@ -232,7 +269,7 @@ public final class MediaMetadata implements Parcelable {
      */
     public static final String METADATA_KEY_MEDIA_ID = "android.media.metadata.MEDIA_ID";
 
-    private static final String[] PREFERRED_DESCRIPTION_ORDER = {
+    private static final @TextKey String[] PREFERRED_DESCRIPTION_ORDER = {
             METADATA_KEY_TITLE,
             METADATA_KEY_ARTIST,
             METADATA_KEY_ALBUM,
@@ -242,13 +279,13 @@ public final class MediaMetadata implements Parcelable {
             METADATA_KEY_COMPOSER
     };
 
-    private static final String[] PREFERRED_BITMAP_ORDER = {
+    private static final @BitmapKey String[] PREFERRED_BITMAP_ORDER = {
             METADATA_KEY_DISPLAY_ICON,
             METADATA_KEY_ART,
             METADATA_KEY_ALBUM_ART
     };
 
-    private static final String[] PREFERRED_URI_ORDER = {
+    private static final @TextKey String[] PREFERRED_URI_ORDER = {
             METADATA_KEY_DISPLAY_ICON_URI,
             METADATA_KEY_ART_URI,
             METADATA_KEY_ALBUM_ART_URI
@@ -349,7 +386,7 @@ public final class MediaMetadata implements Parcelable {
      * @param key The key the value is stored under
      * @return a CharSequence value, or null
      */
-    public CharSequence getText(String key) {
+    public CharSequence getText(@TextKey String key) {
         return mBundle.getCharSequence(key);
     }
 
@@ -362,7 +399,7 @@ public final class MediaMetadata implements Parcelable {
      * @param key The key the value is stored under
      * @return a String value, or null
      */
-    public String getString(String key) {
+    public String getString(@TextKey String key) {
         CharSequence text = getText(key);
         if (text != null) {
             return text.toString();
@@ -377,7 +414,7 @@ public final class MediaMetadata implements Parcelable {
      * @param key The key the value is stored under
      * @return a long value
      */
-    public long getLong(String key) {
+    public long getLong(@LongKey String key) {
         return mBundle.getLong(key, 0);
     }
 
@@ -388,7 +425,7 @@ public final class MediaMetadata implements Parcelable {
      * @param key The key the value is stored under
      * @return A {@link Rating} or null
      */
-    public Rating getRating(String key) {
+    public Rating getRating(@RatingKey String key) {
         Rating rating = null;
         try {
             rating = mBundle.getParcelable(key);
@@ -406,7 +443,7 @@ public final class MediaMetadata implements Parcelable {
      * @param key The key the value is stored under
      * @return A {@link Bitmap} or null
      */
-    public Bitmap getBitmap(String key) {
+    public Bitmap getBitmap(@BitmapKey String key) {
         Bitmap bmp = null;
         try {
             bmp = mBundle.getParcelable(key);
@@ -612,7 +649,7 @@ public final class MediaMetadata implements Parcelable {
          * @param value The CharSequence value to store
          * @return The Builder to allow chaining
          */
-        public Builder putText(String key, CharSequence value) {
+        public Builder putText(@TextKey String key, CharSequence value) {
             if (METADATA_KEYS_TYPE.containsKey(key)) {
                 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
                     throw new IllegalArgumentException("The " + key
@@ -654,7 +691,7 @@ public final class MediaMetadata implements Parcelable {
          * @param value The String value to store
          * @return The Builder to allow chaining
          */
-        public Builder putString(String key, String value) {
+        public Builder putString(@TextKey String key, String value) {
             if (METADATA_KEYS_TYPE.containsKey(key)) {
                 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_TEXT) {
                     throw new IllegalArgumentException("The " + key
@@ -681,7 +718,7 @@ public final class MediaMetadata implements Parcelable {
          * @param value The long value to store
          * @return The Builder to allow chaining
          */
-        public Builder putLong(String key, long value) {
+        public Builder putLong(@LongKey String key, long value) {
             if (METADATA_KEYS_TYPE.containsKey(key)) {
                 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_LONG) {
                     throw new IllegalArgumentException("The " + key
@@ -705,7 +742,7 @@ public final class MediaMetadata implements Parcelable {
          * @param value The Rating value to store
          * @return The Builder to allow chaining
          */
-        public Builder putRating(String key, Rating value) {
+        public Builder putRating(@RatingKey String key, Rating value) {
             if (METADATA_KEYS_TYPE.containsKey(key)) {
                 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_RATING) {
                     throw new IllegalArgumentException("The " + key
@@ -734,7 +771,7 @@ public final class MediaMetadata implements Parcelable {
          * @param value The Bitmap to store
          * @return The Builder to allow chaining
          */
-        public Builder putBitmap(String key, Bitmap value) {
+        public Builder putBitmap(@BitmapKey String key, Bitmap value) {
             if (METADATA_KEYS_TYPE.containsKey(key)) {
                 if (METADATA_KEYS_TYPE.get(key) != METADATA_TYPE_BITMAP) {
                     throw new IllegalArgumentException("The " + key
index 8618ec9..ebe509c 100644 (file)
@@ -127,7 +127,8 @@ final public class MediaMuxer {
      * @param path The path of the output media file.
      * @param format The format of the output media file.
      * @see android.media.MediaMuxer.OutputFormat
-     * @throws IOException if failed to open the file for write
+     * @throws IllegalArgumentException if path is invalid or format is not supported.
+     * @throws IOException if failed to open the file for write.
      */
     public MediaMuxer(@NonNull String path, @Format int format) throws IOException {
         if (path == null) {
@@ -165,6 +166,8 @@ final public class MediaMuxer {
      * By default, the rotation degree is 0.</p>
      * @param degrees the angle to be rotated clockwise in degrees.
      * The supported angles are 0, 90, 180, and 270 degrees.
+     * @throws IllegalArgumentException if degree is not supported.
+     * @throws IllegalStateException If this method is called after {@link #start}.
      */
     public void setOrientationHint(int degrees) {
         if (degrees != 0 && degrees != 90  && degrees != 180 && degrees != 270) {
@@ -217,6 +220,8 @@ final public class MediaMuxer {
      * Starts the muxer.
      * <p>Make sure this is called after {@link #addTrack} and before
      * {@link #writeSampleData}.</p>
+     * @throws IllegalStateException If this method is called after {@link #start}
+     * or Muxer is released
      */
     public void start() {
         if (mNativeObject == 0) {
@@ -233,6 +238,7 @@ final public class MediaMuxer {
     /**
      * Stops the muxer.
      * <p>Once the muxer stops, it can not be restarted.</p>
+     * @throws IllegalStateException if muxer is in the wrong state.
      */
     public void stop() {
         if (mState == MUXER_STATE_STARTED) {
@@ -264,6 +270,8 @@ final public class MediaMuxer {
      *               MediaFormat.
      * @return The track index for this newly added track, and it should be used
      * in the {@link #writeSampleData}.
+     * @throws IllegalArgumentException if format is invalid.
+     * @throws IllegalStateException if muxer is in the wrong state.
      */
     public int addTrack(@NonNull MediaFormat format) {
         if (format == null) {
@@ -314,6 +322,8 @@ final public class MediaMuxer {
      * @param byteBuf The encoded sample.
      * @param trackIndex The track index for this sample.
      * @param bufferInfo The buffer information related to this sample.
+     * @throws IllegalArgumentException if trackIndex, byteBuf or bufferInfo is  invalid.
+     * @throws IllegalStateException if muxer is in wrong state.
      * MediaMuxer uses the flags provided in {@link MediaCodec.BufferInfo},
      * to signal sync frames.
      */
index adf8551..b78869e 100644 (file)
@@ -2845,13 +2845,17 @@ public class MediaPlayer implements SubtitleController.Listener
                             MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, MEDIA_ERROR_UNSUPPORTED, null);
                     sendMessage(msg2);
                 }
-                if (mOnPreparedListener != null)
-                    mOnPreparedListener.onPrepared(mMediaPlayer);
+                OnPreparedListener onPreparedListener = mOnPreparedListener;
+                if (onPreparedListener != null)
+                    onPreparedListener.onPrepared(mMediaPlayer);
                 return;
 
             case MEDIA_PLAYBACK_COMPLETE:
-                if (mOnCompletionListener != null)
-                    mOnCompletionListener.onCompletion(mMediaPlayer);
+                {
+                    OnCompletionListener onCompletionListener = mOnCompletionListener;
+                    if (onCompletionListener != null)
+                        onCompletionListener.onCompletion(mMediaPlayer);
+                }
                 stayAwake(false);
                 return;
 
@@ -2875,13 +2879,15 @@ public class MediaPlayer implements SubtitleController.Listener
                 break;
 
             case MEDIA_BUFFERING_UPDATE:
-                if (mOnBufferingUpdateListener != null)
-                    mOnBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1);
+                OnBufferingUpdateListener onBufferingUpdateListener = mOnBufferingUpdateListener;
+                if (onBufferingUpdateListener != null)
+                    onBufferingUpdateListener.onBufferingUpdate(mMediaPlayer, msg.arg1);
                 return;
 
             case MEDIA_SEEK_COMPLETE:
-                if (mOnSeekCompleteListener != null) {
-                    mOnSeekCompleteListener.onSeekComplete(mMediaPlayer);
+                OnSeekCompleteListener onSeekCompleteListener = mOnSeekCompleteListener;
+                if (onSeekCompleteListener != null) {
+                    onSeekCompleteListener.onSeekComplete(mMediaPlayer);
                 }
                 // fall through
 
@@ -2895,8 +2901,9 @@ public class MediaPlayer implements SubtitleController.Listener
                 return;
 
             case MEDIA_SET_VIDEO_SIZE:
-                if (mOnVideoSizeChangedListener != null) {
-                    mOnVideoSizeChangedListener.onVideoSizeChanged(
+                OnVideoSizeChangedListener onVideoSizeChangedListener = mOnVideoSizeChangedListener;
+                if (onVideoSizeChangedListener != null) {
+                    onVideoSizeChangedListener.onVideoSizeChanged(
                         mMediaPlayer, msg.arg1, msg.arg2);
                 }
                 return;
@@ -2904,11 +2911,15 @@ public class MediaPlayer implements SubtitleController.Listener
             case MEDIA_ERROR:
                 Log.e(TAG, "Error (" + msg.arg1 + "," + msg.arg2 + ")");
                 boolean error_was_handled = false;
-                if (mOnErrorListener != null) {
-                    error_was_handled = mOnErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2);
+                OnErrorListener onErrorListener = mOnErrorListener;
+                if (onErrorListener != null) {
+                    error_was_handled = onErrorListener.onError(mMediaPlayer, msg.arg1, msg.arg2);
                 }
-                if (mOnCompletionListener != null && ! error_was_handled) {
-                    mOnCompletionListener.onCompletion(mMediaPlayer);
+                {
+                    OnCompletionListener onCompletionListener = mOnCompletionListener;
+                    if (onCompletionListener != null && ! error_was_handled) {
+                        onCompletionListener.onCompletion(mMediaPlayer);
+                    }
                 }
                 stayAwake(false);
                 return;
@@ -2944,47 +2955,52 @@ public class MediaPlayer implements SubtitleController.Listener
                     break;
                 }
 
-                if (mOnInfoListener != null) {
-                    mOnInfoListener.onInfo(mMediaPlayer, msg.arg1, msg.arg2);
+                OnInfoListener onInfoListener = mOnInfoListener;
+                if (onInfoListener != null) {
+                    onInfoListener.onInfo(mMediaPlayer, msg.arg1, msg.arg2);
                 }
                 // No real default action so far.
                 return;
             case MEDIA_TIMED_TEXT:
-                if (mOnTimedTextListener == null)
+                OnTimedTextListener onTimedTextListener = mOnTimedTextListener;
+                if (onTimedTextListener == null)
                     return;
                 if (msg.obj == null) {
-                    mOnTimedTextListener.onTimedText(mMediaPlayer, null);
+                    onTimedTextListener.onTimedText(mMediaPlayer, null);
                 } else {
                     if (msg.obj instanceof Parcel) {
                         Parcel parcel = (Parcel)msg.obj;
                         TimedText text = new TimedText(parcel);
                         parcel.recycle();
-                        mOnTimedTextListener.onTimedText(mMediaPlayer, text);
+                        onTimedTextListener.onTimedText(mMediaPlayer, text);
                     }
                 }
                 return;
 
             case MEDIA_SUBTITLE_DATA:
-                if (mOnSubtitleDataListener == null) {
+                OnSubtitleDataListener onSubtitleDataListener = mOnSubtitleDataListener;
+                if (onSubtitleDataListener == null) {
                     return;
                 }
                 if (msg.obj instanceof Parcel) {
                     Parcel parcel = (Parcel) msg.obj;
                     SubtitleData data = new SubtitleData(parcel);
                     parcel.recycle();
-                    mOnSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
+                    onSubtitleDataListener.onSubtitleData(mMediaPlayer, data);
                 }
                 return;
 
             case MEDIA_META_DATA:
-                if (mOnTimedMetaDataAvailableListener == null) {
+                OnTimedMetaDataAvailableListener onTimedMetaDataAvailableListener =
+                    mOnTimedMetaDataAvailableListener;
+                if (onTimedMetaDataAvailableListener == null) {
                     return;
                 }
                 if (msg.obj instanceof Parcel) {
                     Parcel parcel = (Parcel) msg.obj;
                     TimedMetaData data = TimedMetaData.createTimedMetaDataFromParcel(parcel);
                     parcel.recycle();
-                    mOnTimedMetaDataAvailableListener.onTimedMetaDataAvailable(mMediaPlayer, data);
+                    onTimedMetaDataAvailableListener.onTimedMetaDataAvailable(mMediaPlayer, data);
                 }
                 return;
 
index bcc2b40..d8e0d6d 100644 (file)
@@ -1547,18 +1547,30 @@ public class MediaRouter {
 
         private Object mTag;
 
+        /** @hide */
+        @IntDef({PLAYBACK_TYPE_LOCAL, PLAYBACK_TYPE_REMOTE})
+        @Retention(RetentionPolicy.SOURCE)
+        public @interface PlaybackType {}
+
         /**
          * The default playback type, "local", indicating the presentation of the media is happening
          * on the same device (e&#46;g&#46; a phone, a tablet) as where it is controlled from.
          * @see #getPlaybackType()
          */
         public final static int PLAYBACK_TYPE_LOCAL = 0;
+
         /**
          * A playback type indicating the presentation of the media is happening on
          * a different device (i&#46;e&#46; the remote device) than where it is controlled from.
          * @see #getPlaybackType()
          */
         public final static int PLAYBACK_TYPE_REMOTE = 1;
+
+        /** @hide */
+         @IntDef({PLAYBACK_VOLUME_FIXED,PLAYBACK_VOLUME_VARIABLE})
+         @Retention(RetentionPolicy.SOURCE)
+         private @interface PlaybackVolume {}
+
         /**
          * Playback information indicating the playback volume is fixed, i&#46;e&#46; it cannot be
          * controlled from this object. An example of fixed playback volume is a remote player,
@@ -1783,6 +1795,7 @@ public class MediaRouter {
          * @return the type of playback associated with this route
          * @see UserRouteInfo#setPlaybackType(int)
          */
+        @PlaybackType
         public int getPlaybackType() {
             return mPlaybackType;
         }
@@ -1874,6 +1887,7 @@ public class MediaRouter {
          * @return how volume is handling on the route
          * @see UserRouteInfo#setVolumeHandling(int)
          */
+        @PlaybackVolume
         public int getVolumeHandling() {
             return mVolumeHandling;
         }
@@ -2164,7 +2178,7 @@ public class MediaRouter {
          *    ({@link RouteInfo#PLAYBACK_TYPE_REMOTE}).
          * @param type
          */
-        public void setPlaybackType(int type) {
+        public void setPlaybackType(@RouteInfo.PlaybackType int type) {
             if (mPlaybackType != type) {
                 mPlaybackType = type;
                 configureSessionVolume();
@@ -2177,7 +2191,7 @@ public class MediaRouter {
          * ({@link RouteInfo#PLAYBACK_VOLUME_VARIABLE}).
          * @param volumeHandling
          */
-        public void setVolumeHandling(int volumeHandling) {
+        public void setVolumeHandling(@RouteInfo.PlaybackVolume int volumeHandling) {
             if (mVolumeHandling != volumeHandling) {
                 mVolumeHandling = volumeHandling;
                 configureSessionVolume();
@@ -2268,7 +2282,8 @@ public class MediaRouter {
                 return;
             }
             if (mPlaybackType == RemoteControlClient.PLAYBACK_TYPE_REMOTE) {
-                int volumeControl = VolumeProvider.VOLUME_CONTROL_FIXED;
+                @VolumeProvider.ControlType int volumeControl =
+                        VolumeProvider.VOLUME_CONTROL_FIXED;
                 switch (mVolumeHandling) {
                     case RemoteControlClient.PLAYBACK_VOLUME_VARIABLE:
                         volumeControl = VolumeProvider.VOLUME_CONTROL_ABSOLUTE;
@@ -2294,7 +2309,8 @@ public class MediaRouter {
 
         class SessionVolumeProvider extends VolumeProvider {
 
-            public SessionVolumeProvider(int volumeControl, int maxVolume, int currentVolume) {
+            public SessionVolumeProvider(@VolumeProvider.ControlType int volumeControl,
+                    int maxVolume, int currentVolume) {
                 super(volumeControl, maxVolume, currentVolume);
             }
 
index a518bb4..04d5364 100644 (file)
 
 package android.media;
 
+import android.annotation.IntDef;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.util.Log;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A class to encapsulate rating information used as content metadata.
  * A rating is defined by its rating style (see {@link #RATING_HEART},
@@ -32,6 +36,21 @@ public final class Rating implements Parcelable {
     private final static String TAG = "Rating";
 
     /**
+     * @hide
+     */
+    @IntDef({RATING_NONE, RATING_HEART, RATING_THUMB_UP_DOWN, RATING_3_STARS, RATING_4_STARS,
+            RATING_5_STARS, RATING_PERCENTAGE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Style {}
+
+    /**
+     * @hide
+     */
+    @IntDef({RATING_3_STARS, RATING_4_STARS, RATING_5_STARS})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface StarStyle {}
+
+    /**
      * Indicates a rating style is not supported. A Rating will never have this
      * type, but can be used by other classes to indicate they do not support
      * Rating.
@@ -75,7 +94,7 @@ public final class Rating implements Parcelable {
 
     private final float mRatingValue;
 
-    private Rating(int ratingStyle, float rating) {
+    private Rating(@Style int ratingStyle, float rating) {
         mRatingStyle = ratingStyle;
         mRatingValue = rating;
     }
@@ -124,7 +143,7 @@ public final class Rating implements Parcelable {
      *    or {@link #RATING_PERCENTAGE}.
      * @return null if an invalid rating style is passed, a new Rating instance otherwise.
      */
-    public static Rating newUnratedRating(int ratingStyle) {
+    public static Rating newUnratedRating(@Style int ratingStyle) {
         switch(ratingStyle) {
             case RATING_HEART:
             case RATING_THUMB_UP_DOWN:
@@ -172,7 +191,7 @@ public final class Rating implements Parcelable {
      * @return null if the rating style is invalid, or the rating is out of range,
      *     a new Rating instance otherwise.
      */
-    public static Rating newStarRating(int starRatingStyle, float starRating) {
+    public static Rating newStarRating(@StarStyle int starRatingStyle, float starRating) {
         float maxRating = -1.0f;
         switch(starRatingStyle) {
             case RATING_3_STARS:
@@ -225,6 +244,7 @@ public final class Rating implements Parcelable {
      *    {@link #RATING_3_STARS}, {@link #RATING_4_STARS}, {@link #RATING_5_STARS},
      *    or {@link #RATING_PERCENTAGE}.
      */
+    @Style
     public int getRatingStyle() {
         return mRatingStyle;
     }
@@ -285,4 +305,4 @@ public final class Rating implements Parcelable {
             return mRatingValue;
         }
     }
-}
\ No newline at end of file
+}
index 5d1e004..1c017c5 100644 (file)
  */
 package android.media;
 
+import android.annotation.IntDef;
 import android.media.session.MediaSession;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Handles requests to adjust or set the volume on a session. This is also used
  * to push volume updates back to the session. The provider must call
@@ -26,6 +30,14 @@ import android.media.session.MediaSession;
  * {@link MediaSession#setPlaybackToRemote}.
  */
 public abstract class VolumeProvider {
+
+    /**
+     * @hide
+     */
+    @IntDef({VOLUME_CONTROL_FIXED, VOLUME_CONTROL_RELATIVE, VOLUME_CONTROL_ABSOLUTE})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ControlType {}
+
     /**
      * The volume is fixed and can not be modified. Requests to change volume
      * should be ignored.
@@ -61,7 +73,7 @@ public abstract class VolumeProvider {
      * @param maxVolume The maximum allowed volume.
      * @param currentVolume The current volume on the output.
      */
-    public VolumeProvider(int volumeControl, int maxVolume, int currentVolume) {
+    public VolumeProvider(@ControlType int volumeControl, int maxVolume, int currentVolume) {
         mControlType = volumeControl;
         mMaxVolume = maxVolume;
         mCurrentVolume = currentVolume;
@@ -72,6 +84,7 @@ public abstract class VolumeProvider {
      *
      * @return The volume control type for this volume provider
      */
+    @ControlType
     public final int getVolumeControl() {
         return mControlType;
     }
@@ -145,4 +158,4 @@ public abstract class VolumeProvider {
     public static abstract class Callback {
         public abstract void onVolumeChanged(VolumeProvider volumeProvider);
     }
-}
\ No newline at end of file
+}
index 9e67c15..ada0e2c 100644 (file)
@@ -633,7 +633,6 @@ public final class MediaBrowser {
                     return;
                 }
 
-                List<MediaItem> data = list == null ? null : list.getList();
                 if (DBG) {
                     Log.d(TAG, "onLoadChildren for " + mServiceComponent + " id=" + parentId);
                 }
@@ -644,10 +643,19 @@ public final class MediaBrowser {
                     // Tell the app.
                     SubscriptionCallback subscriptionCallback = subscription.getCallback(options);
                     if (subscriptionCallback != null) {
+                        List<MediaItem> data = list == null ? null : list.getList();
                         if (options == null) {
-                            subscriptionCallback.onChildrenLoaded(parentId, data);
+                            if (data == null) {
+                                subscriptionCallback.onError(parentId);
+                            } else {
+                                subscriptionCallback.onChildrenLoaded(parentId, data);
+                            }
                         } else {
-                            subscriptionCallback.onChildrenLoaded(parentId, data, options);
+                            if (data == null) {
+                                subscriptionCallback.onError(parentId, options);
+                            } else {
+                                subscriptionCallback.onChildrenLoaded(parentId, data, options);
+                            }
                         }
                         return;
                     }
@@ -848,21 +856,21 @@ public final class MediaBrowser {
          * Called when the list of children is loaded or updated.
          *
          * @param parentId The media id of the parent media item.
-         * @param children The children which were loaded, or null if the id is invalid.
+         * @param children The children which were loaded.
          */
-        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children) {
+        public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children) {
         }
 
         /**
          * Called when the list of children is loaded or updated.
          *
          * @param parentId The media id of the parent media item.
-         * @param children The children which were loaded, or null if the id is invalid.
+         * @param children The children which were loaded.
          * @param options A bundle of service-specific arguments sent to the media
          *            browse service. The contents of this bundle may affect the
          *            information returned when browsing.
          */
-        public void onChildrenLoaded(@NonNull String parentId, List<MediaItem> children,
+        public void onChildrenLoaded(@NonNull String parentId, @NonNull List<MediaItem> children,
                 @NonNull Bundle options) {
         }
 
index 266b0d9..07c8ae8 100644 (file)
@@ -186,8 +186,7 @@ public final class MidiManager {
         try {
             mService.registerListener(mToken, deviceListener);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in registerDeviceListener");
-            return;
+            throw e.rethrowFromSystemServer();
         }
         mDeviceListeners.put(callback, deviceListener);
     }
@@ -203,7 +202,7 @@ public final class MidiManager {
             try {
                 mService.unregisterListener(mToken, deviceListener);
             } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException in unregisterDeviceListener");
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -217,8 +216,7 @@ public final class MidiManager {
         try {
            return mService.getDevices();
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in getDevices");
-            return new MidiDeviceInfo[0];
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -267,7 +265,7 @@ public final class MidiManager {
         try {
             mService.openDevice(mToken, deviceInfo, callback);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in openDevice");
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -306,7 +304,7 @@ public final class MidiManager {
         try {
             mService.openBluetoothDevice(mToken, bluetoothDevice, callback);
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in openDevice");
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -326,8 +324,7 @@ public final class MidiManager {
             }
             return server;
         } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in createVirtualDevice");
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 }
index 0bd1713..7f9653d 100644 (file)
@@ -469,7 +469,7 @@ public final class MediaSession {
      * <li>{@link Rating#RATING_THUMB_UP_DOWN}</li>
      * </ul>
      */
-    public void setRatingType(int type) {
+    public void setRatingType(@Rating.Style int type) {
         try {
             mBinder.setRatingType(type);
         } catch (RemoteException e) {
index 1485cd7..8283c8b 100644 (file)
@@ -16,6 +16,7 @@
 package android.media.session;
 
 import android.annotation.DrawableRes;
+import android.annotation.IntDef;
 import android.annotation.Nullable;
 import android.media.RemoteControlClient;
 import android.os.Bundle;
@@ -26,6 +27,9 @@ import android.text.TextUtils;
 import java.util.ArrayList;
 import java.util.List;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Playback state for a {@link MediaSession}. This includes a state like
  * {@link PlaybackState#STATE_PLAYING}, the current playback position,
@@ -35,6 +39,17 @@ public final class PlaybackState implements Parcelable {
     private static final String TAG = "PlaybackState";
 
     /**
+     * @hide
+     */
+    @IntDef(flag=true, value={ACTION_STOP, ACTION_PAUSE, ACTION_PLAY, ACTION_REWIND,
+            ACTION_SKIP_TO_PREVIOUS, ACTION_SKIP_TO_NEXT, ACTION_FAST_FORWARD, ACTION_SET_RATING,
+            ACTION_SEEK_TO, ACTION_PLAY_PAUSE, ACTION_PLAY_FROM_MEDIA_ID, ACTION_PLAY_FROM_SEARCH,
+            ACTION_SKIP_TO_QUEUE_ITEM, ACTION_PLAY_FROM_URI, ACTION_PREPARE,
+            ACTION_PREPARE_FROM_MEDIA_ID, ACTION_PREPARE_FROM_SEARCH, ACTION_PREPARE_FROM_URI})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Actions {}
+
+    /**
      * Indicates this session supports the stop command.
      *
      * @see Builder#setActions(long)
@@ -161,6 +176,15 @@ public final class PlaybackState implements Parcelable {
     public static final long ACTION_PREPARE_FROM_URI = 1 << 17;
 
     /**
+     * @hide
+     */
+    @IntDef({STATE_NONE, STATE_STOPPED, STATE_PAUSED, STATE_PLAYING, STATE_FAST_FORWARDING,
+            STATE_REWINDING, STATE_BUFFERING, STATE_ERROR, STATE_CONNECTING,
+            STATE_SKIPPING_TO_PREVIOUS, STATE_SKIPPING_TO_NEXT, STATE_SKIPPING_TO_QUEUE_ITEM})
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface State {}
+
+    /**
      * This is the default playback state and indicates that no media has been
      * added yet, or the performer has been reset and has no content to play.
      *
@@ -349,9 +373,11 @@ public final class PlaybackState implements Parcelable {
      * <li> {@link PlaybackState#STATE_SKIPPING_TO_QUEUE_ITEM}</li>
      * </ul>
      */
+    @State
     public int getState() {
         return mState;
     }
+
     /**
      * Get the current playback position in ms.
      */
@@ -403,6 +429,7 @@ public final class PlaybackState implements Parcelable {
      * <li> {@link PlaybackState#ACTION_PREPARE_FROM_URI}</li>
      * </ul>
      */
+    @Actions
     public long getActions() {
         return mActions;
     }
@@ -866,7 +893,8 @@ public final class PlaybackState implements Parcelable {
          *            timebase that the position was updated at.
          * @return this
          */
-        public Builder setState(int state, long position, float playbackSpeed, long updateTime) {
+        public Builder setState(@State int state, long position, float playbackSpeed,
+                long updateTime) {
             mState = state;
             mPosition = position;
             mUpdateTime = updateTime;
@@ -907,7 +935,7 @@ public final class PlaybackState implements Parcelable {
          *            normal playback.
          * @return this
          */
-        public Builder setState(int state, long position, float playbackSpeed) {
+        public Builder setState(@State int state, long position, float playbackSpeed) {
             return setState(state, position, playbackSpeed, SystemClock.elapsedRealtime());
         }
 
@@ -938,7 +966,7 @@ public final class PlaybackState implements Parcelable {
          * @param actions The set of actions allowed.
          * @return this
          */
-        public Builder setActions(long actions) {
+        public Builder setActions(@Actions long actions) {
             mActions = actions;
             return this;
         }
index 4fd3310..fdd7fc2 100644 (file)
@@ -69,6 +69,7 @@ public final class SoundTriggerManager {
         try {
             mSoundTriggerService.updateSoundModel(model.getGenericSoundModel());
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -81,7 +82,7 @@ public final class SoundTriggerManager {
             return new Model(mSoundTriggerService.getSoundModel(
                     new ParcelUuid(soundModelId)));
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -92,6 +93,7 @@ public final class SoundTriggerManager {
         try {
             mSoundTriggerService.deleteSoundModel(new ParcelUuid(soundModelId));
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
index 5dd4e85..72f8b57 100644 (file)
@@ -45,7 +45,7 @@ oneway interface ITvInputClient {
     void onTimeShiftCurrentPositionChanged(long timeMs, int seq);
 
     // For the recording session
-    void onTuned(int seq);
+    void onTuned(int seq, in Uri channelUri);
     void onRecordingStopped(in Uri recordedProgramUri, int seq);
     void onError(int error, int seq);
 }
index 60d6f0d..af76f90 100644 (file)
@@ -42,7 +42,7 @@ oneway interface ITvInputSessionCallback {
     void onTimeShiftCurrentPositionChanged(long timeMs);
 
     // For the recording session
-    void onTuned();
+    void onTuned(in Uri channelUri);
     void onRecordingStopped(in Uri recordedProgramUri);
     void onError(int error);
 }
index 6e0f5f2..63e3edc 100644 (file)
@@ -677,11 +677,12 @@ public final class TvInputInfo implements Parcelable {
          * Constructs a new builder for {@link TvInputInfo}.
          *
          * @param context A Context of the application package implementing this class.
-         * @param cls The component class that is to be used for the {@link TvInputService}.
+         * @param component The name of the application component to be used for the
+         *            {@link TvInputService}.
          */
-        public Builder(Context context, Class<?> cls) {
+        public Builder(Context context, ComponentName component) {
             mContext = context;
-            Intent intent = new Intent(TvInputService.SERVICE_INTERFACE).setClass(context, cls);
+            Intent intent = new Intent(TvInputService.SERVICE_INTERFACE).setComponent(component);
             mResolveInfo = context.getPackageManager().resolveService(intent,
                     PackageManager.GET_SERVICES | PackageManager.GET_META_DATA);
         }
index 2703b1a..0b0306c 100644 (file)
@@ -478,8 +478,10 @@ public final class TvInputManager {
         /**
          * This is called when the recording session has been tuned to the given channel and is
          * ready to start recording.
+         *
+         * @param channelUri The URI of a channel.
          */
-        void onTuned(Session session) {
+        void onTuned(Session session, Uri channelUri) {
         }
 
         // For the recording session only
@@ -653,11 +655,11 @@ public final class TvInputManager {
         }
 
         // For the recording session only
-        void postTuned() {
+        void postTuned(final Uri channelUri) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mSessionCallback.onTuned(mSession);
+                    mSessionCallback.onTuned(mSession, channelUri);
                 }
             });
         }
@@ -1013,14 +1015,14 @@ public final class TvInputManager {
             }
 
             @Override
-            public void onTuned(int seq) {
+            public void onTuned(int seq, Uri channelUri) {
                 synchronized (mSessionCallbackRecordMap) {
                     SessionCallbackRecord record = mSessionCallbackRecordMap.get(seq);
                     if (record == null) {
                         Log.e(TAG, "Callback not found for seq " + seq);
                         return;
                     }
-                    record.postTuned();
+                    record.postTuned(channelUri);
                 }
             }
 
@@ -1109,7 +1111,7 @@ public final class TvInputManager {
                 }
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "TvInputManager initialization failed", e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1122,7 +1124,7 @@ public final class TvInputManager {
         try {
             return mService.getTvInputList(mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1138,7 +1140,7 @@ public final class TvInputManager {
         try {
             return mService.getTvInputInfo(inputId, mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1155,7 +1157,7 @@ public final class TvInputManager {
         try {
             mService.updateTvInputInfo(inputInfo, mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException("Error trying to update " + inputInfo, e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1226,7 +1228,7 @@ public final class TvInputManager {
         try {
             return mService.isParentalControlsEnabled(mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1243,7 +1245,7 @@ public final class TvInputManager {
         try {
             mService.setParentalControlsEnabled(enabled, mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1258,7 +1260,7 @@ public final class TvInputManager {
         try {
             return mService.isRatingBlocked(rating.flattenToString(), mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1277,7 +1279,7 @@ public final class TvInputManager {
             }
             return ratings;
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1295,7 +1297,7 @@ public final class TvInputManager {
         try {
             mService.addBlockedRating(rating.flattenToString(), mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1313,7 +1315,7 @@ public final class TvInputManager {
         try {
             mService.removeBlockedRating(rating.flattenToString(), mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1326,7 +1328,7 @@ public final class TvInputManager {
         try {
             return mService.getTvContentRatingSystemList(mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1376,7 +1378,7 @@ public final class TvInputManager {
             try {
                 mService.createSession(mClient, inputId, isRecordingSession, seq, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
     }
@@ -1400,7 +1402,7 @@ public final class TvInputManager {
         try {
             return mService.getAvailableTvStreamConfigList(inputId, mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1418,7 +1420,7 @@ public final class TvInputManager {
         try {
             return mService.captureFrame(inputId, surface, config, mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1432,7 +1434,7 @@ public final class TvInputManager {
         try {
             return mService.isSingleSessionActive(mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1446,7 +1448,7 @@ public final class TvInputManager {
         try {
             return mService.getHardwareList();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1476,7 +1478,7 @@ public final class TvInputManager {
                 }
             }, info, mUserId));
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1490,7 +1492,7 @@ public final class TvInputManager {
         try {
             mService.releaseTvInputHardware(deviceId, hardware.getInterface(), mUserId);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1504,7 +1506,7 @@ public final class TvInputManager {
         try {
             return mService.getDvbDeviceList();
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1527,7 +1529,7 @@ public final class TvInputManager {
             }
             return mService.openDvbDevice(info, device);
         } catch (RemoteException e) {
-            throw new RuntimeException(e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1598,7 +1600,7 @@ public final class TvInputManager {
             try {
                 mService.releaseSession(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
 
             releaseInternal();
@@ -1618,7 +1620,7 @@ public final class TvInputManager {
             try {
                 mService.setMainSession(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1636,7 +1638,7 @@ public final class TvInputManager {
             try {
                 mService.setSurface(mToken, surface, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1658,7 +1660,7 @@ public final class TvInputManager {
             try {
                 mService.dispatchSurfaceChanged(mToken, format, width, height, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1679,7 +1681,7 @@ public final class TvInputManager {
                 }
                 mService.setVolume(mToken, volume, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1719,7 +1721,7 @@ public final class TvInputManager {
             try {
                 mService.tune(mToken, channelUri, params, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1736,7 +1738,7 @@ public final class TvInputManager {
             try {
                 mService.setCaptionEnabled(mToken, enabled, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1778,7 +1780,7 @@ public final class TvInputManager {
             try {
                 mService.selectTrack(mToken, type, trackId, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1926,7 +1928,7 @@ public final class TvInputManager {
             try {
                 mService.timeShiftPlay(mToken, recordedProgramUri, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1941,7 +1943,7 @@ public final class TvInputManager {
             try {
                 mService.timeShiftPause(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1956,7 +1958,7 @@ public final class TvInputManager {
             try {
                 mService.timeShiftResume(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1977,7 +1979,7 @@ public final class TvInputManager {
             try {
                 mService.timeShiftSeekTo(mToken, timeMs, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -1994,7 +1996,7 @@ public final class TvInputManager {
             try {
                 mService.timeShiftSetPlaybackParams(mToken, params, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2011,7 +2013,7 @@ public final class TvInputManager {
             try {
                 mService.timeShiftEnablePositionTracking(mToken, enable, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2029,7 +2031,7 @@ public final class TvInputManager {
             try {
                 mService.startRecording(mToken, programHint, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2044,7 +2046,7 @@ public final class TvInputManager {
             try {
                 mService.stopRecording(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2067,7 +2069,7 @@ public final class TvInputManager {
             try {
                 mService.sendAppPrivateCommand(mToken, action, data, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2095,7 +2097,7 @@ public final class TvInputManager {
             try {
                 mService.createOverlayView(mToken, view.getWindowToken(), frame, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2113,7 +2115,7 @@ public final class TvInputManager {
             try {
                 mService.relayoutOverlayView(mToken, frame, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2128,7 +2130,7 @@ public final class TvInputManager {
             try {
                 mService.removeOverlayView(mToken, mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
@@ -2144,7 +2146,7 @@ public final class TvInputManager {
             try {
                 mService.unblockContent(mToken, unblockedRating.flattenToString(), mUserId);
             } catch (RemoteException e) {
-                throw new RuntimeException(e);
+                throw e.rethrowFromSystemServer();
             }
         }
 
index db851a3..8fb58b5 100644 (file)
@@ -1567,8 +1567,10 @@ public abstract class TvInputService extends Service {
          * passed channel and call this method to indicate that it is now available for immediate
          * recording. When {@link #onStartRecording(Uri)} is called, recording must start with
          * minimal delay.
+         *
+         * @param channelUri The URI of a channel.
          */
-        public void notifyTuned() {
+        public void notifyTuned(Uri channelUri) {
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
                 @Override
@@ -1576,7 +1578,7 @@ public abstract class TvInputService extends Service {
                     try {
                         if (DEBUG) Log.d(TAG, "notifyTuned");
                         if (mSessionCallback != null) {
-                            mSessionCallback.onTuned();
+                            mSessionCallback.onTuned(channelUri);
                         }
                     } catch (RemoteException e) {
                         Log.w(TAG, "error in notifyTuned", e);
@@ -1679,7 +1681,7 @@ public abstract class TvInputService extends Service {
          * <p>The application may call this method before starting or after stopping recording, but
          * not during recording.
          *
-         * <p>The session must call {@link #notifyTuned()} if the tune request was fulfilled, or
+         * <p>The session must call {@link #notifyTuned(Uri)} if the tune request was fulfilled, or
          * {@link #notifyError(int)} otherwise.
          *
          * @param channelUri The URI of a channel.
@@ -1708,8 +1710,8 @@ public abstract class TvInputService extends Service {
          * Called when the application requests to start TV program recording. Recording must start
          * immediately when this method is called.
          *
-         * <p>The application may supply the URI for a TV program as a hint for filling in program
-         * specific data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
+         * <p>The application may supply the URI for a TV program for filling in program specific
+         * data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
          * A non-null {@code programHint} implies the started recording should be of that specific
          * program, whereas null {@code programHint} does not impose such a requirement and the
          * recording can span across multiple TV programs. In either case, the application must call
@@ -1718,10 +1720,10 @@ public abstract class TvInputService extends Service {
          * <p>The session must call {@link #notifyError(int)} if the start request cannot be
          * fulfilled.
          *
-         * @param programHint The URI for the TV program to record as a hint, built by
+         * @param programUri The URI for the TV program to record, built by
          *            {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
          */
-        public abstract void onStartRecording(@Nullable Uri programHint);
+        public abstract void onStartRecording(@Nullable Uri programUri);
 
         /**
          * Called when the application requests to stop TV program recording. Recording must stop
index 1c920f5..d48ea21 100644 (file)
@@ -76,11 +76,12 @@ public class TvRecordingClient {
      * during recording.
      *
      * <p>The recording session will respond by calling
-     * {@link RecordingCallback#onTuned()} if the tune request was fulfilled, or
+     * {@link RecordingCallback#onTuned(Uri)} if the tune request was fulfilled, or
      * {@link RecordingCallback#onError(int)} otherwise.
      *
      * @param inputId The ID of the TV input for the given channel.
      * @param channelUri The URI of a channel.
+     * @throws IllegalStateException If recording is already started.
      */
     public void tune(String inputId, Uri channelUri) {
         tune(inputId, channelUri, null);
@@ -102,6 +103,7 @@ public class TvRecordingClient {
      * @param inputId The ID of the TV input for the given channel.
      * @param channelUri The URI of a channel.
      * @param params Extra parameters.
+     * @throws IllegalStateException If recording is already started.
      * @hide
      */
     @SystemApi
@@ -152,8 +154,8 @@ public class TvRecordingClient {
      * immediately when this method is called. If the current recording session has not yet tuned to
      * any channel, this method throws an exception.
      *
-     * <p>The application may supply the URI for a TV program as a hint for filling in program
-     * specific data fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
+     * <p>The application may supply the URI for a TV program for filling in program specific data
+     * fields in the {@link android.media.tv.TvContract.RecordedPrograms} table.
      * A non-null {@code programHint} implies the started recording should be of that specific
      * program, whereas null {@code programHint} does not impose such a requirement and the
      * recording can span across multiple TV programs. In either case, the application must call
@@ -162,15 +164,16 @@ public class TvRecordingClient {
      * <p>The recording session will respond by calling {@link RecordingCallback#onError(int)} if
      * the start request cannot be fulfilled.
      *
-     * @param programHint The URI for the TV program to record as a hint, built by
+     * @param programUri The URI for the TV program to record, built by
      *            {@link TvContract#buildProgramUri(long)}. Can be {@code null}.
+     * @throws IllegalStateException If {@link #tune} request hasn't been handled yet.
      */
-    public void startRecording(@Nullable Uri programHint) {
+    public void startRecording(@Nullable Uri programUri) {
         if (!mIsTuned) {
             throw new IllegalStateException("startRecording failed - not yet tuned");
         }
         if (mSession != null) {
-            mSession.startRecording(programHint);
+            mSession.startRecording(programUri);
             mIsRecordingStarted = true;
         }
     }
@@ -245,8 +248,10 @@ public class TvRecordingClient {
         /**
          * This is called when the recording session has been tuned to the given channel and is
          * ready to start recording.
+         *
+         * @param channelUri The URI of a channel.
          */
-        public void onTuned() {
+        public void onTuned(Uri channelUri) {
         }
 
         /**
@@ -327,7 +332,7 @@ public class TvRecordingClient {
         }
 
         @Override
-        void onTuned(TvInputManager.Session session) {
+        void onTuned(TvInputManager.Session session, Uri channelUri) {
             if (DEBUG) {
                 Log.d(TAG, "onTuned()");
             }
@@ -336,7 +341,7 @@ public class TvRecordingClient {
                 return;
             }
             mIsTuned = true;
-            mCallback.onTuned();
+            mCallback.onTuned(channelUri);
         }
 
         @Override
index 29bcc19..760a2d1 100755 (executable)
@@ -713,8 +713,7 @@ public class MtpDatabase implements AutoCloseable {
         };
     }
 
-
-    private MtpPropertyList getObjectPropertyList(long handle, int format, long property,
+    private MtpPropertyList getObjectPropertyList(int handle, int format, int property,
                         int groupCode, int depth) {
         // FIXME - implement group support
         if (groupCode != 0) {
@@ -722,29 +721,29 @@ public class MtpDatabase implements AutoCloseable {
         }
 
         MtpPropertyGroup propertyGroup;
-        if (property == 0xFFFFFFFFL) {
-            if (format == 0 && handle > 0) {
+        if (property == 0xffffffff) {
+            if (format == 0 && handle != 0 && handle != 0xffffffff) {
                 // return properties based on the object's format
-                format = getObjectFormat((int)handle);
+                format = getObjectFormat(handle);
             }
-             propertyGroup = mPropertyGroupsByFormat.get(format);
-             if (propertyGroup == null) {
+            propertyGroup = mPropertyGroupsByFormat.get(format);
+            if (propertyGroup == null) {
                 int[] propertyList = getSupportedObjectProperties(format);
                 propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
                         mVolumeName, propertyList);
-                mPropertyGroupsByFormat.put(new Integer(format), propertyGroup);
+                mPropertyGroupsByFormat.put(format, propertyGroup);
             }
         } else {
-              propertyGroup = mPropertyGroupsByProperty.get(property);
-             if (propertyGroup == null) {
-                int[] propertyList = new int[] { (int)property };
-                propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
-                        mVolumeName, propertyList);
-                mPropertyGroupsByProperty.put(new Integer((int)property), propertyGroup);
+            propertyGroup = mPropertyGroupsByProperty.get(property);
+            if (propertyGroup == null) {
+                final int[] propertyList = new int[] { property };
+                propertyGroup = new MtpPropertyGroup(
+                        this, mMediaProvider, mVolumeName, propertyList);
+                mPropertyGroupsByProperty.put(property, propertyGroup);
             }
         }
 
-        return propertyGroup.getPropertyList((int)handle, format, depth);
+        return propertyGroup.getPropertyList(handle, format, depth);
     }
 
     private int renameFile(int handle, String newName) {
@@ -970,7 +969,7 @@ public class MtpDatabase implements AutoCloseable {
         Cursor c = null;
         try {
             c = mMediaProvider.query(mObjectsUri, FORMAT_PROJECTION,
-                            ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
+                            ID_WHERE, new String[] { Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 return c.getInt(1);
             } else {
index 480acd9..f593685 100644 (file)
@@ -45,6 +45,7 @@ import java.io.PrintWriter;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
 
@@ -120,8 +121,8 @@ public abstract class MediaBrowserService extends Service {
      * they are done. If more than one of those methods is called, an exception will
      * be thrown.
      *
-     * @see MediaBrowserService#onLoadChildren
-     * @see MediaBrowserService#onLoadItem
+     * @see #onLoadChildren
+     * @see #onLoadItem
      */
     public class Result<T> {
         private Object mDebug;
@@ -367,11 +368,16 @@ public abstract class MediaBrowserService extends Service {
      * {@link Result#detach result.detach} may be called before returning from
      * this function, and then {@link Result#sendResult result.sendResult}
      * called when the loading is complete.
+     * </p><p>
+     * In case the media item does not have any children, call {@link Result#sendResult}
+     * with an empty list. When the given {@code parentId} is invalid, implementations must
+     * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
+     * {@link MediaBrowser.SubscriptionCallback#onError}.
+     * </p>
      *
      * @param parentId The id of the parent media item whose children are to be
      *            queried.
-     * @param result The Result to send the list of children to, or null if the
-     *            id is invalid.
+     * @param result The Result to send the list of children to.
      */
     public abstract void onLoadChildren(@NonNull String parentId,
             @NonNull Result<List<MediaBrowser.MediaItem>> result);
@@ -385,11 +391,16 @@ public abstract class MediaBrowserService extends Service {
      * {@link Result#detach result.detach} may be called before returning from
      * this function, and then {@link Result#sendResult result.sendResult}
      * called when the loading is complete.
+     * </p><p>
+     * In case the media item does not have any children, call {@link Result#sendResult}
+     * with an empty list. When the given {@code parentId} is invalid, implementations must
+     * call {@link Result#sendResult result.sendResult} with {@code null}, which will invoke
+     * {@link MediaBrowser.SubscriptionCallback#onError}.
+     * </p>
      *
      * @param parentId The id of the parent media item whose children are to be
      *            queried.
-     * @param result The Result to send the list of children to, or null if the
-     *            id is invalid.
+     * @param result The Result to send the list of children to.
      * @param options A bundle of service-specific arguments sent from the media
      *            browse. The information returned through the result should be
      *            affected by the contents of this bundle.
@@ -411,13 +422,18 @@ public abstract class MediaBrowserService extends Service {
      * result.detach} may be called before returning from this function, and
      * then {@link Result#sendResult result.sendResult} called when the item has
      * been loaded.
-     * <p>
-     * The default implementation sends a null result.
+     * </p><p>
+     * When the given {@code itemId} is invalid, implementations must call
+     * {@link Result#sendResult result.sendResult} with {@code null}, which will
+     * invoke {@link MediaBrowser.ItemCallback#onError}.
+     * </p><p>
+     * The default implementation calls {@link Result#sendResult result.sendResult}
+     * with {@code null}.
+     * </p>
      *
      * @param itemId The id for the specific
      *            {@link android.media.browse.MediaBrowser.MediaItem}.
-     * @param result The Result to send the item to, or null if the id is
-     *            invalid.
+     * @param result The Result to send the item to.
      */
     public void onLoadItem(String itemId, Result<MediaBrowser.MediaItem> result) {
         result.sendResult(null);
@@ -630,6 +646,9 @@ public abstract class MediaBrowserService extends Service {
 
     private List<MediaBrowser.MediaItem> applyOptions(List<MediaBrowser.MediaItem> list,
             final Bundle options) {
+        if (list == null) {
+            return null;
+        }
         int page = options.getInt(MediaBrowser.EXTRA_PAGE, -1);
         int pageSize = options.getInt(MediaBrowser.EXTRA_PAGE_SIZE, -1);
         if (page == -1 && pageSize == -1) {
@@ -638,7 +657,7 @@ public abstract class MediaBrowserService extends Service {
         int fromIndex = pageSize * (page - 1);
         int toIndex = fromIndex + pageSize;
         if (page < 1 || pageSize < 1 || fromIndex >= list.size()) {
-            return null;
+            return Collections.EMPTY_LIST;
         }
         if (toIndex > list.size()) {
             toIndex = list.size();
index fa9c48c..29739ca 100644 (file)
@@ -64,7 +64,6 @@ LOCAL_C_INCLUDES += \
     frameworks/av/media/mtp \
     frameworks/native/include/media/openmax \
     $(call include-path-for, libhardware)/hardware \
-    system/media/camera/include \
     $(PV_INCLUDES) \
     $(JNI_H_INCLUDE)
 
index 2004a3a..d6994b3 100644 (file)
@@ -1302,7 +1302,10 @@ static void android_media_MediaCodec_queueSecureInputBuffer(
     jobject patternObj = env->GetObjectField(cryptoInfoObj, gFields.cryptoInfoPatternID);
 
     CryptoPlugin::Pattern pattern;
-    if (patternObj != NULL) {
+    if (patternObj == NULL) {
+        pattern.mEncryptBlocks = 0;
+        pattern.mSkipBlocks = 0;
+    } else {
         pattern.mEncryptBlocks = env->GetIntField(patternObj, gFields.patternEncryptBlocksID);
         pattern.mSkipBlocks = env->GetIntField(patternObj, gFields.patternSkipBlocksID);
     }
index 3b892cb..537b56d 100644 (file)
@@ -116,7 +116,8 @@ status_t JMediaDataSource::getSize(off64_t* size) {
         return UNKNOWN_ERROR;
     }
     if (mSizeIsCached) {
-        return mCachedSize;
+        *size = mCachedSize;
+        return OK;
     }
 
     JNIEnv* env = AndroidRuntime::getJNIEnv();
index 701f7ac..922ad79 100644 (file)
@@ -26,7 +26,6 @@
 #include <utils/Log.h>
 
 #include <gui/Surface.h>
-#include <camera/ICameraService.h>
 #include <camera/Camera.h>
 #include <media/mediarecorder.h>
 #include <media/stagefright/PersistentSurface.h>
index 556f2c7..5722cb0 100644 (file)
@@ -231,11 +231,11 @@ MyMtpDatabase::~MyMtpDatabase() {
 }
 
 MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
-                                            MtpObjectFormat format,
-                                            MtpObjectHandle parent,
-                                            MtpStorageID storage,
-                                            uint64_t size,
-                                            time_t modified) {
+                                               MtpObjectFormat format,
+                                               MtpObjectHandle parent,
+                                               MtpStorageID storage,
+                                               uint64_t size,
+                                               time_t modified) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jstring pathStr = env->NewStringUTF(path);
     MtpObjectHandle result = env->CallIntMethod(mDatabase, method_beginSendObject,
@@ -249,7 +249,7 @@ MtpObjectHandle MyMtpDatabase::beginSendObject(const char* path,
 }
 
 void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
-                                MtpObjectFormat format, bool succeeded) {
+                                  MtpObjectFormat format, bool succeeded) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jstring pathStr = env->NewStringUTF(path);
     env->CallVoidMethod(mDatabase, method_endSendObject, pathStr,
@@ -261,8 +261,8 @@ void MyMtpDatabase::endSendObject(const char* path, MtpObjectHandle handle,
 }
 
 MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
-                                    MtpObjectFormat format,
-                                    MtpObjectHandle parent) {
+                                                  MtpObjectFormat format,
+                                                  MtpObjectHandle parent) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jintArray array = (jintArray)env->CallObjectMethod(mDatabase, method_getObjectList,
                 (jint)storageID, (jint)format, (jint)parent);
@@ -281,8 +281,8 @@ MtpObjectHandleList* MyMtpDatabase::getObjectList(MtpStorageID storageID,
 }
 
 int MyMtpDatabase::getNumObjects(MtpStorageID storageID,
-                                MtpObjectFormat format,
-                                MtpObjectHandle parent) {
+                                 MtpObjectFormat format,
+                                 MtpObjectHandle parent) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     int result = env->CallIntMethod(mDatabase, method_getNumObjects,
                 (jint)storageID, (jint)format, (jint)parent);
@@ -364,11 +364,21 @@ MtpDevicePropertyList* MyMtpDatabase::getSupportedDeviceProperties() {
 }
 
 MtpResponseCode MyMtpDatabase::getObjectPropertyValue(MtpObjectHandle handle,
-                                            MtpObjectProperty property,
-                                            MtpDataPacket& packet) {
+                                                      MtpObjectProperty property,
+                                                      MtpDataPacket& packet) {
+    static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
+                  "Casting MtpObjectHandle to jint loses a value");
+    static_assert(sizeof(jint) >= sizeof(MtpObjectProperty),
+                  "Casting MtpObjectProperty to jint loses a value");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
-                (jlong)handle, 0, (jlong)property, 0, 0);
+    jobject list = env->CallObjectMethod(
+            mDatabase,
+            method_getObjectPropertyList,
+            static_cast<jint>(handle),
+            0,
+            static_cast<jint>(property),
+            0,
+            0);
     MtpResponseCode result = env->GetIntField(list, field_mResult);
     int count = env->GetIntField(list, field_mCount);
     if (result == MTP_RESPONSE_OK && count != 1)
@@ -532,8 +542,8 @@ static bool readLongValue(int type, MtpDataPacket& packet, jlong& longValue) {
 }
 
 MtpResponseCode MyMtpDatabase::setObjectPropertyValue(MtpObjectHandle handle,
-                                            MtpObjectProperty property,
-                                            MtpDataPacket& packet) {
+                                                      MtpObjectProperty property,
+                                                      MtpDataPacket& packet) {
     int         type;
 
     if (!getObjectPropertyInfo(property, type))
@@ -563,7 +573,7 @@ fail:
 }
 
 MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property,
-                                            MtpDataPacket& packet) {
+                                                      MtpDataPacket& packet) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
 
     if (property == MTP_DEVICE_PROPERTY_BATTERY_LEVEL) {
@@ -636,7 +646,7 @@ MtpResponseCode MyMtpDatabase::getDevicePropertyValue(MtpDeviceProperty property
 }
 
 MtpResponseCode MyMtpDatabase::setDevicePropertyValue(MtpDeviceProperty property,
-                                            MtpDataPacket& packet) {
+                                                      MtpDataPacket& packet) {
     int         type;
 
     if (!getDevicePropertyInfo(property, type))
@@ -670,12 +680,20 @@ MtpResponseCode MyMtpDatabase::resetDeviceProperty(MtpDeviceProperty /*property*
 }
 
 MtpResponseCode MyMtpDatabase::getObjectPropertyList(MtpObjectHandle handle,
-                                            uint32_t format, uint32_t property,
-                                            int groupCode, int depth,
-                                            MtpDataPacket& packet) {
+                                                     uint32_t format, uint32_t property,
+                                                     int groupCode, int depth,
+                                                     MtpDataPacket& packet) {
+    static_assert(sizeof(jint) >= sizeof(MtpObjectHandle),
+                  "Casting MtpObjectHandle to jint loses a value");
     JNIEnv* env = AndroidRuntime::getJNIEnv();
-    jobject list = env->CallObjectMethod(mDatabase, method_getObjectPropertyList,
-                (jlong)handle, (jint)format, (jlong)property, (jint)groupCode, (jint)depth);
+    jobject list = env->CallObjectMethod(
+            mDatabase,
+            method_getObjectPropertyList,
+            static_cast<jint>(handle),
+            static_cast<jint>(format),
+            static_cast<jint>(property),
+            static_cast<jint>(groupCode),
+            static_cast<jint>(depth));
     checkAndClearExceptionFromCallback(env, __FUNCTION__);
     if (!list)
         return MTP_RESPONSE_GENERAL_ERROR;
@@ -787,7 +805,7 @@ static long getLongFromExifEntry(ExifEntry *e) {
 }
 
 MtpResponseCode MyMtpDatabase::getObjectInfo(MtpObjectHandle handle,
-                                            MtpObjectInfo& info) {
+                                             MtpObjectInfo& info) {
     MtpString       path;
     int64_t         length;
     MtpObjectFormat format;
@@ -940,9 +958,9 @@ void* MyMtpDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize)
 }
 
 MtpResponseCode MyMtpDatabase::getObjectFilePath(MtpObjectHandle handle,
-                                            MtpString& outFilePath,
-                                            int64_t& outFileLength,
-                                            MtpObjectFormat& outFormat) {
+                                                 MtpString& outFilePath,
+                                                 int64_t& outFileLength,
+                                                 MtpObjectFormat& outFormat) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     jint result = env->CallIntMethod(mDatabase, method_getObjectFilePath,
                 (jint)handle, mStringBuffer, mLongBuffer);
@@ -1056,7 +1074,7 @@ MtpObjectHandleList* MyMtpDatabase::getObjectReferences(MtpObjectHandle handle)
 }
 
 MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
-                                                    MtpObjectHandleList* references) {
+                                                   MtpObjectHandleList* references) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     int count = references->size();
     jintArray array = env->NewIntArray(count);
@@ -1077,7 +1095,7 @@ MtpResponseCode MyMtpDatabase::setObjectReferences(MtpObjectHandle handle,
 }
 
 MtpProperty* MyMtpDatabase::getObjectPropertyDesc(MtpObjectProperty property,
-                                            MtpObjectFormat format) {
+                                                  MtpObjectFormat format) {
     static const int channelEnum[] = {
                                         1,  // mono
                                         2,  // stereo
@@ -1313,7 +1331,7 @@ int register_android_mtp_MtpDatabase(JNIEnv *env)
         return -1;
     }
     method_getObjectPropertyList = env->GetMethodID(clazz, "getObjectPropertyList",
-            "(JIJII)Landroid/mtp/MtpPropertyList;");
+            "(IIIII)Landroid/mtp/MtpPropertyList;");
     if (method_getObjectPropertyList == NULL) {
         ALOGE("Can't find getObjectPropertyList");
         return -1;
index 61dede3..9be7004 100644 (file)
@@ -60,10 +60,7 @@ public class MediaFrameworkUnitTestRunner extends InstrumentationTestRunner {
     }
 
     private void addCameraUnitTests(TestSuite suite) {
-        suite.addTestSuite(CameraUtilsDecoratorTest.class);
-        suite.addTestSuite(CameraUtilsRuntimeExceptionTest.class);
         suite.addTestSuite(CameraUtilsUncheckedThrowTest.class);
-        suite.addTestSuite(CameraUtilsBinderDecoratorTest.class);
         suite.addTestSuite(CameraUtilsTypeReferenceTest.class);
         suite.addTestSuite(CameraMetadataTest.class);
     }
index 6f74203..9a0946e 100644 (file)
@@ -19,16 +19,16 @@ package com.android.mediaframeworktest.integration;
 import android.hardware.CameraInfo;
 import android.hardware.ICamera;
 import android.hardware.ICameraClient;
+import android.hardware.ICameraService;
 import android.hardware.ICameraServiceListener;
 import android.hardware.camera2.ICameraDeviceCallbacks;
 import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
-import android.hardware.camera2.utils.BinderHolder;
-import android.hardware.camera2.utils.CameraBinderDecorator;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
@@ -84,14 +84,7 @@ public class CameraBinderTest extends AndroidTestCase {
     public void testCameraInfo() throws Exception {
         for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
 
-            CameraInfo info = new CameraInfo();
-            info.info.facing = -1;
-            info.info.orientation = -1;
-
-            assertTrue(
-                    "Camera service returned info for camera " + cameraId,
-                    mUtils.getCameraService().getCameraInfo(cameraId, info) ==
-                    CameraBinderTestUtils.NO_ERROR);
+            CameraInfo info = mUtils.getCameraService().getCameraInfo(cameraId);
             assertTrue("Facing was not set for camera " + cameraId, info.info.facing != -1);
             assertTrue("Orientation was not set for camera " + cameraId,
                     info.info.orientation != -1);
@@ -105,20 +98,17 @@ public class CameraBinderTest extends AndroidTestCase {
     public void testGetLegacyParameters() throws Exception {
         for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
 
-            String[] parameters = new String[1];
-            assertEquals("Camera service returned parameters for camera " + cameraId,
-                    CameraBinderTestUtils.NO_ERROR,
-                    mUtils.getCameraService().getLegacyParameters(cameraId, /*out*/parameters));
-            assertNotNull(parameters[0]);
+            String parameters = mUtils.getCameraService().getLegacyParameters(cameraId);
+            assertNotNull(parameters);
             assertTrue("Parameters should have at least one character in it",
-                    parameters[0].length() > 0);
+                    parameters.length() > 0);
 
-            int end = parameters[0].length();
+            int end = parameters.length();
             if (end > MAX_PARAMETERS_LENGTH) {
                 end = MAX_PARAMETERS_LENGTH;
             }
 
-            Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters[0].substring(0, end));
+            Log.v(TAG, "Camera " + cameraId + " parameters: " + parameters.substring(0, end));
         }
     }
 
@@ -127,14 +117,8 @@ public class CameraBinderTest extends AndroidTestCase {
     public void testSupportsCamera2Api() throws Exception {
         for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
 
-            int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
+            boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_2);
 
-            if (res != CameraBinderTestUtils.NO_ERROR && res != -android.system.OsConstants.EOPNOTSUPP) {
-                fail("Camera service returned bad value when queried if it supports camera2 api: "
-                        + res + " for camera ID " + cameraId);
-            }
-
-            boolean supports = res == CameraBinderTestUtils.NO_ERROR;
             Log.v(TAG, "Camera " + cameraId + " supports api2: " + supports);
         }
     }
@@ -144,10 +128,10 @@ public class CameraBinderTest extends AndroidTestCase {
     public void testSupportsCamera1Api() throws Exception {
         for (int cameraId = 0; cameraId < mUtils.getGuessedNumCameras(); ++cameraId) {
 
-            int res = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
-            assertEquals(
-                    "Camera service returned bad value when queried if it supports camera1 api: "
-                    + res + " for camera ID " + cameraId, CameraBinderTestUtils.NO_ERROR, res);
+            boolean supports = mUtils.getCameraService().supportsCameraApi(cameraId, API_VERSION_1);
+            assertTrue(
+                    "Camera service returned false when queried if it supports camera1 api " +
+                    " for camera ID " + cameraId, supports);
         }
     }
 
@@ -169,11 +153,10 @@ public class CameraBinderTest extends AndroidTestCase {
 
             String clientPackageName = getContext().getPackageName();
 
-            BinderHolder holder = new BinderHolder();
-            CameraBinderDecorator.newInstance(mUtils.getCameraService())
+            ICamera cameraUser = mUtils.getCameraService()
                     .connect(dummyCallbacks, cameraId, clientPackageName,
-                    CameraBinderTestUtils.USE_CALLING_UID, holder);
-            ICamera cameraUser = ICamera.Stub.asInterface(holder.getBinder());
+                            ICameraService.USE_CALLING_UID,
+                            ICameraService.USE_CALLING_PID);
             assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
 
             Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -191,14 +174,11 @@ public class CameraBinderTest extends AndroidTestCase {
 
             String clientPackageName = getContext().getPackageName();
 
-            BinderHolder holder = new BinderHolder();
-
             try {
-                CameraBinderDecorator.newInstance(mUtils.getCameraService())
+                cameraUser = mUtils.getCameraService()
                         .connectLegacy(dummyCallbacks, cameraId, CAMERA_HAL_API_VERSION_1_0,
-                        clientPackageName,
-                        CameraBinderTestUtils.USE_CALLING_UID, holder);
-                cameraUser = ICamera.Stub.asInterface(holder.getBinder());
+                                clientPackageName,
+                                ICameraService.USE_CALLING_UID);
                 assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
 
                 Log.v(TAG, String.format("Camera %s connected as HAL1 legacy device", cameraId));
@@ -284,11 +264,11 @@ public class CameraBinderTest extends AndroidTestCase {
 
             String clientPackageName = getContext().getPackageName();
 
-            BinderHolder holder = new BinderHolder();
-            CameraBinderDecorator.newInstance(mUtils.getCameraService())
-                    .connectDevice(dummyCallbacks, cameraId,
-                    clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
-            ICameraDeviceUser cameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
+            ICameraDeviceUser cameraUser =
+                    mUtils.getCameraService().connectDevice(
+                        dummyCallbacks, cameraId,
+                        clientPackageName,
+                        ICameraService.USE_CALLING_UID);
             assertNotNull(String.format("Camera %s was null", cameraId), cameraUser);
 
             Log.v(TAG, String.format("Camera %s connected", cameraId));
@@ -323,27 +303,33 @@ public class CameraBinderTest extends AndroidTestCase {
 
             ICameraServiceListener listener = new DummyCameraServiceListener();
 
-            assertTrue(
-                    "Listener was removed before added",
-                    mUtils.getCameraService().removeListener(listener) ==
-                    CameraBinderTestUtils.BAD_VALUE);
+            try {
+                mUtils.getCameraService().removeListener(listener);
+                fail("Listener was removed before added");
+            } catch (ServiceSpecificException e) {
+                assertEquals("Listener was removed before added",
+                        e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
+            }
 
-            assertTrue("Listener was not added",
-                    mUtils.getCameraService().addListener(listener) ==
-                    CameraBinderTestUtils.NO_ERROR);
-            assertTrue(
-                    "Listener was wrongly added again",
-                    mUtils.getCameraService().addListener(listener) ==
-                    CameraBinderTestUtils.ALREADY_EXISTS);
+            mUtils.getCameraService().addListener(listener);
 
-            assertTrue(
-                    "Listener was not removed",
-                    mUtils.getCameraService().removeListener(listener) ==
-                    CameraBinderTestUtils.NO_ERROR);
-            assertTrue(
-                    "Listener was wrongly removed again",
-                    mUtils.getCameraService().removeListener(listener) ==
-                    CameraBinderTestUtils.BAD_VALUE);
+            try {
+                mUtils.getCameraService().addListener(listener);
+                fail("Listener was wrongly added again");
+            } catch (ServiceSpecificException e) {
+                assertEquals("Listener was wrongly added again",
+                        e.errorCode, ICameraService.ERROR_ALREADY_EXISTS);
+            }
+
+            mUtils.getCameraService().removeListener(listener);
+
+            try {
+                mUtils.getCameraService().removeListener(listener);
+                fail("Listener was wrongly removed twice");
+            } catch (ServiceSpecificException e) {
+                assertEquals("Listener was wrongly removed twice",
+                        e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
+            }
         }
     }
 }
index 5c4b23b..38fc49f 100644 (file)
@@ -18,10 +18,6 @@ public class CameraBinderTestUtils {
 
     static final String CAMERA_SERVICE_BINDER_NAME = "media.camera";
 
-    protected static final int USE_CALLING_UID = -1;
-    protected static final int BAD_VALUE = -EINVAL;
-    protected static final int INVALID_OPERATION = -ENOSYS;
-    protected static final int ALREADY_EXISTS = -EEXIST;
     public static final int NO_ERROR = 0;
     private final Context mContext;
 
index d71b44b..5c1d8a7 100644 (file)
@@ -18,6 +18,7 @@ package com.android.mediaframeworktest.integration;
 
 import android.graphics.ImageFormat;
 import android.graphics.SurfaceTexture;
+import android.hardware.ICameraService;
 import android.hardware.camera2.CameraMetadata;
 import android.hardware.camera2.CameraCaptureSession;
 import android.hardware.camera2.CameraCharacteristics;
@@ -27,12 +28,13 @@ import android.hardware.camera2.ICameraDeviceUser;
 import android.hardware.camera2.impl.CameraMetadataNative;
 import android.hardware.camera2.impl.CaptureResultExtras;
 import android.hardware.camera2.params.OutputConfiguration;
-import android.hardware.camera2.utils.BinderHolder;
+import android.hardware.camera2.utils.SubmitInfo;
 import android.media.Image;
 import android.media.ImageReader;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.RemoteException;
+import android.os.ServiceSpecificException;
 import android.os.SystemClock;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -164,11 +166,10 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
     }
 
     private CaptureRequest.Builder createDefaultBuilder(boolean needStream) throws Exception {
-        CameraMetadataNative metadata = new CameraMetadataNative();
+        CameraMetadataNative metadata = null;
         assertTrue(metadata.isEmpty());
 
-        int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        metadata = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW);
         assertFalse(metadata.isEmpty());
 
         CaptureRequest.Builder request = new CaptureRequest.Builder(metadata, /*reprocess*/false,
@@ -183,12 +184,13 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
         return request;
     }
 
-    private int submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
-        int requestId = mCameraUser.submitRequest(request, streaming, null);
+    private SubmitInfo submitCameraRequest(CaptureRequest request, boolean streaming) throws Exception {
+        SubmitInfo requestInfo = mCameraUser.submitRequest(request, streaming);
         assertTrue(
-                "Request IDs should be non-negative (expected: >= 0, actual: " + requestId + ")",
-                requestId >= 0);
-        return requestId;
+                "Request IDs should be non-negative (expected: >= 0, actual: " +
+                requestInfo.getRequestId() + ")",
+                requestInfo.getRequestId() >= 0);
+        return requestInfo;
     }
 
     @Override
@@ -214,10 +216,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
 
         mMockCb = spy(dummyCallbacks);
 
-        BinderHolder holder = new BinderHolder();
-        mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
-                clientPackageName, CameraBinderTestUtils.USE_CALLING_UID, holder);
-        mCameraUser = ICameraDeviceUser.Stub.asInterface(holder.getBinder());
+        mCameraUser = mUtils.getCameraService().connectDevice(mMockCb, mCameraId,
+                clientPackageName, ICameraService.USE_CALLING_UID);
         assertNotNull(String.format("Camera %s was null", mCameraId), mCameraUser);
         mHandlerThread = new HandlerThread(TAG);
         mHandlerThread.start();
@@ -238,11 +238,10 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
 
     @SmallTest
     public void testCreateDefaultRequest() throws Exception {
-        CameraMetadataNative metadata = new CameraMetadataNative();
+        CameraMetadataNative metadata = null;
         assertTrue(metadata.isEmpty());
 
-        int status = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW, /* out */metadata);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        metadata = mCameraUser.createDefaultRequest(TEMPLATE_PREVIEW);
         assertFalse(metadata.isEmpty());
 
     }
@@ -252,18 +251,28 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
         int streamId = mCameraUser.createStream(mOutputConfiguration);
         assertEquals(0, streamId);
 
-        assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
-                mCameraUser.createStream(mOutputConfiguration));
+        try {
+            mCameraUser.createStream(mOutputConfiguration);
+            fail("Creating same stream twice");
+        } catch (ServiceSpecificException e) {
+            assertEquals("Creating same stream twice",
+                    e.errorCode, ICameraService.ERROR_ALREADY_EXISTS);
+        }
 
-        assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
+        mCameraUser.deleteStream(streamId);
     }
 
     @SmallTest
     public void testDeleteInvalidStream() throws Exception {
-        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(-1));
-        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0));
-        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(1));
-        assertEquals(CameraBinderTestUtils.BAD_VALUE, mCameraUser.deleteStream(0xC0FFEE));
+        int[] badStreams = { -1, 0, 1, 0xC0FFEE };
+        for (int badStream : badStreams) {
+            try {
+                mCameraUser.deleteStream(badStream);
+                fail("Allowed bad stream delete");
+            } catch (ServiceSpecificException e) {
+                assertEquals(e.errorCode, ICameraService.ERROR_ILLEGAL_ARGUMENT);
+            }
+        }
     }
 
     @SmallTest
@@ -273,8 +282,13 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
         int streamId = mCameraUser.createStream(mOutputConfiguration);
         assertEquals(0, streamId);
 
-        assertEquals(CameraBinderTestUtils.ALREADY_EXISTS,
-                mCameraUser.createStream(mOutputConfiguration));
+        try {
+            mCameraUser.createStream(mOutputConfiguration);
+            fail("Created same stream twice");
+        } catch (ServiceSpecificException e) {
+            assertEquals("Created same stream twice",
+                    ICameraService.ERROR_ALREADY_EXISTS, e.errorCode);
+        }
 
         // Create second stream with a different surface.
         SurfaceTexture surfaceTexture = new SurfaceTexture(/* ignored */0);
@@ -286,8 +300,8 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
         assertEquals(1, streamId2);
 
         // Clean up streams
-        assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId));
-        assertEquals(CameraBinderTestUtils.NO_ERROR, mCameraUser.deleteStream(streamId2));
+        mCameraUser.deleteStream(streamId);
+        mCameraUser.deleteStream(streamId2);
     }
 
     @SmallTest
@@ -295,16 +309,25 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
 
         CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */false);
         CaptureRequest request1 = builder.build();
-        int status = mCameraUser.submitRequest(request1, /* streaming */false, null);
-        assertEquals("Expected submitRequest to return BAD_VALUE " +
-                "since we had 0 surface targets set.", CameraBinderTestUtils.BAD_VALUE, status);
+        try {
+            SubmitInfo requestInfo = mCameraUser.submitRequest(request1, /* streaming */false);
+            fail("Exception expected");
+        } catch(ServiceSpecificException e) {
+            assertEquals("Expected submitRequest to throw ServiceSpecificException with BAD_VALUE " +
+                    "since we had 0 surface targets set.", ICameraService.ERROR_ILLEGAL_ARGUMENT,
+                    e.errorCode);
+        }
 
         builder.addTarget(mSurface);
         CaptureRequest request2 = builder.build();
-        status = mCameraUser.submitRequest(request2, /* streaming */false, null);
-        assertEquals("Expected submitRequest to return BAD_VALUE since " +
-                "the target surface wasn't registered with createStream.",
-                CameraBinderTestUtils.BAD_VALUE, status);
+        try {
+            SubmitInfo requestInfo = mCameraUser.submitRequest(request2, /* streaming */false);
+            fail("Exception expected");
+        } catch(ServiceSpecificException e) {
+            assertEquals("Expected submitRequest to throw ILLEGAL_ARGUMENT " +
+                    "ServiceSpecificException since the target wasn't registered with createStream.",
+                    ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
+        }
     }
 
     @SmallTest
@@ -314,9 +337,10 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
         CaptureRequest request = builder.build();
 
         // Submit valid request twice.
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
-        int requestId2 = submitCameraRequest(request, /* streaming */false);
-        assertNotSame("Request IDs should be unique for multiple requests", requestId1, requestId2);
+        SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
+        assertNotSame("Request IDs should be unique for multiple requests",
+                requestInfo1.getRequestId(), requestInfo2.getRequestId());
 
     }
 
@@ -329,32 +353,35 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
 
         // Submit valid request once (non-streaming), and another time
         // (streaming)
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
-
-        int requestIdStreaming = submitCameraRequest(request, /* streaming */true);
-        assertNotSame("Request IDs should be unique for multiple requests", requestId1,
-                requestIdStreaming);
-
-        int status = mCameraUser.cancelRequest(-1, null);
-        assertEquals("Invalid request IDs should not be cancellable",
-                CameraBinderTestUtils.BAD_VALUE, status);
-
-        status = mCameraUser.cancelRequest(requestId1, null);
-        assertEquals("Non-streaming request IDs should not be cancellable",
-                CameraBinderTestUtils.BAD_VALUE, status);
+        SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
+
+        SubmitInfo requestInfoStreaming = submitCameraRequest(request, /* streaming */true);
+        assertNotSame("Request IDs should be unique for multiple requests",
+                requestInfo1.getRequestId(),
+                requestInfoStreaming.getRequestId());
+
+        try {
+            long lastFrameNumber = mCameraUser.cancelRequest(-1);
+            fail("Expected exception");
+        } catch (ServiceSpecificException e) {
+            assertEquals("Invalid request IDs should not be cancellable",
+                    ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
+        }
 
-        status = mCameraUser.cancelRequest(requestIdStreaming, null);
-        assertEquals("Streaming request IDs should be cancellable", CameraBinderTestUtils.NO_ERROR,
-                status);
+        try {
+            long lastFrameNumber = mCameraUser.cancelRequest(requestInfo1.getRequestId());
+            fail("Expected exception");
+        } catch (ServiceSpecificException e) {
+            assertEquals("Non-streaming request IDs should not be cancellable",
+                    ICameraService.ERROR_ILLEGAL_ARGUMENT, e.errorCode);
+        }
 
+        long lastFrameNumber = mCameraUser.cancelRequest(requestInfoStreaming.getRequestId());
     }
 
     @SmallTest
     public void testCameraInfo() throws RemoteException {
-        CameraMetadataNative info = new CameraMetadataNative();
-
-        int status = mCameraUser.getCameraInfo(/*out*/info);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        CameraMetadataNative info = mCameraUser.getCameraInfo();
 
         assertFalse(info.isEmpty());
         assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
@@ -362,10 +389,7 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
 
     @SmallTest
     public void testCameraCharacteristics() throws RemoteException {
-        CameraMetadataNative info = new CameraMetadataNative();
-
-        int status = mUtils.getCameraService().getCameraCharacteristics(mCameraId, /*out*/info);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        CameraMetadataNative info = mUtils.getCameraService().getCameraCharacteristics(mCameraId);
 
         assertFalse(info.isEmpty());
         assertNotNull(info.get(CameraCharacteristics.SCALER_AVAILABLE_FORMATS));
@@ -374,18 +398,19 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
     @SmallTest
     public void testWaitUntilIdle() throws Exception {
         CaptureRequest.Builder builder = createDefaultBuilder(/* needStream */true);
-        int requestIdStreaming = submitCameraRequest(builder.build(), /* streaming */true);
+        SubmitInfo requestInfoStreaming = submitCameraRequest(builder.build(), /* streaming */true);
 
         // Test Bad case first: waitUntilIdle when there is active repeating request
-        int status = mCameraUser.waitUntilIdle();
-        assertEquals("waitUntilIdle is invalid operation when there is active repeating request",
-            CameraBinderTestUtils.INVALID_OPERATION, status);
+        try {
+            mCameraUser.waitUntilIdle();
+        } catch (ServiceSpecificException e) {
+            assertEquals("waitUntilIdle is invalid operation when there is active repeating request",
+                    ICameraService.ERROR_INVALID_OPERATION, e.errorCode);
+        }
 
         // Test good case, waitUntilIdle when there is no active repeating request
-        status = mCameraUser.cancelRequest(requestIdStreaming, null);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
-        status = mCameraUser.waitUntilIdle();
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        long lastFrameNumber = mCameraUser.cancelRequest(requestInfoStreaming.getRequestId());
+        mCameraUser.waitUntilIdle();
     }
 
     @SmallTest
@@ -411,12 +436,12 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
         ArgumentCaptor<Long> timestamps = ArgumentCaptor.forClass(Long.class);
 
         // Test both single request and streaming request.
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).times(1)).onCaptureStarted(
                 any(CaptureResultExtras.class),
                 anyLong());
 
-        int streamingId = submitCameraRequest(request, /* streaming */true);
+        SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
         verify(mMockCb, timeout(WAIT_FOR_COMPLETE_TIMEOUT_MS).atLeast(NUM_CALLBACKS_CHECKED))
                 .onCaptureStarted(
                         any(CaptureResultExtras.class),
@@ -436,22 +461,22 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
         CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
 
         // Try streaming
-        int streamingId = submitCameraRequest(request, /* streaming */true);
+        SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
 
         // Wait a bit to fill up the queue
         SystemClock.sleep(WAIT_FOR_WORK_MS);
 
         // Cancel and make sure we eventually quiesce
-        status = mCameraUser.cancelRequest(streamingId, null);
+        long lastFrameNumber = mCameraUser.cancelRequest(streamingInfo.getRequestId());
 
         verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(1)).onDeviceIdle();
 
         // Submit a few capture requests
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
-        int requestId2 = submitCameraRequest(request, /* streaming */false);
-        int requestId3 = submitCameraRequest(request, /* streaming */false);
-        int requestId4 = submitCameraRequest(request, /* streaming */false);
-        int requestId5 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo3 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo4 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo5 = submitCameraRequest(request, /* streaming */false);
 
         // And wait for more idle
         verify(mMockCb, timeout(WAIT_FOR_IDLE_TIMEOUT_MS).times(2)).onDeviceIdle();
@@ -463,38 +488,34 @@ public class CameraDeviceBinderTest extends AndroidTestCase {
         int status;
 
         // Initial flush should work
-        status = mCameraUser.flush(null);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        long lastFrameNumber = mCameraUser.flush();
 
         // Then set up a stream
         CaptureRequest request = createDefaultBuilder(/* needStream */true).build();
 
         // Flush should still be a no-op, really
-        status = mCameraUser.flush(null);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        lastFrameNumber = mCameraUser.flush();
 
         // Submit a few capture requests
-        int requestId1 = submitCameraRequest(request, /* streaming */false);
-        int requestId2 = submitCameraRequest(request, /* streaming */false);
-        int requestId3 = submitCameraRequest(request, /* streaming */false);
-        int requestId4 = submitCameraRequest(request, /* streaming */false);
-        int requestId5 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo1 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo2 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo3 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo4 = submitCameraRequest(request, /* streaming */false);
+        SubmitInfo requestInfo5 = submitCameraRequest(request, /* streaming */false);
 
         // Then flush and wait for idle
-        status = mCameraUser.flush(null);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        lastFrameNumber = mCameraUser.flush();
 
         verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(1)).onDeviceIdle();
 
         // Now a streaming request
-        int streamingId = submitCameraRequest(request, /* streaming */true);
+        SubmitInfo streamingInfo = submitCameraRequest(request, /* streaming */true);
 
         // Wait a bit to fill up the queue
         SystemClock.sleep(WAIT_FOR_WORK_MS);
 
         // Then flush and wait for the idle callback
-        status = mCameraUser.flush(null);
-        assertEquals(CameraBinderTestUtils.NO_ERROR, status);
+        lastFrameNumber = mCameraUser.flush();
 
         verify(mMockCb, timeout(WAIT_FOR_FLUSH_TIMEOUT_MS).times(2)).onDeviceIdle();
 
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsBinderDecoratorTest.java
deleted file mode 100644 (file)
index 33c6388..0000000
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.unit;
-
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.utils.CameraBinderDecorator;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.os.DeadObjectException;
-import android.os.RemoteException;
-import android.os.TransactionTooLargeException;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import static org.mockito.Mockito.*;
-import static android.hardware.camera2.utils.CameraBinderDecorator.*;
-import static android.hardware.camera2.CameraAccessException.*;
-import static android.system.OsConstants.*;
-
-import junit.framework.Assert;
-
-public class CameraUtilsBinderDecoratorTest extends junit.framework.TestCase {
-
-    private interface ICameraBinderStereotype {
-
-        double doNothing();
-
-        // int is a 'status_t'
-        int doSomethingPositive();
-
-        int doSomethingNoError();
-
-        int doSomethingPermissionDenied();
-
-        int doSomethingAlreadyExists();
-
-        int doSomethingBadValue();
-
-        int doSomethingDeadObject() throws CameraRuntimeException;
-
-        int doSomethingBadPolicy() throws CameraRuntimeException;
-
-        int doSomethingDeviceBusy() throws CameraRuntimeException;
-
-        int doSomethingNoSuchDevice() throws CameraRuntimeException;
-
-        int doSomethingUnknownErrorCode();
-
-        int doSomethingThrowDeadObjectException() throws RemoteException;
-
-        int doSomethingThrowTransactionTooLargeException() throws RemoteException;
-    }
-
-    private static final double SOME_ARBITRARY_DOUBLE = 1.0;
-    private static final int SOME_ARBITRARY_POSITIVE_INT = 5;
-    private static final int SOME_ARBITRARY_NEGATIVE_INT = -0xC0FFEE;
-
-    @SmallTest
-    public void testStereotypes() {
-
-        ICameraBinderStereotype mock = mock(ICameraBinderStereotype.class);
-        try {
-            when(mock.doNothing()).thenReturn(SOME_ARBITRARY_DOUBLE);
-            when(mock.doSomethingPositive()).thenReturn(SOME_ARBITRARY_POSITIVE_INT);
-            when(mock.doSomethingNoError()).thenReturn(NO_ERROR);
-            when(mock.doSomethingPermissionDenied()).thenReturn(PERMISSION_DENIED);
-            when(mock.doSomethingAlreadyExists()).thenReturn(ALREADY_EXISTS);
-            when(mock.doSomethingBadValue()).thenReturn(BAD_VALUE);
-            when(mock.doSomethingDeadObject()).thenReturn(DEAD_OBJECT);
-            when(mock.doSomethingBadPolicy()).thenReturn(-EACCES);
-            when(mock.doSomethingDeviceBusy()).thenReturn(-EBUSY);
-            when(mock.doSomethingNoSuchDevice()).thenReturn(-ENODEV);
-            when(mock.doSomethingUnknownErrorCode()).thenReturn(SOME_ARBITRARY_NEGATIVE_INT);
-            when(mock.doSomethingThrowDeadObjectException()).thenThrow(new DeadObjectException());
-            when(mock.doSomethingThrowTransactionTooLargeException()).thenThrow(
-                    new TransactionTooLargeException());
-        } catch (RemoteException e) {
-            Assert.fail("Unreachable");
-        }
-
-        ICameraBinderStereotype decoratedMock = CameraBinderDecorator.newInstance(mock);
-
-        // ignored by decorator because return type is double, not int
-        assertEquals(SOME_ARBITRARY_DOUBLE, decoratedMock.doNothing());
-
-        // pass through for positive values
-        assertEquals(SOME_ARBITRARY_POSITIVE_INT, decoratedMock.doSomethingPositive());
-
-        // pass through NO_ERROR
-        assertEquals(NO_ERROR, decoratedMock.doSomethingNoError());
-
-        try {
-            decoratedMock.doSomethingPermissionDenied();
-            Assert.fail("Should've thrown SecurityException");
-        } catch (SecurityException e) {
-        }
-
-        assertEquals(ALREADY_EXISTS, decoratedMock.doSomethingAlreadyExists());
-
-        try {
-            decoratedMock.doSomethingBadValue();
-            Assert.fail("Should've thrown IllegalArgumentException");
-        } catch (IllegalArgumentException e) {
-        }
-
-        try {
-            decoratedMock.doSomethingDeadObject();
-            Assert.fail("Should've thrown CameraRuntimeException");
-        } catch (CameraRuntimeException e) {
-            assertEquals(CAMERA_DISCONNECTED, e.getReason());
-        }
-
-        try {
-            decoratedMock.doSomethingBadPolicy();
-            Assert.fail("Should've thrown CameraRuntimeException");
-        } catch (CameraRuntimeException e) {
-            assertEquals(CAMERA_DISABLED, e.getReason());
-        }
-
-        try {
-            decoratedMock.doSomethingDeviceBusy();
-            Assert.fail("Should've thrown CameraRuntimeException");
-        } catch (CameraRuntimeException e) {
-            assertEquals(CAMERA_IN_USE, e.getReason());
-        }
-
-        try {
-            decoratedMock.doSomethingNoSuchDevice();
-            Assert.fail("Should've thrown CameraRuntimeException");
-        } catch (CameraRuntimeException e) {
-            assertEquals(CAMERA_DISCONNECTED, e.getReason());
-        }
-
-        try {
-            decoratedMock.doSomethingUnknownErrorCode();
-            Assert.fail("Should've thrown UnsupportedOperationException");
-        } catch (UnsupportedOperationException e) {
-            assertEquals(String.format("Unknown error %d",
-                    SOME_ARBITRARY_NEGATIVE_INT), e.getMessage());
-        }
-
-        try {
-            decoratedMock.doSomethingThrowDeadObjectException();
-            Assert.fail("Should've thrown CameraRuntimeException");
-        } catch (CameraRuntimeException e) {
-            assertEquals(CAMERA_DISCONNECTED, e.getReason());
-        } catch (RemoteException e) {
-            Assert.fail("Should not throw a DeadObjectException directly, but rethrow");
-        }
-
-        try {
-            decoratedMock.doSomethingThrowTransactionTooLargeException();
-            Assert.fail("Should've thrown UnsupportedOperationException");
-        } catch (UnsupportedOperationException e) {
-            assertTrue(e.getCause() instanceof TransactionTooLargeException);
-        } catch (RemoteException e) {
-            Assert.fail("Should not throw a TransactionTooLargeException directly, but rethrow");
-        }
-    }
-
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsDecoratorTest.java
deleted file mode 100644 (file)
index c3b6006..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.unit;
-
-import android.test.suitebuilder.annotation.SmallTest;
-import android.hardware.camera2.utils.*;
-import android.hardware.camera2.utils.Decorator.DecoratorListener;
-
-import junit.framework.Assert;
-
-import java.lang.reflect.Method;
-
-/**
- * adb shell am instrument -e class 'com.android.mediaframeworktest.unit.CameraUtilsDecoratorTest' \
- *      -w com.android.mediaframeworktest/.MediaFrameworkUnitTestRunner
- */
-public class CameraUtilsDecoratorTest extends junit.framework.TestCase {
-    private DummyListener mDummyListener;
-    private DummyInterface mIface;
-
-    @Override
-    public void setUp() {
-        mDummyListener = new DummyListener();
-        mIface = Decorator.newInstance(new DummyImpl(), mDummyListener);
-    }
-
-    interface DummyInterface {
-        int addValues(int x, int y, int z);
-
-        void raiseException() throws Exception;
-
-        void raiseUnsupportedOperationException() throws UnsupportedOperationException;
-    }
-
-    class DummyImpl implements DummyInterface {
-        @Override
-        public int addValues(int x, int y, int z) {
-            return x + y + z;
-        }
-
-        @Override
-        public void raiseException() throws Exception {
-            throw new Exception("Test exception");
-        }
-
-        @Override
-        public void raiseUnsupportedOperationException() throws UnsupportedOperationException {
-            throw new UnsupportedOperationException("Test exception");
-        }
-    }
-
-    class DummyListener implements DecoratorListener {
-
-        public boolean beforeCalled = false;
-        public boolean afterCalled = false;
-        public boolean catchCalled = false;
-        public boolean finallyCalled = false;
-        public Object resultValue = null;
-
-        public boolean raiseException = false;
-
-        @Override
-        public void onBeforeInvocation(Method m, Object[] args) {
-            beforeCalled = true;
-        }
-
-        @Override
-        public void onAfterInvocation(Method m, Object[] args, Object result) {
-            afterCalled = true;
-            resultValue = result;
-
-            if (raiseException) {
-                throw new UnsupportedOperationException("Test exception");
-            }
-        }
-
-        @Override
-        public boolean onCatchException(Method m, Object[] args, Throwable t) {
-            catchCalled = true;
-            return false;
-        }
-
-        @Override
-        public void onFinally(Method m, Object[] args) {
-            finallyCalled = true;
-        }
-
-    };
-
-    @SmallTest
-    public void testDecorator() {
-
-        // TODO rewrite this using mocks
-
-        assertTrue(mIface.addValues(1, 2, 3) == 6);
-        assertTrue(mDummyListener.beforeCalled);
-        assertTrue(mDummyListener.afterCalled);
-
-        int resultValue = (Integer)mDummyListener.resultValue;
-        assertTrue(resultValue == 6);
-        assertTrue(mDummyListener.finallyCalled);
-        assertFalse(mDummyListener.catchCalled);
-    }
-
-    @SmallTest
-    public void testDecoratorExceptions() {
-
-        boolean gotExceptions = false;
-        try {
-            mIface.raiseException();
-        } catch (Exception e) {
-            gotExceptions = true;
-            assertTrue(e.getMessage() == "Test exception");
-        }
-        assertTrue(gotExceptions);
-        assertTrue(mDummyListener.beforeCalled);
-        assertFalse(mDummyListener.afterCalled);
-        assertTrue(mDummyListener.catchCalled);
-        assertTrue(mDummyListener.finallyCalled);
-    }
-
-    @SmallTest
-    public void testDecoratorUnsupportedOperationException() {
-
-        boolean gotExceptions = false;
-        try {
-            mIface.raiseUnsupportedOperationException();
-        } catch (UnsupportedOperationException e) {
-            gotExceptions = true;
-            assertTrue(e.getMessage() == "Test exception");
-        }
-        assertTrue(gotExceptions);
-        assertTrue(mDummyListener.beforeCalled);
-        assertFalse(mDummyListener.afterCalled);
-        assertTrue(mDummyListener.catchCalled);
-        assertTrue(mDummyListener.finallyCalled);
-    }
-
-    @SmallTest
-    public void testDecoratorRaisesException() {
-
-        boolean gotExceptions = false;
-        try {
-            mDummyListener.raiseException = true;
-            mIface.addValues(1, 2, 3);
-            Assert.fail("unreachable");
-        } catch (UnsupportedOperationException e) {
-            gotExceptions = true;
-            assertTrue(e.getMessage() == "Test exception");
-        }
-        assertTrue(gotExceptions);
-        assertTrue(mDummyListener.beforeCalled);
-        assertTrue(mDummyListener.afterCalled);
-        assertFalse(mDummyListener.catchCalled);
-        assertTrue(mDummyListener.finallyCalled);
-    }
-}
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/CameraUtilsRuntimeExceptionTest.java
deleted file mode 100644 (file)
index 02c9f2a..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2013 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.mediaframeworktest.unit;
-
-import android.hardware.camera2.CameraAccessException;
-import android.hardware.camera2.utils.CameraRuntimeException;
-import android.hardware.camera2.utils.UncheckedThrow;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import junit.framework.Assert;
-
-public class CameraUtilsRuntimeExceptionTest extends junit.framework.TestCase {
-
-    @SmallTest
-    public void testCameraRuntimeException1() {
-        try {
-            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345);
-            throw runtimeExc.asChecked();
-        } catch (CameraAccessException e) {
-            assertEquals(12345, e.getReason());
-            assertNull(e.getMessage());
-            assertNull(e.getCause());
-        }
-    }
-
-    @SmallTest
-    public void testCameraRuntimeException2() {
-        try {
-            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, "Hello");
-            throw runtimeExc.asChecked();
-        } catch (CameraAccessException e) {
-            assertEquals(12345, e.getReason());
-            assertEquals("Hello", e.getMessage());
-            assertNull(e.getCause());
-        }
-    }
-
-    @SmallTest
-    public void testCameraRuntimeException3() {
-        Throwable cause = new IllegalStateException("For great justice");
-        try {
-            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, cause);
-            throw runtimeExc.asChecked();
-        } catch (CameraAccessException e) {
-            assertEquals(12345, e.getReason());
-            assertNull(e.getMessage());
-            assertEquals(cause, e.getCause());
-        }
-    }
-
-    @SmallTest
-    public void testCameraRuntimeException4() {
-        Throwable cause = new IllegalStateException("For great justice");
-        try {
-            CameraRuntimeException runtimeExc = new CameraRuntimeException(12345, "Hello", cause);
-            throw runtimeExc.asChecked();
-        } catch (CameraAccessException e) {
-            assertEquals(12345, e.getReason());
-            assertEquals("Hello", e.getMessage());
-            assertEquals(cause, e.getCause());
-        }
-    }
-}
index 9c3b505..74181c5 100644 (file)
@@ -889,7 +889,10 @@ public class GLES30 extends GLES20 {
     );
 
     // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
-
+    /**
+     * @deprecated
+     * Use the version that takes a ByteBuffer as the last argument, or the versions that return a String.
+     * */
     public static native void glGetTransformFeedbackVarying(
         int program,
         int index,
@@ -902,6 +905,18 @@ public class GLES30 extends GLES20 {
 
     // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
 
+    public static native void glGetTransformFeedbackVarying(
+        int program,
+        int index,
+        int bufsize,
+        java.nio.IntBuffer length,
+        java.nio.IntBuffer size,
+        java.nio.IntBuffer type,
+        java.nio.ByteBuffer name
+    );
+
+    // C function void glGetTransformFeedbackVarying ( GLuint program, GLuint index, GLsizei bufSize, GLsizei *length, GLint *size, GLenum *type, GLchar *name )
+
     public static native String glGetTransformFeedbackVarying(
         int program,
         int index,
index e1650e1..d5e48b5 100644 (file)
@@ -30,9 +30,12 @@ LOCAL_AAPT_FLAGS := \
   --extra-packages android.support.design \
   --extra-packages android.support.v7.recyclerview
 
+LOCAL_JACK_FLAGS := \
+  -D jack.assert.policy=enable \
+  -D jack.optimization.inner-class.accessors=true
+
 LOCAL_PACKAGE_NAME := DocumentsUI
 LOCAL_CERTIFICATE := platform
 
 include $(BUILD_PACKAGE)
-
-include $(LOCAL_PATH)/tests/Android.mk
+include $(call all-makefiles-under, $(LOCAL_PATH))
diff --git a/packages/DocumentsUI/perf-tests/Android.mk b/packages/DocumentsUI/perf-tests/Android.mk
new file mode 100644 (file)
index 0000000..c83094e
--- /dev/null
@@ -0,0 +1,22 @@
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+#LOCAL_SDK_VERSION := current
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src) \
+    $(call all-java-files-under, ../tests/src/com/android/documentsui/bots) \
+    ../tests/src/com/android/documentsui/ActivityTest.java \
+    ../tests/src/com/android/documentsui/DocumentsProviderHelper.java \
+    ../tests/src/com/android/documentsui/StubProvider.java
+
+LOCAL_JAVA_LIBRARIES := android.test.runner
+LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4 mockito-target ub-uiautomator
+
+LOCAL_PACKAGE_NAME := DocumentsUIPerfTests
+LOCAL_INSTRUMENTATION_FOR := DocumentsUI
+
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
+
diff --git a/packages/DocumentsUI/perf-tests/AndroidManifest.xml b/packages/DocumentsUI/perf-tests/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..97353e7
--- /dev/null
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.documentsui.perftests">
+
+    <application>
+        <uses-library android:name="android.test.runner" />
+        <provider
+            android:name="com.android.documentsui.StressProvider"
+            android:authorities="com.android.documentsui.stressprovider"
+            android:exported="true"
+            android:grantUriPermissions="true"
+            android:permission="android.permission.MANAGE_DOCUMENTS"
+            android:enabled="true">
+            <intent-filter>
+                <action android:name="android.content.action.DOCUMENTS_PROVIDER" />
+            </intent-filter>
+        </provider>
+    </application>
+
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+        android:targetPackage="com.android.documentsui"
+        android:label="Performance tests for DocumentsUI" />
+
+</manifest>
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/FilesActivityPerfTest.java
new file mode 100644 (file)
index 0000000..bf056f1
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import static com.android.documentsui.StressProvider.DEFAULT_AUTHORITY;
+import static com.android.documentsui.StressProvider.STRESS_ROOT_0_ID;
+import static com.android.documentsui.StressProvider.STRESS_ROOT_1_ID;
+
+import android.app.Activity;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.RemoteException;
+import android.test.suitebuilder.annotation.LargeTest;
+import android.util.Log;
+import android.view.KeyEvent;
+
+import com.android.documentsui.model.RootInfo;
+import com.android.documentsui.EventListener;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Random;
+import java.util.concurrent.CountDownLatch;
+
+@LargeTest
+public class FilesActivityPerfTest extends ActivityTest<FilesActivity> {
+
+    // Constants starting with KEY_ are used to report metrics to APCT.
+    private static final String KEY_FILES_LISTED_PERFORMANCE_FIRST =
+            "files-listed-performance-first";
+
+    private static final String KEY_FILES_LISTED_PERFORMANCE_MEDIAN =
+            "files-listed-performance-median";
+
+    private static final String TESTED_URI =
+            "content://com.android.documentsui.stressprovider/document/STRESS_ROOT_1_DOC";
+
+    private static final int NUM_MEASUREMENTS = 10;
+
+    public FilesActivityPerfTest() {
+        super(FilesActivity.class);
+    }
+
+    @Override
+    protected RootInfo getInitialRoot() {
+        return rootDir0;
+    }
+
+    @Override
+    protected String getTestingProviderAuthority() {
+        return DEFAULT_AUTHORITY;
+    }
+
+    @Override
+    protected void setupTestingRoots() throws RemoteException {
+        rootDir0 = mDocsHelper.getRoot(STRESS_ROOT_0_ID);
+        rootDir1 = mDocsHelper.getRoot(STRESS_ROOT_1_ID);
+    }
+
+    @Override
+    public void initTestFiles() throws RemoteException {
+        // Nothing to create, already done by StressProvider.
+    }
+
+    public void testFilesListedPerformance() throws Exception {
+        final BaseActivity activity = getActivity();
+
+        final List<Long> measurements = new ArrayList<Long>();
+        EventListener listener;
+        for (int i = 0; i < 10; i++) {
+            final CountDownLatch signal = new CountDownLatch(1);
+            listener = new EventListener() {
+                @Override
+                public void onDirectoryNavigated(Uri uri) {
+                    if (uri != null && TESTED_URI.equals(uri.toString())) {
+                        mStartTime = System.currentTimeMillis();
+                    } else {
+                        mStartTime = -1;
+                    }
+                }
+
+                @Override
+                public void onDirectoryLoaded(Uri uri) {
+                    if (uri == null || !TESTED_URI.equals(uri.toString())) {
+                        return;
+                    }
+                    assertTrue(mStartTime != -1);
+                    getInstrumentation().waitForIdle(new Runnable() {
+                        @Override
+                        public void run() {
+                            assertTrue(mStartTime != -1);
+                            measurements.add(System.currentTimeMillis() - mStartTime);
+                            signal.countDown();
+                        }
+                    });
+                }
+
+                private long mStartTime = -1;
+            };
+
+            try {
+                activity.addEventListener(listener);
+                bots.roots.openRoot(STRESS_ROOT_1_ID);
+                signal.await();
+            } finally {
+                activity.removeEventListener(listener);
+            }
+
+            assertEquals(i + 1, measurements.size());
+
+            // Go back to the empty root.
+            bots.roots.openRoot(STRESS_ROOT_0_ID);
+        }
+
+        assertEquals(NUM_MEASUREMENTS, measurements.size());
+
+        final Bundle status = new Bundle();
+        status.putDouble(KEY_FILES_LISTED_PERFORMANCE_FIRST, measurements.get(0));
+
+        final Long[] rawMeasurements = measurements.toArray(new Long[NUM_MEASUREMENTS]);
+        Arrays.sort(rawMeasurements);
+
+        final long median = rawMeasurements[NUM_MEASUREMENTS / 2 - 1];
+        status.putDouble(KEY_FILES_LISTED_PERFORMANCE_MEDIAN, median);
+
+        getInstrumentation().sendStatus(Activity.RESULT_OK, status);
+    }
+}
diff --git a/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java b/packages/DocumentsUI/perf-tests/src/com/android/documentsui/StressProvider.java
new file mode 100644 (file)
index 0000000..1bc802a
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.content.Context;
+import android.content.pm.ProviderInfo;
+import android.database.Cursor;
+import android.database.MatrixCursor.RowBuilder;
+import android.database.MatrixCursor;
+import android.os.CancellationSignal;
+import android.os.FileUtils;
+import android.os.ParcelFileDescriptor;
+import android.provider.DocumentsContract.Document;
+import android.provider.DocumentsContract.Root;
+import android.provider.DocumentsContract;
+import android.provider.DocumentsProvider;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Random;
+
+/**
+ * Provider with thousands of files for testing loading time of directories in DocumentsUI.
+ * It doesn't support any file operations.
+ */
+public class StressProvider extends DocumentsProvider {
+
+    public static final String DEFAULT_AUTHORITY = "com.android.documentsui.stressprovider";
+
+    // Empty root.
+    public static final String STRESS_ROOT_0_ID = "STRESS_ROOT_0";
+
+    // Root with thousands of items.
+    public static final String STRESS_ROOT_1_ID = "STRESS_ROOT_1";
+
+    private static final String STRESS_ROOT_0_DOC_ID = "STRESS_ROOT_0_DOC";
+    private static final String STRESS_ROOT_1_DOC_ID = "STRESS_ROOT_1_DOC";
+
+    private static final String[] DEFAULT_ROOT_PROJECTION = new String[] {
+            Root.COLUMN_ROOT_ID, Root.COLUMN_FLAGS, Root.COLUMN_TITLE, Root.COLUMN_DOCUMENT_ID,
+            Root.COLUMN_AVAILABLE_BYTES
+    };
+    private static final String[] DEFAULT_DOCUMENT_PROJECTION = new String[] {
+            Document.COLUMN_DOCUMENT_ID, Document.COLUMN_MIME_TYPE, Document.COLUMN_DISPLAY_NAME,
+            Document.COLUMN_LAST_MODIFIED, Document.COLUMN_FLAGS, Document.COLUMN_SIZE,
+    };
+
+    private String mAuthority = DEFAULT_AUTHORITY;
+    private ArrayList<String> mIds = new ArrayList<>();
+
+    @Override
+    public void attachInfo(Context context, ProviderInfo info) {
+        mAuthority = info.authority;
+        super.attachInfo(context, info);
+    }
+
+    @Override
+    public boolean onCreate() {
+        mIds = new ArrayList();
+        for (int i = 0; i < 10000; i++) {
+            mIds.add(createRandomId(i));
+        }
+        mIds.add(STRESS_ROOT_0_DOC_ID);
+        mIds.add(STRESS_ROOT_1_DOC_ID);
+        return true;
+    }
+
+    @Override
+    public Cursor queryRoots(String[] projection) throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(DEFAULT_ROOT_PROJECTION);
+        includeRoot(result, STRESS_ROOT_0_ID, STRESS_ROOT_0_DOC_ID);
+        includeRoot(result, STRESS_ROOT_1_ID, STRESS_ROOT_1_DOC_ID);
+        return result;
+    }
+
+    @Override
+    public Cursor queryDocument(String documentId, String[] projection)
+            throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
+        includeDocument(result, documentId);
+        return result;
+    }
+
+    @Override
+    public Cursor queryChildDocuments(String parentDocumentId, String[] projection, String sortOrder)
+            throws FileNotFoundException {
+        final MatrixCursor result = new MatrixCursor(DEFAULT_DOCUMENT_PROJECTION);
+        if (STRESS_ROOT_1_DOC_ID.equals(parentDocumentId)) {
+            for (String id : mIds) {
+                includeDocument(result, id);
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public ParcelFileDescriptor openDocument(String docId, String mode, CancellationSignal signal)
+            throws FileNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    private void includeRoot(MatrixCursor result, String rootId, String docId) {
+        final RowBuilder row = result.newRow();
+        row.add(Root.COLUMN_ROOT_ID, rootId);
+        row.add(Root.COLUMN_FLAGS, 0);
+        row.add(Root.COLUMN_TITLE, rootId);
+        row.add(Root.COLUMN_DOCUMENT_ID, docId);
+    }
+
+    private void includeDocument(MatrixCursor result, String id) {
+        final RowBuilder row = result.newRow();
+        row.add(Document.COLUMN_DOCUMENT_ID, id);
+        row.add(Document.COLUMN_DISPLAY_NAME, id);
+        row.add(Document.COLUMN_SIZE, 0);
+        row.add(Document.COLUMN_MIME_TYPE, DocumentsContract.Document.MIME_TYPE_DIR);
+        row.add(Document.COLUMN_FLAGS, 0);
+        row.add(Document.COLUMN_LAST_MODIFIED, null);
+    }
+
+    private static String getDocumentIdForFile(File file) {
+        return file.getAbsolutePath();
+    }
+
+    private String createRandomId(int index) {
+        final Random random = new Random(index);
+        final StringBuilder builder = new StringBuilder();
+        for (int i = 0; i < 20; i++) {
+            builder.append((char) (random.nextInt(96) + 32));
+        }
+        builder.append(index);  // Append a number to guarantee uniqueness.
+        return builder.toString();
+    }
+}
diff --git a/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow_down.xml b/packages/DocumentsUI/res/drawable/ic_breadcrumb_arrow_down.xml
new file mode 100644 (file)
index 0000000..199a308
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<rotate xmlns:android="http://schemas.android.com/apk/res/android"
+        android:fromDegrees="90"
+        android:toDegrees="90"
+        android:pivotX="50%"
+        android:pivotY="50%"
+        android:drawable="@drawable/ic_breadcrumb_arrow">
+</rotate>
\ No newline at end of file
index b0f3cc3..5aeebbb 100644 (file)
@@ -14,8 +14,8 @@ Copyright (C) 2015 The Android Open Source Project
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48dp"
-        android:height="48dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
@@ -1,5 +1,5 @@
 <!--
-Copyright (C) 2014 The Android Open Source Project
+Copyright (C) 2015 The Android Open Source Project
 
    Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -14,11 +14,11 @@ Copyright (C) 2014 The Android Open Source Project
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
+        android:width="24dp"
+        android:height="24dp"
         android:viewportWidth="24.0"
         android:viewportHeight="24.0">
     <path
-        android:pathData="M12.000000,2.000000C6.500000,2.000000 2.000000,6.500000 2.000000,12.000000s4.500000,10.000000 10.000000,10.000000c5.500000,0.000000 10.000000,-4.500000 10.000000,-10.000000S17.500000,2.000000 12.000000,2.000000zM13.000000,17.000000l-2.000000,0.000000l0.000000,-6.000000l2.000000,0.000000L13.000000,17.000000zM13.000000,9.000000l-2.000000,0.000000L11.000000,7.000000l2.000000,0.000000L13.000000,9.000000z"
-        android:fillColor="#FFFFFF"/>
+        android:fillColor="#FF000000"
+        android:pathData="M15 7v4h1v2h-3V5h2l-3,-4,-3 4h2v8H8v-2.07c.7,-.37 1.2,-1.08 1.2,-1.93 0,-1.21,-.99,-2.2,-2.2,-2.2,-1.21 0,-2.2.99,-2.2 2.2 0 .85.5 1.56 1.2 1.93V13c0 1.11.89 2 2 2h3v3.05c-.71.37,-1.2 1.1,-1.2 1.95 0 1.22.99 2.2 2.2 2.2 1.21 0 2.2,-.98 2.2,-2.2 0,-.85,-.49,-1.58,-1.2,-1.95V15h3c1.11 0 2,-.89 2,-2v-2h1V7h-4z"/>
 </vector>
diff --git a/packages/DocumentsUI/res/layout/dialog_delete_confirmation.xml b/packages/DocumentsUI/res/layout/dialog_delete_confirmation.xml
new file mode 100644 (file)
index 0000000..990ce0b
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:paddingTop="30dp"
+    android:gravity="center"
+    android:textAppearance="@android:style/TextAppearance.Material.Subhead"
+    android:textColor="@*android:color/primary_text_default_material_light">
+</TextView>
index 065102b..b65c5a0 100644 (file)
@@ -46,6 +46,8 @@
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
                     android:layout_marginStart="4dp"
+                    android:popupTheme="?actionBarPopupTheme"
+                    android:background="@android:color/transparent"
                     android:overlapAnchor="true" />
 
             </com.android.documentsui.DocumentsToolbar>
index 84a928d..deb0894 100644 (file)
@@ -44,6 +44,8 @@
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_marginStart="4dp"
+                android:popupTheme="?actionBarPopupTheme"
+                android:background="@android:color/transparent"
                 android:overlapAnchor="true" />
 
         </com.android.documentsui.DocumentsToolbar>
index b169ec8..29f65e0 100644 (file)
@@ -73,7 +73,8 @@
             android:layout_width="0dp"
             android:layout_height="wrap_content"
             android:layout_weight="1"
-            android:orientation="vertical" >
+            android:orientation="vertical"
+            android:layout_gravity="center_vertical" >
 
             <TextView
                 android:id="@android:id/title"
index ff80d07..816cb8a 100644 (file)
@@ -27,8 +27,6 @@
     <FrameLayout
         android:layout_width="@dimen/icon_size"
         android:layout_height="@dimen/icon_size"
-        android:layout_marginStart="@dimen/root_icon_margin"
-        android:layout_marginEnd="@dimen/root_icon_margin"
         android:duplicateParentState="true">
 
         <ImageView
@@ -55,7 +53,7 @@
             android:singleLine="true"
             android:ellipsize="end"
             android:textAlignment="viewStart"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@android:style/TextAppearance.Material.Menu"
             android:textColor="@color/item_root_primary_text" />
 
         <TextView
@@ -65,7 +63,7 @@
             android:singleLine="true"
             android:ellipsize="end"
             android:textAlignment="viewStart"
-            android:textAppearance="@android:style/TextAppearance.Material.Body1"
+            android:textAppearance="@android:style/TextAppearance.Material.Caption"
             android:textColor="@color/item_root_primary_text" />
 
     </LinearLayout>
index b8251d1..ffe4afe 100644 (file)
     android:orientation="horizontal"
     android:baselineAligned="false">
 
-    <ImageView
-        android:id="@+id/subdir"
-        android:layout_width="24dp"
-        android:layout_height="24dp"
-        android:paddingEnd="8dp"
-        android:scaleType="centerInside"
-        android:visibility="gone"
-        android:src="@drawable/ic_subdirectory_arrow"
-        android:contentDescription="@null" />
-
     <TextView
         android:id="@android:id/title"
         android:layout_width="0dp"
index de6c523..8d0d807 100644 (file)
@@ -28,6 +28,7 @@
         android:singleLine="true"
         android:ellipsize="end"
         android:textAlignment="viewStart"
+        android:drawablePadding="12dp"
+        android:drawableRight="@drawable/ic_breadcrumb_arrow_down"
         android:textAppearance="@android:style/TextAppearance.DeviceDefault.Widget.ActionBar.Title" />
-
 </LinearLayout>
index 235d22d..7b7e229 100644 (file)
@@ -43,6 +43,8 @@
                 android:id="@+id/stack"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
+                android:popupTheme="?actionBarPopupTheme"
+                android:background="@android:color/transparent"
                 android:layout_marginStart="4dp"
                 android:overlapAnchor="true" />
 
index 73571af..79f6fa9 100644 (file)
         android:showAsAction="never"
         android:visible="false" />
     <item
-        android:id="@+id/menu_advanced"
-        android:showAsAction="never"
-        android:visible="false" />
-    <item
         android:id="@+id/menu_settings"
         android:title="@string/menu_settings"
         android:showAsAction="never"
index 9c66502..8846b62 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Deel via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopieer tans lêers"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Skuif tans lêers"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Vee tans lêers uit"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> oor"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Kopieer tans <xliff:g id="COUNT_1">%1$d</xliff:g> lêers.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sommige lêers is omgeskakel"</string>
     <string name="allow" msgid="7225948811296386551">"Laat toe"</string>
     <string name="deny" msgid="2081879885755434506">"Weier"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Vee lêers uit?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Is jy seker jy wil <xliff:g id="COUNT_1">%1$d</xliff:g> lêers uitvee?</item>
+      <item quantity="one">Is jy seker jy wil <xliff:g id="COUNT_0">%1$d</xliff:g> lêer uitvee?</item>
+    </plurals>
 </resources>
index c255e36..6f975da 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"በሚከተለው በኩል ያጋሩ"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ፋይሎች በመገልበጥ ላይ"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ፋይሎችን በመውሰድ ላይ"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"ፋይሎችን በመሰረዝ ላይ"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> ቀርቷል"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎች በመቅዳት ላይ።</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"አንዳንድ ፋይሎች ተለውጠዋል"</string>
     <string name="allow" msgid="7225948811296386551">"ይፍቀዱ"</string>
     <string name="deny" msgid="2081879885755434506">"ያስተባብሉ"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"ፋይሎች ይሰረዙ?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">እርግጠኛ ነዎት <xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎችን መሰረዝ ይፈልጋሉ?</item>
+      <item quantity="other">እርግጠኛ ነዎት <xliff:g id="COUNT_1">%1$d</xliff:g> ፋይሎችን መሰረዝ ይፈልጋሉ?</item>
+    </plurals>
 </resources>
index 81a4f9b..ea4485b 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Delite preko"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopiranje datoteka"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Datoteke se premeštaju"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Datoteke se brišu"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kopiranje <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke datoteke su konvertovane"</string>
     <string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
     <string name="deny" msgid="2081879885755434506">"Odbij"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Želite li da izbrišete datoteke?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Želite li stvarno da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteku?</item>
+      <item quantity="few">Želite li stvarno da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteke?</item>
+      <item quantity="other">Želite li stvarno da izbrišete <xliff:g id="COUNT_1">%1$d</xliff:g> datoteka?</item>
+    </plurals>
 </resources>
index 7c096d9..66af887 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Споделяне чрез"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Файловете се копират"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Файловете се преместват"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Изтриване на файлове"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Оставащо време: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Копират се <xliff:g id="COUNT_1">%1$d</xliff:g> файла.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Някои файлове бяха преобразувани"</string>
     <string name="allow" msgid="7225948811296386551">"Разрешаване"</string>
     <string name="deny" msgid="2081879885755434506">"Отказване"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Да се изтрият ли файловете?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Наистина ли искате да изтриете <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+      <item quantity="one">Наистина ли искате да изтриете <xliff:g id="COUNT_0">%1$d</xliff:g> файл?</item>
+    </plurals>
 </resources>
index 68a2b42..9f5f932 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Podijeli preko"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopiraju se fajlovi"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Premještanje fajlova"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Brisanje fajlova"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Još <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kopira se <xliff:g id="COUNT_1">%1$d</xliff:g> fajl.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Neke od datoteka su pretvorene"</string>
     <string name="allow" msgid="7225948811296386551">"Dozvoli"</string>
     <string name="deny" msgid="2081879885755434506">"Odbijte"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Zaista želite obrisati fajlove?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one"> Jeste li sigurni da želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajl?</item>
+      <item quantity="few"> Jeste li sigurni da želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajla?</item>
+      <item quantity="other"> Jeste li sigurni da želite izbrisati <xliff:g id="COUNT_1">%1$d</xliff:g> fajlova?</item>
+    </plurals>
 </resources>
index e979b11..2b136f1 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Comparteix mitjançant"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"S\'estan copiant fitxers"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"S\'estan movent fitxers"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Suprimint els fitxers"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Temps restant: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">S\'estan copiant <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"S\'han convertit alguns fitxers"</string>
     <string name="allow" msgid="7225948811296386551">"Permet"</string>
     <string name="deny" msgid="2081879885755434506">"Denega"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Vols suprimir els fitxers?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Confirmes que vols suprimir <xliff:g id="COUNT_1">%1$d</xliff:g> fitxers?</item>
+      <item quantity="one">Confirmes que vols suprimir <xliff:g id="COUNT_0">%1$d</xliff:g> fitxer?</item>
+    </plurals>
 </resources>
index 0f3b4e0..7196c6a 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Sdílet pomocí"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopírování souborů"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Přesouvání souborů"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Mazání souborů"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Zbývající čas: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="few">Kopírování <xliff:g id="COUNT_1">%1$d</xliff:g> souborů</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Některé soubory byly převedeny"</string>
     <string name="allow" msgid="7225948811296386551">"Povolit"</string>
     <string name="deny" msgid="2081879885755434506">"Odepřít"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Smazat soubory?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="few">Opravdu chcete smazat <xliff:g id="COUNT_1">%1$d</xliff:g> soubory?</item>
+      <item quantity="many">Opravdu chcete smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souboru?</item>
+      <item quantity="other">Opravdu chcete smazat <xliff:g id="COUNT_1">%1$d</xliff:g> souborů?</item>
+      <item quantity="one">Opravdu chcete smazat <xliff:g id="COUNT_0">%1$d</xliff:g> soubor?</item>
+    </plurals>
 </resources>
index 3854f0f..ab9271c 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Del via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Flytter filer"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Filerne slettes"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> tilbage"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Nogle filer er konverteret"</string>
     <string name="allow" msgid="7225948811296386551">"Tillad"</string>
     <string name="deny" msgid="2081879885755434506">"Afvis"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Vil du slette filerne?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Er du sikker på, at du vil slette <xliff:g id="COUNT_1">%1$d</xliff:g> fil?</item>
+      <item quantity="other">Er du sikker på, at du vil slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+    </plurals>
 </resources>
index fd7f35c..8c06c7f 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Teilen über"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Dateien werden kopiert"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Dateien werden verschoben"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Dateien werden gelöscht"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Noch <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> Dateien werden kopiert.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Einige Dateien wurden konvertiert"</string>
     <string name="allow" msgid="7225948811296386551">"Zulassen"</string>
     <string name="deny" msgid="2081879885755434506">"Ablehnen"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Dateien löschen?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Möchtest du wirklich <xliff:g id="COUNT_1">%1$d</xliff:g> Dateien löschen?</item>
+      <item quantity="one">Möchtest du wirklich <xliff:g id="COUNT_0">%1$d</xliff:g> Datei löschen?</item>
+    </plurals>
 </resources>
index 6257e17..1752a29 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Κοινή χρήση μέσω"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Αντιγραφή αρχείων"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Μετακίνηση αρχείων"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Διαγραφή αρχείων"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Απομένουν <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Αντιγραφή <xliff:g id="COUNT_1">%1$d</xliff:g> αρχείων.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Ορισμένα αρχεία μετατράπηκαν"</string>
     <string name="allow" msgid="7225948811296386551">"Να επιτρέπεται"</string>
     <string name="deny" msgid="2081879885755434506">"Άρνηση"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Διαγραφή αρχείων;"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Είστε βέβαιοι ότι θέλετε να διαγράψετε <xliff:g id="COUNT_1">%1$d</xliff:g> αρχεία;</item>
+      <item quantity="one">Είστε βέβαιοι ότι θέλετε να διαγράψετε <xliff:g id="COUNT_0">%1$d</xliff:g> αρχείο;</item>
+    </plurals>
 </resources>
index 29b9111..1ba7c2d 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Compartir mediante"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Moviendo archivos"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Borrando los archivos"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Faltan <xliff:g id="DURATION">%s</xliff:g>."</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> archivos</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se convirtieron algunos archivos"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Denegar"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"¿Quieres borrar los archivos?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">¿Confirmas que quieres borrar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
+      <item quantity="one">¿Confirmas que quieres borrar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
+    </plurals>
 </resources>
index 02e6d74..0c1f2dd 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copiando archivos"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Moviendo archivos"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Eliminando archivos"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Tiempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> archivos.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Se han convertido algunos archivos"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Denegar"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"¿Eliminar archivos?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">¿Seguro que quieres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> archivos?</item>
+      <item quantity="one">¿Seguro que quieres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> archivo?</item>
+    </plurals>
 </resources>
index 125d899..c66bae4 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Partekatu honen bidez:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Fitxategiak kopiatzen"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Fitxategiak mugitzea"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Fitxategiak ezabatzea"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Falta den denbora: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi kopiatzen.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Artxibo batzuk bihurtu dira"</string>
     <string name="allow" msgid="7225948811296386551">"Onartu"</string>
     <string name="deny" msgid="2081879885755434506">"Ukatu"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Fitxategiak ezabatu nahi dituzu?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Ziur <xliff:g id="COUNT_1">%1$d</xliff:g> fitxategi ezabatu nahi dituzula?</item>
+      <item quantity="one">Ziur <xliff:g id="COUNT_0">%1$d</xliff:g> fitxategi ezabatu nahi duzula?</item>
+    </plurals>
 </resources>
index 0788598..1dfbe15 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Jaa sovelluksessa"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopioidaan tiedostoja"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Siirretään tiedostoja"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Poistetaan tiedostoja"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> jäljellä"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Kopioidaan <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Joitakin tiedostoja muunnettiin."</string>
     <string name="allow" msgid="7225948811296386551">"Salli"</string>
     <string name="deny" msgid="2081879885755434506">"Kiellä"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Poistetaanko tiedostot?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Haluatko varmasti poistaa <xliff:g id="COUNT_1">%1$d</xliff:g> tiedostoa?</item>
+      <item quantity="one">Haluatko varmasti poistaa <xliff:g id="COUNT_0">%1$d</xliff:g> tiedoston?</item>
+    </plurals>
 </resources>
index 6b4c7fd..08dacac 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Partager par"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers..."</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Déplacement des fichiers"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Suppression des fichiers"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Durée restante : <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Copier de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
     <string name="allow" msgid="7225948811296386551">"Autoriser"</string>
     <string name="deny" msgid="2081879885755434506">"Refuser"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Supprimer les fichiers?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Voulez-vous vraiment supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier?</item>
+      <item quantity="other">Voulez-vous vraiment supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers?</item>
+    </plurals>
 </resources>
index 84021b0..6378191 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Partager via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copie de fichiers en cours"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Déplacement de fichiers"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Suppression des fichiers…"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Temps restant : <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Copie de <xliff:g id="COUNT_1">%1$d</xliff:g> fichier en cours…</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Certains fichiers ont été convertis"</string>
     <string name="allow" msgid="7225948811296386551">"Autoriser"</string>
     <string name="deny" msgid="2081879885755434506">"Refuser"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Supprimer les fichiers ?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Voulez-vous vraiment supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichier ?</item>
+      <item quantity="other">Voulez-vous vraiment supprimer <xliff:g id="COUNT_1">%1$d</xliff:g> fichiers ?</item>
+    </plurals>
 </resources>
index fd03af7..79cc70f 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Compartir a través de"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copiando ficheiros"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Mover ficheiros"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Eliminando ficheiros"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Tempo restante: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Convertéronse algúns ficheiros"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Rexeitar"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Queres eliminar os ficheiros?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Seguro que queres eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+      <item quantity="one">Seguro que queres eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
+    </plurals>
 </resources>
index 2ad2aa7..3598934 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Տարածել"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Ֆայլերի պատճենում"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Ֆայլերի տեղափոխում"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Ֆայլերը ջնջվում են"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Մնացել է <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլի պատճենում:</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Որոշ ֆայլեր փոխարկվել են"</string>
     <string name="allow" msgid="7225948811296386551">"Թույլատրել"</string>
     <string name="deny" msgid="2081879885755434506">"Մերժել"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Ջնջե՞լ ֆայլերը:"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
+      <item quantity="other">Ջնջե՞լ <xliff:g id="COUNT_1">%1$d</xliff:g> ֆայլ:</item>
+    </plurals>
 </resources>
index 66d40d2..d87fad3 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Bagikan melalui"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Menyalin file"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Memindahkan file"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Menghapus file"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> lagi"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> file.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Beberapa file dikonversi"</string>
     <string name="allow" msgid="7225948811296386551">"Izinkan"</string>
     <string name="deny" msgid="2081879885755434506">"Tolak"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Hapus file?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Yakin ingin menghapus <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+      <item quantity="one">Yakin ingin menghapus <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
 </resources>
index 290ec92..5b2531d 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Deila í gegnum"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Afritar skrár"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Skrár færðar"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Eyðir skrám"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> eftir"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Afritar <xliff:g id="COUNT_1">%1$d</xliff:g> skrá.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sumum skrám var umbreytt"</string>
     <string name="allow" msgid="7225948811296386551">"Leyfa"</string>
     <string name="deny" msgid="2081879885755434506">"Hafna"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Eyða skrám?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Ertu viss um að þú viljir eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrá?</item>
+      <item quantity="other">Ertu viss um að þú viljir eyða <xliff:g id="COUNT_1">%1$d</xliff:g> skrám?</item>
+    </plurals>
 </resources>
index 43f5fcb..4785ffc 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Condividi via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copia di file in corso"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Spostamento di file"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Eliminazione dei file"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> rimanenti"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Copia di <xliff:g id="COUNT_1">%1$d</xliff:g> file in corso.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alcuni file sono stati convertiti"</string>
     <string name="allow" msgid="7225948811296386551">"Consenti"</string>
     <string name="deny" msgid="2081879885755434506">"Nega"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Eliminare i file?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Vuoi eliminare <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+      <item quantity="one">Vuoi eliminare <xliff:g id="COUNT_0">%1$d</xliff:g> file?</item>
+    </plurals>
 </resources>
index 622785c..1fb81dd 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"שתף באמצעות"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"מעתיק קבצים"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"מעביר קבצים"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"מחיקת קבצים מתבצעת"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"זמן נותר: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="two">מעתיק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"קבצים מסוימים הומרו"</string>
     <string name="allow" msgid="7225948811296386551">"אפשר"</string>
     <string name="deny" msgid="2081879885755434506">"דחה"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"האם למחוק את הקבצים?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="two">האם אתה בטוח שברצונך למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+      <item quantity="many">האם אתה בטוח שברצונך למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+      <item quantity="other">האם אתה בטוח שברצונך למחוק <xliff:g id="COUNT_1">%1$d</xliff:g> קבצים?</item>
+      <item quantity="one">האם אתה בטוח שברצונך למחוק קובץ <xliff:g id="COUNT_0">%1$d</xliff:g>?</item>
+    </plurals>
 </resources>
index 3319af0..32bc414 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"共有ツール"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"ファイルのコピー中"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ファイルを移動中"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"ファイルを削除しています"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"残り<xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g>個のファイルをコピーしています。</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"一部のファイルが変換されました"</string>
     <string name="allow" msgid="7225948811296386551">"許可"</string>
     <string name="deny" msgid="2081879885755434506">"拒否"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"ファイルを削除しますか?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> 個のファイルを削除してもよろしいですか?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> 個のファイルを削除してもよろしいですか?</item>
+    </plurals>
 </resources>
index 30b78e5..ce32f23 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"გაზიარება:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"მიმდ. ფაილების კოპირება"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"ფაილების გადაადგილება"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"ფაილების წაშლა…"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"დარჩა <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">მიმდინარეობს <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის კოპირება.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"ზოგიერთი ფაილი გარდაქმნილია"</string>
     <string name="allow" msgid="7225948811296386551">"უფლების მიცემა"</string>
     <string name="deny" msgid="2081879885755434506">"აკრძალვა"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"გსურთ ფაილების წაშლა?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">ნამდვილად გსურთ <xliff:g id="COUNT_1">%1$d</xliff:g> ფაილის წაშლა?</item>
+      <item quantity="one">ნამდვილად გსურთ <xliff:g id="COUNT_0">%1$d</xliff:g> ფაილის წაშლა?</item>
+    </plurals>
 </resources>
index ab045c6..ad10920 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Бөлісу"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Файлдарды көшіру"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Файлдар тасымалдануда"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Файлдар жойылуда"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> қалды"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды көшіру.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Кейбір файлдар түрлендірілді"</string>
     <string name="allow" msgid="7225948811296386551">"Рұқсат беру"</string>
     <string name="deny" msgid="2081879885755434506">"Бас тарту"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Файлдарды жою керек пе?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файлды жою керек пе?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> файлды жою керек пе?</item>
+    </plurals>
 </resources>
index ba3a6e3..134b5b8 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Кийинки аркылуу бөлүшүү:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Файлдар көчүрүлүүдө"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Файлдар жылдырылууда…"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Файлдар жок кылынууда"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> калды"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> файл көчүрүлүүдө.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Айрым файлдардын форматы өзгөртүлдү"</string>
     <string name="allow" msgid="7225948811296386551">"Уруксат берүү"</string>
     <string name="deny" msgid="2081879885755434506">"Жок"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Файлдар жок кылынсынбы?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Бул <xliff:g id="COUNT_1">%1$d</xliff:g> файлды чын эле жок кылгыңыз келеби?</item>
+      <item quantity="one">Бул <xliff:g id="COUNT_0">%1$d</xliff:g> файлды чын эле жок кылгыңыз келеби?</item>
+    </plurals>
 </resources>
index 7e42922..194e590 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Bendrinti naudojant"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopijuojami failai"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Perkeliami failai"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Failų ištrynimas"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Liko: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kopijuojamas <xliff:g id="COUNT_1">%1$d</xliff:g> failas.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Kai kurie failai buvo konvertuoti"</string>
     <string name="allow" msgid="7225948811296386551">"Leisti"</string>
     <string name="deny" msgid="2081879885755434506">"Atmesti"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Ištrinti failus?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">]Ar tikrai norite ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failą?</item>
+      <item quantity="few">]Ar tikrai norite ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+      <item quantity="many">]Ar tikrai norite ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failo?</item>
+      <item quantity="other">]Ar tikrai norite ištrinti <xliff:g id="COUNT_1">%1$d</xliff:g> failų?</item>
+    </plurals>
 </resources>
index 14bd7a8..cd4cb5e 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Kopīgot, izmantojot"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Notiek failu kopēšana"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Failu pārvietošana"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Notiek failu dzēšana"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Atlikušais laiks: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="zero">Notiek <xliff:g id="COUNT_1">%1$d</xliff:g> failu kopēšana.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Daži faili tika pārveidoti."</string>
     <string name="allow" msgid="7225948811296386551">"Atļaut"</string>
     <string name="deny" msgid="2081879885755434506">"Noraidīt"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Vai dzēst failus?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="zero">Vai tiešām vēlaties dzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+      <item quantity="one">Vai tiešām vēlaties dzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failu?</item>
+      <item quantity="other">Vai tiešām vēlaties dzēst <xliff:g id="COUNT_1">%1$d</xliff:g> failus?</item>
+    </plurals>
 </resources>
index 8531295..a2617f9 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Дараахаар дамжуулан хуваалцах"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Файлуудыг хуулж байна"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Файлыг зөөвөрлөж байна"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Эдгээр файлыг устгаж байна"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> үлдсэн"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> файлуудыг хуулж байна.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Зарим файлыг хөрвүүлсэн"</string>
     <string name="allow" msgid="7225948811296386551">"Зөвшөөрөх"</string>
     <string name="deny" msgid="2081879885755434506">"Татгалзах"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Эдгээр файлыг устгах уу?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Та <xliff:g id="COUNT_1">%1$d</xliff:g> файлыг устгахдаа итгэлтэй байна уу?</item>
+      <item quantity="one">Та <xliff:g id="COUNT_0">%1$d</xliff:g> файлыг устгахдаа итгэлтэй байна уу?</item>
+    </plurals>
 </resources>
index f747d1a..c44b481 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"द्वारे सामायिक करा"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"फायली कॉपी करीत आहे"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"फायली हलविणे"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"फायली हटवित आहे"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> शिल्लक"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one"><xliff:g id="COUNT_1">%1$d</xliff:g> फाईल कॉपी करीत आहे.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"काही फायली रूपांतरित केल्या होत्या"</string>
     <string name="allow" msgid="7225948811296386551">"अनुमती द्या"</string>
     <string name="deny" msgid="2081879885755434506">"नकार द्या"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"फायली हटवायच्या?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">आपल्याला खात्री आहे की आपण <xliff:g id="COUNT_1">%1$d</xliff:g> फाईल हटवू इच्छिता?</item>
+      <item quantity="other">आपल्याला खात्री आहे की आपण <xliff:g id="COUNT_1">%1$d</xliff:g> फायली हटवू इच्छिता?</item>
+    </plurals>
 </resources>
index d481125..17cd348 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Kongsi melalui"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Menyalin fail"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Mengalihkan fail"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Memadamkan fail"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> lagi"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Menyalin <xliff:g id="COUNT_1">%1$d</xliff:g> fail.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Sesetengah fail telah ditukarkan"</string>
     <string name="allow" msgid="7225948811296386551">"Benarkan"</string>
     <string name="deny" msgid="2081879885755434506">"Nafi"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Padamkan fail?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Adakah anda pasti mahu memadamkan <xliff:g id="COUNT_1">%1$d</xliff:g> fail?</item>
+      <item quantity="one">Adakah anda pasti mahu memadamkan <xliff:g id="COUNT_0">%1$d</xliff:g> fail?</item>
+    </plurals>
 </resources>
index 8271428..d42c98e 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Del via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopierer filer"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Flytter filer"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Sletter filene"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> gjenstår"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Kopierer <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Noen filer er konvertert"</string>
     <string name="allow" msgid="7225948811296386551">"Tillat"</string>
     <string name="deny" msgid="2081879885755434506">"Avslå"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Vil du slette filene?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Er du sikker på at du vil slette <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+      <item quantity="one">Er du sikker på at du vil slette <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
+    </plurals>
 </resources>
index 7330e1e..d334194 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Udostępnij przez:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopiowanie plików"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Przenoszenie plików"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Usuwam pliki"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Pozostało: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="few">Kopiowanie <xliff:g id="COUNT_1">%1$d</xliff:g> plików.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektóre pliki zostały przekonwertowane"</string>
     <string name="allow" msgid="7225948811296386551">"Zezwól"</string>
     <string name="deny" msgid="2081879885755434506">"Odmów"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Usunąć pliki?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="few">Na pewno chcesz usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliki?</item>
+      <item quantity="many">Na pewno chcesz usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> plików?</item>
+      <item quantity="other">Na pewno chcesz usunąć <xliff:g id="COUNT_1">%1$d</xliff:g> pliku?</item>
+      <item quantity="one">Na pewno chcesz usunąć <xliff:g id="COUNT_0">%1$d</xliff:g> plik?</item>
+    </plurals>
 </resources>
index 44f2ab8..cc55006 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Movendo arquivos"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Excluindo arquivos"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> restantes"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Negar"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Excluir arquivos?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Tem certeza de que deseja excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+      <item quantity="other">Tem certeza de que deseja excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+    </plurals>
 </resources>
index 3d999c7..1e51019 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Partilhar através de"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"A copiar ficheiros"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"A mover ficheiros"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Eliminar ficheiros"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Faltam <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">A copiar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns ficheiros foram convertidos"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Recusar"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Pretende eliminar ficheiros?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Tem a certeza de que pretende eliminar <xliff:g id="COUNT_1">%1$d</xliff:g> ficheiros?</item>
+      <item quantity="one">Tem a certeza de que pretende eliminar <xliff:g id="COUNT_0">%1$d</xliff:g> ficheiro?</item>
+    </plurals>
 </resources>
index 44f2ab8..cc55006 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Compartilhar via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Copiando arquivos"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Movendo arquivos"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Excluindo arquivos"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> restantes"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Copiando <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Alguns arquivos foram convertidos"</string>
     <string name="allow" msgid="7225948811296386551">"Permitir"</string>
     <string name="deny" msgid="2081879885755434506">"Negar"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Excluir arquivos?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Tem certeza de que deseja excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+      <item quantity="other">Tem certeza de que deseja excluir <xliff:g id="COUNT_1">%1$d</xliff:g> arquivos?</item>
+    </plurals>
 </resources>
index d256a26..9932bd8 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Trimiteți prin"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Se copiază fișierele"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Se mută fișierele"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Se șterg fișierele"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Timp rămas: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="few">Se copiază <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Unele fișiere au fost convertite"</string>
     <string name="allow" msgid="7225948811296386551">"Permiteți"</string>
     <string name="deny" msgid="2081879885755434506">"Refuzați"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Ștergeți fișierele?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="few">Sigur doriți să ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> fișiere?</item>
+      <item quantity="other">Sigur doriți să ștergeți <xliff:g id="COUNT_1">%1$d</xliff:g> de fișiere?</item>
+      <item quantity="one">Sigur doriți să ștergeți <xliff:g id="COUNT_0">%1$d</xliff:g> fișier?</item>
+    </plurals>
 </resources>
index 161bb19..ebddb27 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Поделиться"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Копирование файлов"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Перемещение файлов"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Удаление файлов…"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Осталось <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Копируется <xliff:g id="COUNT_1">%1$d</xliff:g> файл...</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Формат некоторых файлов изменен"</string>
     <string name="allow" msgid="7225948811296386551">"Разрешить"</string>
     <string name="deny" msgid="2081879885755434506">"Отклонить"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Удаление файлов"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+      <item quantity="few">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+      <item quantity="many">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файлов?</item>
+      <item quantity="other">Удалить <xliff:g id="COUNT_1">%1$d</xliff:g> файла?</item>
+    </plurals>
 </resources>
index 7919533..7b3c213 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Zdieľať"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopírovanie súborov"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Presúvajú sa súbory"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Odstraňujú sa súbory"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Zostáva: <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="few">Kopírujú sa <xliff:g id="COUNT_1">%1$d</xliff:g> súbory.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Niektoré súbory boli konvertované"</string>
     <string name="allow" msgid="7225948811296386551">"Povoliť"</string>
     <string name="deny" msgid="2081879885755434506">"Zamietnuť"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Odstrániť súbory?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="few">Naozaj chcete odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súbory?</item>
+      <item quantity="many">Naozaj chcete odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súboru?</item>
+      <item quantity="other">Naozaj chcete odstrániť <xliff:g id="COUNT_1">%1$d</xliff:g> súborov?</item>
+      <item quantity="one">Naozaj chcete odstrániť <xliff:g id="COUNT_0">%1$d</xliff:g> súbor?</item>
+    </plurals>
 </resources>
index ffa6944..7575ff8 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Делите преко"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Копирање датотека"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Датотеке се премештају"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Датотеке се бришу"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Још <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Копирање <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Неке датотеке су конвертоване"</string>
     <string name="allow" msgid="7225948811296386551">"Дозволи"</string>
     <string name="deny" msgid="2081879885755434506">"Одбиј"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Желите ли да избришете датотеке?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Желите ли стварно да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеку?</item>
+      <item quantity="few">Желите ли стварно да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотеке?</item>
+      <item quantity="other">Желите ли стварно да избришете <xliff:g id="COUNT_1">%1$d</xliff:g> датотека?</item>
+    </plurals>
 </resources>
index 656ef8f..97e6ab0 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Dela via"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kopierar filer"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Filer flyttas"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Filerna tas bort"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> återstår"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">Kopierar <xliff:g id="COUNT_1">%1$d</xliff:g> filer.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Vissa filer konverterades"</string>
     <string name="allow" msgid="7225948811296386551">"Tillåt"</string>
     <string name="deny" msgid="2081879885755434506">"Neka"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Vill du ta bort filerna?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">Vill du ta bort <xliff:g id="COUNT_1">%1$d</xliff:g> filer?</item>
+      <item quantity="one">Vill du ta bort <xliff:g id="COUNT_0">%1$d</xliff:g> fil?</item>
+    </plurals>
 </resources>
index 2488fa2..b5d1150 100644 (file)
@@ -18,4 +18,6 @@
     <dimen name="grid_padding_horiz">16dp</dimen>
     <dimen name="grid_padding_vert">16dp</dimen>
 
+    <dimen name="list_item_padding">24dp</dimen>
+
 </resources>
index ad4c5b9..8881fcd 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"แชร์ผ่าน"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"กำลังคัดลอกไฟล์"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"กำลังย้ายไฟล์"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"กำลังลบไฟล์"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"เหลือ <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">กำลังคัดลอก <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"แปลงบางไฟล์แล้ว"</string>
     <string name="allow" msgid="7225948811296386551">"อนุญาต"</string>
     <string name="deny" msgid="2081879885755434506">"ปฏิเสธ"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"ลบไฟล์เหล่านี้ไหม"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">คุณแน่ใจไหมว่าต้องการลบ <xliff:g id="COUNT_1">%1$d</xliff:g> ไฟล์</item>
+      <item quantity="one">คุณแน่ใจไหมว่าต้องการลบ <xliff:g id="COUNT_0">%1$d</xliff:g> ไฟล์</item>
+    </plurals>
 </resources>
index 8c8b018..1639425 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Ibahagi sa pamamagitan ng"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Kinokopya ang mga file"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Inililipat ang mga file"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Pagde-delete ng mga file"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> na lang ang natitira"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Kumokopya ng <xliff:g id="COUNT_1">%1$d</xliff:g> file.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Na-convert ang ilang file"</string>
     <string name="allow" msgid="7225948811296386551">"Payagan"</string>
     <string name="deny" msgid="2081879885755434506">"Tanggihan"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"I-delete ang mga file?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Sigurado ka bang gusto mong i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> file?</item>
+      <item quantity="other">Sigurado ka bang gusto mong i-delete ang <xliff:g id="COUNT_1">%1$d</xliff:g> na file?</item>
+    </plurals>
 </resources>
index 602f8d7..822a9ed 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Şunu kullanarak paylaş:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Dosyalar kopyalanıyor"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Dosyalar taşınıyor"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Dosyalar siliniyor"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> kaldı"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosya kopyalanıyor.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bazı dosyalar dönüştürüldü"</string>
     <string name="allow" msgid="7225948811296386551">"İzin Ver"</string>
     <string name="deny" msgid="2081879885755434506">"Reddet"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Dosyalar silinsin mi?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> dosyayı silmek istediğinizden emin misiniz?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> dosyayı silmek istediğinizden emin misiniz?</item>
+    </plurals>
 </resources>
index 15ae424..1886ca3 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Надіслати через"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Копіювання файлів"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Переміщення файлів"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Видалення файлів"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"Залишилося <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Копіювання <xliff:g id="COUNT_1">%1$d</xliff:g> файлу.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Деякі файли конвертовано"</string>
     <string name="allow" msgid="7225948811296386551">"Дозвол."</string>
     <string name="deny" msgid="2081879885755434506">"Забор."</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Видалити файли?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файл?</item>
+      <item quantity="few">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файли?</item>
+      <item quantity="many">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлів?</item>
+      <item quantity="other">Видалити <xliff:g id="COUNT_1">%1$d</xliff:g> файлу?</item>
+    </plurals>
 </resources>
index 272677f..82d20e3 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"اشتراک کریں بذریعہ"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"فائلیں کاپی ہو رہی ہیں"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"فائلیں منتقل ہو رہی ہیں"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"فائلیں حذف کی جا رہی ہیں"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> باقی ہے"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں کاپی کی جا رہی ہیں۔</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"کچھ فائلوں کو تبدیل کیا گیا تھا"</string>
     <string name="allow" msgid="7225948811296386551">"اجازت دیں"</string>
     <string name="deny" msgid="2081879885755434506">"مسترد کریں"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"فائلوں کو حذف کریں؟"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">کیا آپ واقعی <xliff:g id="COUNT_1">%1$d</xliff:g> فائلیں حذف کرنا چاہتے ہیں؟</item>
+      <item quantity="one">کیا آپ واقعی <xliff:g id="COUNT_0">%1$d</xliff:g> فائل حذف کرنا چاہتے ہیں؟</item>
+    </plurals>
 </resources>
index 0a599c5..ce43fc2 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Quyidagi orqali ulashish"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Fayllar nusxalanmoqda"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Ko‘chirib o‘tkazilmoqda"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Fayllar o‘chirilmoqda"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> qoldi"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other"> <xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl nusxalanmoqda</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Bir nechta fayllar o‘girildi"</string>
     <string name="allow" msgid="7225948811296386551">"Ruxsat berish"</string>
     <string name="deny" msgid="2081879885755434506">"Rad qilish"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Fayllar o‘chirib tashlansinmi?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other"><xliff:g id="COUNT_1">%1$d</xliff:g> ta fayl o‘chirib tashlansinmi?</item>
+      <item quantity="one"><xliff:g id="COUNT_0">%1$d</xliff:g> ta fayl o‘chirib tashlansinmi?</item>
+    </plurals>
 </resources>
index 83a9204..6e87c81 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"分享方式"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"正在复制文件"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"正在移动文件"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"正在删除文件"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"剩余时间:<xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">正在复制 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件。</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分文件已转换成其他格式"</string>
     <string name="allow" msgid="7225948811296386551">"允许"</string>
     <string name="deny" msgid="2081879885755434506">"拒绝"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"要删除文件吗?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">您确定要删除 <xliff:g id="COUNT_1">%1$d</xliff:g> 个文件吗?</item>
+      <item quantity="one">您确定要删除 <xliff:g id="COUNT_0">%1$d</xliff:g> 个文件吗?</item>
+    </plurals>
 </resources>
index 532f976..345bba4 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"正在複製檔案"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"正在移動檔案"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"正在刪除檔案"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"剩餘 <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">正在複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案。</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
     <string name="allow" msgid="7225948811296386551">"允許"</string>
     <string name="deny" msgid="2081879885755434506">"拒絕"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"要刪除檔案嗎?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">您確定要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
+      <item quantity="one">您確定要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
+    </plurals>
 </resources>
index e8b48cc..c799fb3 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"分享方式:"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"複製檔案"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"正在移動檔案"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"正在刪除檔案"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"剩餘 <xliff:g id="DURATION">%s</xliff:g>"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="other">正在複製 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案。</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"部分檔案已轉換成其他格式"</string>
     <string name="allow" msgid="7225948811296386551">"允許"</string>
     <string name="deny" msgid="2081879885755434506">"拒絕"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"要刪除檔案嗎?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="other">確定要刪除 <xliff:g id="COUNT_1">%1$d</xliff:g> 個檔案嗎?</item>
+      <item quantity="one">確定要刪除 <xliff:g id="COUNT_0">%1$d</xliff:g> 個檔案嗎?</item>
+    </plurals>
 </resources>
index b22f994..eda4f7b 100644 (file)
@@ -67,8 +67,7 @@
     <string name="share_via" msgid="8966594246261344259">"Yabelana nge-"</string>
     <string name="copy_notification_title" msgid="6374299806748219777">"Ikopisha amafayela"</string>
     <string name="move_notification_title" msgid="6193835179777284805">"Ihambisa amafayela"</string>
-    <!-- no translation found for delete_notification_title (3329403967712437496) -->
-    <skip />
+    <string name="delete_notification_title" msgid="3329403967712437496">"Ukususa amafayela"</string>
     <string name="copy_remaining" msgid="6283790937387975095">"<xliff:g id="DURATION">%s</xliff:g> okusele"</string>
     <plurals name="copy_begin" formatted="false" msgid="9071199452634086365">
       <item quantity="one">Ikopisha amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>.</item>
     <string name="notification_copy_files_converted_title" msgid="3153573223054275181">"Amanye amafayela aguqulelwe"</string>
     <string name="allow" msgid="7225948811296386551">"Vumela"</string>
     <string name="deny" msgid="2081879885755434506">"Yala"</string>
-    <!-- no translation found for delete_confirmation_title (1958369150786342998) -->
-    <skip />
-    <!-- no translation found for delete_confirmation_message (6608317554854868128) -->
+    <string name="delete_confirmation_title" msgid="1958369150786342998">"Susa amafayela?"</string>
+    <plurals name="delete_confirmation_message" formatted="false" msgid="6608317554854868128">
+      <item quantity="one">Ingabe uqinisekile ukuthi ufuna ukususa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+      <item quantity="other">Ingabe uqinisekile ukuthi ufuna ukususa amafayela angu-<xliff:g id="COUNT_1">%1$d</xliff:g>?</item>
+    </plurals>
 </resources>
index 3dc111a..6e1b30e 100644 (file)
     <string name="allow">Allow</string>
     <!-- Text in the button asking user to deny access to a given directory. -->
     <string name="deny">Deny</string>
-    <!-- Dialog title shown to users when asking if they want to delete files (a confirmation). -->
-    <string name="delete_confirmation_title">Delete files?</string>
     <!-- Dialog text shown to users when asking if they want to delete files (a confirmation). -->
     <plurals name="delete_confirmation_message">
-        <item quantity="one">Are you sure you want to delete <xliff:g id="count" example="1">%1$d</xliff:g> file?</item>
-        <item quantity="other">Are you sure you want to delete <xliff:g id="count" example="3">%1$d</xliff:g> files?</item>
+        <item quantity="one">Delete <xliff:g id="count" example="1">%1$d</xliff:g> file?</item>
+        <item quantity="other">Delete <xliff:g id="count" example="3">%1$d</xliff:g> files?</item>
     </plurals>
 </resources>
index 95c49ff..6efe9d1 100644 (file)
@@ -22,8 +22,6 @@ import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_ENTER;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_LEAVE;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_SIDE;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.google.common.base.Preconditions.checkState;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -41,6 +39,7 @@ import android.provider.DocumentsContract.Root;
 import android.support.annotation.CallSuper;
 import android.support.annotation.LayoutRes;
 import android.support.annotation.Nullable;
+import android.support.annotation.VisibleForTesting;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.Menu;
@@ -54,7 +53,6 @@ import com.android.documentsui.dirlist.Model;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Preconditions;
 
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
@@ -70,6 +68,7 @@ public abstract class BaseActivity extends Activity
     SearchViewManager mSearchManager;
     DrawerController mDrawer;
     NavigationView mNavigator;
+    List<EventListener> mEventListeners = new ArrayList<>();
 
     private final String mTag;
 
@@ -152,7 +151,6 @@ public abstract class BaseActivity extends Activity
         final MenuItem sortSize = menu.findItem(R.id.menu_sort_size);
         final MenuItem grid = menu.findItem(R.id.menu_grid);
         final MenuItem list = menu.findItem(R.id.menu_list);
-        final MenuItem advanced = menu.findItem(R.id.menu_advanced);
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
 
         // Search uses backend ranking; no sorting, recents doesn't support sort.
@@ -164,9 +162,6 @@ public abstract class BaseActivity extends Activity
         grid.setVisible(mState.derivedMode != State.MODE_GRID);
         list.setVisible(mState.derivedMode != State.MODE_LIST);
 
-        advanced.setVisible(!mState.forceAdvanced);
-        advanced.setTitle(LocalPreferences.getDisplayAdvancedDevices(this)
-                ? R.string.menu_advanced_hide : R.string.menu_advanced_show);
         fileSize.setTitle(LocalPreferences.getDisplayFileSize(this)
                 ? R.string.menu_file_size_hide : R.string.menu_file_size_show);
 
@@ -202,10 +197,6 @@ public abstract class BaseActivity extends Activity
         state.forceSize = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, false);
         state.showSize = state.forceSize || LocalPreferences.getDisplayFileSize(this);
 
-        state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
-        state.showAdvanced = state.forceAdvanced
-                || LocalPreferences.getDisplayAdvancedDevices(this);
-
         state.initAcceptMimes(intent);
         state.excludedAuthorities = getExcludedAuthorities();
 
@@ -281,10 +272,6 @@ public abstract class BaseActivity extends Activity
                 }
                 return true;
 
-            case R.id.menu_advanced:
-                setDisplayAdvancedDevices(!LocalPreferences.getDisplayAdvancedDevices(this));
-                return true;
-
             case R.id.menu_file_size:
                 setDisplayFileSize(!LocalPreferences.getDisplayFileSize(this));
                 return true;
@@ -330,7 +317,10 @@ public abstract class BaseActivity extends Activity
     }
 
     void openContainerDocument(DocumentInfo doc) {
-        checkArgument(doc.isContainer());
+        assert(doc.isContainer());
+
+        notifyDirectoryNavigated(doc.derivedUri);
+
         mState.pushDocument(doc);
         // Show an opening animation only if pressing "back" would get us back to the
         // previous directory. Especially after opening a root document, pressing
@@ -373,7 +363,8 @@ public abstract class BaseActivity extends Activity
     @Override
     public void onSearchChanged(@Nullable String query) {
         // We should not get here if root is not searchable
-        checkState(canSearchRoot());
+        assert(canSearchRoot());
+
         reloadSearch(query);
     }
 
@@ -432,13 +423,6 @@ public abstract class BaseActivity extends Activity
         return mState;
     }
 
-    void setDisplayAdvancedDevices(boolean display) {
-        LocalPreferences.setDisplayAdvancedDevices(this, display);
-        mState.showAdvanced = mState.forceAdvanced | display;
-        RootsFragment.get(getFragmentManager()).onDisplayStateChanged();
-        invalidateOptionsMenu();
-    }
-
     void setDisplayFileSize(boolean display) {
         LocalPreferences.setDisplayFileSize(this, display);
         mState.showSize = display;
@@ -595,6 +579,28 @@ public abstract class BaseActivity extends Activity
         return super.onKeyDown(keyCode, event);
     }
 
+    @VisibleForTesting
+    public void addEventListener(EventListener listener) {
+        mEventListeners.add(listener);
+    }
+
+    @VisibleForTesting
+    public void removeEventListener(EventListener listener) {
+        mEventListeners.remove(listener);
+    }
+
+    public void notifyDirectoryLoaded(Uri uri) {
+        for (EventListener listener : mEventListeners) {
+            listener.onDirectoryLoaded(uri);
+        }
+    }
+
+    void notifyDirectoryNavigated(Uri uri) {
+        for (EventListener listener : mEventListeners) {
+            listener.onDirectoryNavigated(uri);
+        }
+    }
+
     /**
      * Toggles focus between the navigation drawer and the directory listing. If the drawer isn't
      * locked, open/close it as appropriate.
@@ -673,7 +679,8 @@ public abstract class BaseActivity extends Activity
 
         @Override
         protected RootInfo run(RootInfo... roots) {
-            checkArgument(roots.length == 1);
+            assert(roots.length == 1);
+
             final RootInfo currentRoot = roots[0];
             final Collection<RootInfo> cachedRoots = mOwner.mRoots.getRootsBlocking();
             RootInfo homeRoot = null;
@@ -686,7 +693,7 @@ public abstract class BaseActivity extends Activity
                     return null;
                 }
             }
-            Preconditions.checkNotNull(homeRoot);
+            assert(homeRoot != null);
             mHome = mOwner.getRootDocumentBlocking(homeRoot);
             return homeRoot;
         }
index 40bd754..ebc9082 100644 (file)
@@ -82,6 +82,9 @@ public class CreateDirectoryFragment extends DialogFragment {
         builder.setNegativeButton(android.R.string.cancel, null);
         final AlertDialog dialog = builder.create();
 
+        // Workaround for the problem - virtual keyboard doesn't show on the phone.
+        Shared.ensureKeyboardPresent(context, dialog);
+
         editText.setOnEditorActionListener(
                 new OnEditorActionListener() {
                     @Override
index 13b7b14..d2e918c 100644 (file)
@@ -59,7 +59,6 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
     private CancellationSignal mSignal;
     private DirectoryResult mResult;
 
-
     public DirectoryLoader(Context context, int type, RootInfo root, DocumentInfo doc, Uri uri,
             int userSortOrder, boolean inSearchMode) {
         super(context, ProviderExecutor.forAuthority(root.authority));
@@ -84,6 +83,7 @@ public class DirectoryLoader extends AsyncTaskLoader<DirectoryResult> {
         final String authority = mUri.getAuthority();
 
         final DirectoryResult result = new DirectoryResult();
+        result.doc = mDoc;
 
         // Use default document when searching
         if (mSearchMode) {
index 22e438a..6268643 100644 (file)
@@ -22,12 +22,15 @@ import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
 import android.content.ContentProviderClient;
 import android.database.Cursor;
 
+import com.android.documentsui.model.DocumentInfo;
+
 import libcore.io.IoUtils;
 
 public class DirectoryResult implements AutoCloseable {
     ContentProviderClient client;
     public Cursor cursor;
     public Exception exception;
+    public DocumentInfo doc;
 
     public int sortOrder = SORT_ORDER_UNKNOWN;
 
index b3c2846..15bfc3b 100644 (file)
@@ -28,7 +28,6 @@ import android.support.annotation.Nullable;
 import android.util.Log;
 
 import com.android.documentsui.model.DocumentInfo;
-import com.android.internal.util.Preconditions;
 
 import libcore.io.IoUtils;
 
@@ -85,7 +84,7 @@ public final class DocumentClipper {
      * This should be run from inside an AsyncTask.
      */
     public List<DocumentInfo> getDocumentsFromClipData(ClipData clipData) {
-        Preconditions.checkNotNull(clipData);
+        assert(clipData != null);
         final List<DocumentInfo> srcDocs = new ArrayList<>();
 
         int count = clipData.getItemCount();
index ed531a8..12a4186 100644 (file)
@@ -23,7 +23,6 @@ import static com.android.documentsui.State.ACTION_OPEN;
 import static com.android.documentsui.State.ACTION_OPEN_TREE;
 import static com.android.documentsui.State.ACTION_PICK_COPY_DESTINATION;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
-import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -333,7 +332,7 @@ public class DocumentsActivity extends BaseActivity {
 
     @Override
     void onDirectoryCreated(DocumentInfo doc) {
-        checkArgument(doc.isDirectory());
+        assert(doc.isDirectory());
         openContainerDocument(doc);
     }
 
index 536feeb..2f784cb 100644 (file)
 
 package com.android.documentsui;
 
-import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.State.ACTION_MANAGE;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
-import static com.android.internal.util.Preconditions.checkState;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -41,7 +39,6 @@ import com.android.documentsui.dirlist.DirectoryFragment;
 import com.android.documentsui.dirlist.Model;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Preconditions;
 
 import java.util.Arrays;
 import java.util.List;
@@ -101,12 +98,10 @@ public class DownloadsActivity extends BaseActivity {
     public boolean onPrepareOptionsMenu(Menu menu) {
         super.onPrepareOptionsMenu(menu);
 
-        final MenuItem advanced = menu.findItem(R.id.menu_advanced);
         final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
         final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
 
-        advanced.setVisible(false);
         createDir.setVisible(false);
         pasteFromCb.setEnabled(false);
         fileSize.setVisible(false);
@@ -121,11 +116,11 @@ public class DownloadsActivity extends BaseActivity {
         final RootInfo root = getCurrentRoot();
         final DocumentInfo cwd = getCurrentDirectory();
 
-        if (DEBUG) checkState(!mSearchManager.isSearching());
+        assert(!mSearchManager.isSearching());
 
         // If started in manage roots mode, there has to be a cwd (i.e. the root dir of the managed
         // root).
-        Preconditions.checkNotNull(cwd);
+        assert(cwd != null);
 
         // Normal boring directory
         DirectoryFragment.showDirectory(fm, root, cwd, anim);
@@ -133,7 +128,8 @@ public class DownloadsActivity extends BaseActivity {
 
     @Override
     public void onDocumentPicked(DocumentInfo doc, Model model) {
-        Preconditions.checkArgument(!doc.isDirectory());
+        assert(!doc.isDirectory());
+
         // First try managing the document; we expect manager to filter
         // based on authority, so we don't grant.
         final Intent manage = new Intent(DocumentsContract.ACTION_MANAGE_DOCUMENT);
index bcf69c4..9fceff5 100644 (file)
@@ -16,8 +16,6 @@
 
 package com.android.documentsui;
 
-import static com.android.internal.util.Preconditions.checkArgument;
-
 import android.app.Activity;
 import android.support.v4.app.ActionBarDrawerToggle;
 import android.support.v4.widget.DrawerLayout;
@@ -83,7 +81,7 @@ abstract class DrawerController implements DrawerListener {
                 DrawerLayout layout, View drawer, ActionBarDrawerToggle toggle,
                 Toolbar drawerToolbar) {
             mToolbar = drawerToolbar;
-            checkArgument(layout != null);
+            assert(layout != null);
 
             mLayout = layout;
             mDrawer = drawer;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/EventListener.java b/packages/DocumentsUI/src/com/android/documentsui/EventListener.java
new file mode 100644 (file)
index 0000000..c15e9a6
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui;
+
+import android.net.Uri;
+import android.support.annotation.Nullable;
+
+public interface EventListener {
+    /**
+     * @param uri Uri navigated to. If recents, then null.
+     */
+    void onDirectoryNavigated(@Nullable Uri uri);
+
+    /**
+     * @param uri Uri of the loaded directory. If recents, then null.
+     */
+    void onDirectoryLoaded(@Nullable Uri uri);
+}
index a3378ad..c17be06 100644 (file)
@@ -19,8 +19,6 @@ package com.android.documentsui;
 import static com.android.documentsui.OperationDialogFragment.DIALOG_TYPE_UNKNOWN;
 import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.dirlist.DirectoryFragment.ANIM_NONE;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkState;
 
 import android.app.Activity;
 import android.app.FragmentManager;
@@ -97,11 +95,11 @@ public class FilesActivity extends BaseActivity {
             // Launch URIs support sensible activity management, but don't specify a real
             // content target.
             if (DEBUG) Log.d(TAG, "Launching with non-empty stack.");
-            checkState(uri == null || uri.getAuthority() == null ||
+            assert(uri == null || uri.getAuthority() == null ||
                     LauncherActivity.isLaunchUri(uri));
             refreshCurrentRootAndDirectory(ANIM_NONE);
         } else if (intent.getAction() == Intent.ACTION_VIEW) {
-            checkArgument(uri != null);
+            assert(uri != null);
             new OpenUriForViewTask(this).executeOnExecutor(
                     ProviderExecutor.forAuthority(uri.getAuthority()), uri);
         } else if (DocumentsContract.isRootUri(this, uri)) {
@@ -143,7 +141,7 @@ public class FilesActivity extends BaseActivity {
         state.allowMultiple = true;
 
         // Options specific to the DocumentsActivity.
-        checkArgument(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
+        assert(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
 
         final DocumentStack stack = intent.getParcelableExtra(Shared.EXTRA_STACK);
         if (stack != null) {
@@ -212,7 +210,7 @@ public class FilesActivity extends BaseActivity {
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case R.id.menu_create_dir:
-                checkState(canCreateDirectory());
+                assert(canCreateDirectory());
                 showCreateDirectoryDialog();
                 return true;
             case R.id.menu_new_window:
@@ -250,7 +248,7 @@ public class FilesActivity extends BaseActivity {
         final RootInfo root = getCurrentRoot();
         final DocumentInfo cwd = getCurrentDirectory();
 
-        if (DEBUG) checkState(!mSearchManager.isSearching());
+        assert(!mSearchManager.isSearching());
 
         if (cwd == null) {
             DirectoryFragment.showRecentsOpen(fm, anim);
index 4bffc49..c7c61c3 100644 (file)
@@ -17,7 +17,6 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.State.MODE_UNKNOWN;
-import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.content.Context;
 import android.preference.PreferenceManager;
@@ -26,17 +25,9 @@ import com.android.documentsui.State.ViewMode;
 import com.android.documentsui.model.RootInfo;
 
 public class LocalPreferences {
-    private static final String KEY_ADVANCED_DEVICES = "advancedDevices";
     private static final String KEY_FILE_SIZE = "fileSize";
     private static final String ROOT_VIEW_MODE_PREFIX = "rootViewMode-";
 
-    public static boolean getDisplayAdvancedDevices(Context context) {
-        boolean defaultAdvanced = context.getResources()
-                .getBoolean(R.bool.config_defaultAdvancedDevices);
-        return PreferenceManager.getDefaultSharedPreferences(context)
-                .getBoolean(KEY_ADVANCED_DEVICES, defaultAdvanced);
-    }
-
     public static boolean getDisplayFileSize(Context context) {
         return PreferenceManager.getDefaultSharedPreferences(context)
                 .getBoolean(KEY_FILE_SIZE, false);
@@ -48,18 +39,14 @@ public class LocalPreferences {
                 .getInt(createKey(root), fallback);
     }
 
-    public static void setDisplayAdvancedDevices(Context context, boolean display) {
-        PreferenceManager.getDefaultSharedPreferences(context).edit()
-                .putBoolean(KEY_ADVANCED_DEVICES, display).apply();
-    }
-
     public static void setDisplayFileSize(Context context, boolean display) {
         PreferenceManager.getDefaultSharedPreferences(context).edit()
                 .putBoolean(KEY_FILE_SIZE, display).apply();
     }
 
     public static void setViewMode(Context context, RootInfo root, @ViewMode int viewMode) {
-        checkArgument(viewMode != MODE_UNKNOWN);
+        assert(viewMode != MODE_UNKNOWN);
+
         PreferenceManager.getDefaultSharedPreferences(context).edit()
                 .putInt(createKey(root), viewMode).apply();
     }
index 699605f..dcaea15 100644 (file)
 
 package com.android.documentsui;
 
+import static android.os.Environment.STANDARD_DIRECTORIES;
 import static com.android.documentsui.Shared.DEBUG;
-import static com.android.internal.util.Preconditions.checkArgument;
-
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.annotation.StringDef;
+import android.app.Activity;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ResolveInfo;
@@ -33,6 +34,7 @@ import com.android.documentsui.model.RootInfo;
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.services.FileOperationService.OpType;
 import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -363,7 +365,7 @@ public final class Metrics {
         if (operationType == FileOperationService.OPERATION_DELETE) {
             logHistogram(context, histogram, FILEOP_DELETE);
         } else {
-            checkArgument(dst != null);
+            assert(dst != null);
             @Provider int providerType =
                     isSystemProvider(dst.authority) ? PROVIDER_SYSTEM : PROVIDER_EXTERNAL;
             logHistogram(context, histogram, getOpCode(operationType, providerType));
@@ -377,6 +379,84 @@ public final class Metrics {
         logHistogram(context, histogram, getOpCode(operationType, PROVIDER_INTRA));
     }
 
+    // Types for logInvalidScopedAccessRequest
+    public static final String SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS =
+            "scoped_directory_access_invalid_args";
+    public static final String SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY =
+            "scoped_directory_access_invalid_dir";
+    public static final String SCOPED_DIRECTORY_ACCESS_ERROR =
+            "scoped_directory_access_error";
+
+    @StringDef(value = {
+            SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS,
+            SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY,
+            SCOPED_DIRECTORY_ACCESS_ERROR
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InvalidScopedAccess{}
+
+    public static void logInvalidScopedAccessRequest(Context context,
+            @InvalidScopedAccess String type) {
+        MetricsLogger.count(context, type, 1);
+        switch (type) {
+            case SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS:
+            case SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY:
+            case SCOPED_DIRECTORY_ACCESS_ERROR:
+                MetricsLogger.count(context, type, 1);
+                break;
+            default:
+                Log.wtf(TAG, "invalid InvalidScopedAccess: " + type);
+        }
+    }
+
+    // Types for logValidScopedAccessRequest
+    public static final int SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED = 0;
+    public static final int SCOPED_DIRECTORY_ACCESS_GRANTED = 1;
+    public static final int SCOPED_DIRECTORY_ACCESS_DENIED = 2;
+
+    @IntDef(flag = true, value = {
+            SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED,
+            SCOPED_DIRECTORY_ACCESS_GRANTED,
+            SCOPED_DIRECTORY_ACCESS_DENIED
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ScopedAccessGrant {}
+
+    public static void logValidScopedAccessRequest(Activity activity, String directory,
+            @ScopedAccessGrant int type) {
+        int index = -1;
+        for (int i = 0; i < STANDARD_DIRECTORIES.length; i++) {
+            if (STANDARD_DIRECTORIES[i].equals(directory)) {
+                index = i;
+                break;
+            }
+        }
+        final String packageName = activity.getCallingPackage();
+        switch (type) {
+            case SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED:
+                MetricsLogger.action(activity,
+                        MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE,
+                        packageName);
+                MetricsLogger.action(activity,
+                        MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER, index);
+                break;
+            case SCOPED_DIRECTORY_ACCESS_GRANTED:
+                MetricsLogger.action(activity,
+                        MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity,
+                        MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER, index);
+                break;
+            case SCOPED_DIRECTORY_ACCESS_DENIED:
+                MetricsLogger.action(activity,
+                        MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE, packageName);
+                MetricsLogger.action(activity,
+                        MetricsEvent.ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER, index);
+                break;
+            default:
+                Log.wtf(TAG, "invalid ScopedAccessGrant: " + type);
+        }
+    }
+
     /**
      * Internal method for making a MetricsLogger.count call. Increments the given counter by 1.
      *
index 4cba135..c520204 100644 (file)
@@ -220,17 +220,14 @@ class NavigationView {
                         .inflate(R.layout.item_subdir, parent, false);
             }
 
-            final ImageView subdir = (ImageView) convertView.findViewById(R.id.subdir);
             final TextView title = (TextView) convertView.findViewById(android.R.id.title);
             final DocumentInfo doc = getItem(position);
 
             if (position == 0) {
                 final RootInfo root = mEnv.getCurrentRoot();
                 title.setText(root.title);
-                subdir.setVisibility(View.GONE);
             } else {
                 title.setText(doc.displayName);
-                subdir.setVisibility(View.VISIBLE);
             }
 
             return convertView;
index 27d6797..dc529ce 100644 (file)
 package com.android.documentsui;
 
 import static android.os.Environment.isStandardDirectory;
+import static android.os.Environment.STANDARD_DIRECTORIES;
 import static android.os.storage.StorageVolume.EXTRA_DIRECTORY_NAME;
 import static android.os.storage.StorageVolume.EXTRA_STORAGE_VOLUME;
 import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.Metrics.logInvalidScopedAccessRequest;
+import static com.android.documentsui.Metrics.logValidScopedAccessRequest;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_DENIED;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_ERROR;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_GRANTED;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS;
+import static com.android.documentsui.Metrics.SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY;
 
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -73,6 +82,7 @@ public class OpenExternalDirectoryActivity extends Activity {
         final Intent intent = getIntent();
         if (intent == null) {
             if (DEBUG) Log.d(TAG, "missing intent");
+            logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
             setResult(RESULT_CANCELED);
             finish();
             return;
@@ -82,12 +92,14 @@ public class OpenExternalDirectoryActivity extends Activity {
             if (DEBUG)
                 Log.d(TAG, "extra " + EXTRA_STORAGE_VOLUME + " is not a StorageVolume: "
                         + storageVolume);
+            logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
             setResult(RESULT_CANCELED);
             finish();
             return;
         }
         final String directoryName = intent.getStringExtra(EXTRA_DIRECTORY_NAME);
         if (directoryName == null) {
+            logInvalidScopedAccessRequest(this, SCOPED_DIRECTORY_ACCESS_INVALID_ARGUMENTS);
             if (DEBUG) Log.d(TAG, "missing extra " + EXTRA_DIRECTORY_NAME + " on " + intent);
             setResult(RESULT_CANCELED);
             finish();
@@ -125,6 +137,7 @@ public class OpenExternalDirectoryActivity extends Activity {
         } catch (IOException e) {
             Log.e(TAG, "Could not get canonical file for volume " + storageVolume.dump()
                     + " and directory " + directoryName);
+            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
             return false;
         }
         final StorageManager sm =
@@ -138,6 +151,7 @@ public class OpenExternalDirectoryActivity extends Activity {
             if (DEBUG)
                 Log.d(TAG, "Directory '" + directory + "' is not standard (full path: '"
                         + file.getAbsolutePath() + "')");
+            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_INVALID_DIRECTORY);
             return false;
         }
 
@@ -159,6 +173,8 @@ public class OpenExternalDirectoryActivity extends Activity {
         // Checks if the user has granted the permission already.
         final Intent intent = getIntentForExistingPermission(activity, file);
         if (intent != null) {
+            logValidScopedAccessRequest(activity, directory,
+                    SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED);
             activity.setResult(RESULT_OK, intent);
             activity.finish();
             return true;
@@ -166,12 +182,14 @@ public class OpenExternalDirectoryActivity extends Activity {
 
         if (volumeLabel == null) {
             Log.e(TAG, "Could not get volume for " + file);
+            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
             return false;
         }
 
         // Gets the package label.
         final String appLabel = getAppLabel(activity);
         if (appLabel == null) {
+            // Error already logged.
             return false;
         }
 
@@ -198,6 +216,7 @@ public class OpenExternalDirectoryActivity extends Activity {
         try {
             return pm.getApplicationLabel(pm.getApplicationInfo(packageName, 0)).toString();
         } catch (NameNotFoundException e) {
+            logInvalidScopedAccessRequest(activity, SCOPED_DIRECTORY_ACCESS_ERROR);
             Log.w(TAG, "Could not get label for package " + packageName);
             return null;
         }
@@ -217,18 +236,21 @@ public class OpenExternalDirectoryActivity extends Activity {
         return volume.isVisibleForWrite(userId) && root.equals(path);
     }
 
-    private static Uri getGrantedUriPermission(ContentProviderClient provider, File file) {
+    private static Uri getGrantedUriPermission(Context context, ContentProviderClient provider,
+            File file) {
         // Calls ExternalStorageProvider to get the doc id for the file
         final Bundle bundle;
         try {
             bundle = provider.call("getDocIdForFileCreateNewDir", file.getPath(), null);
         } catch (RemoteException e) {
             Log.e(TAG, "Did not get doc id from External Storage provider for " + file, e);
+            logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
             return null;
         }
         final String docId = bundle == null ? null : bundle.getString("DOC_ID");
         if (docId == null) {
             Log.e(TAG, "Did not get doc id from External Storage provider for " + file);
+            logInvalidScopedAccessRequest(context, SCOPED_DIRECTORY_ACCESS_ERROR);
             return null;
         }
         Log.d(TAG, "doc id for " + file + ": " + docId);
@@ -242,9 +264,9 @@ public class OpenExternalDirectoryActivity extends Activity {
         return uri;
     }
 
-    private static Intent createGrantedUriPermissionsIntent(ContentProviderClient provider,
-            File file) {
-        final Uri uri = getGrantedUriPermission(provider, file);
+    private static Intent createGrantedUriPermissionsIntent(Context context,
+            ContentProviderClient provider, File file) {
+        final Uri uri = getGrantedUriPermission(context, provider, file);
         return createGrantedUriPermissionsIntent(uri);
     }
 
@@ -261,7 +283,8 @@ public class OpenExternalDirectoryActivity extends Activity {
     private static Intent getIntentForExistingPermission(OpenExternalDirectoryActivity activity,
             File file) {
         final String packageName = activity.getCallingPackage();
-        final Uri grantedUri = getGrantedUriPermission(activity.getExternalStorageClient(), file);
+        final Uri grantedUri =
+                getGrantedUriPermission(activity, activity.getExternalStorageClient(), file);
         if (DEBUG)
             Log.d(TAG, "checking if " + packageName + " already has permission for " + grantedUri);
         final ActivityManager am =
@@ -298,7 +321,7 @@ public class OpenExternalDirectoryActivity extends Activity {
 
         @Override
         public Dialog onCreateDialog(Bundle savedInstanceState) {
-            final String folder = mFile.getName();
+            final String directory = mFile.getName();
             final Activity activity = getActivity();
             final OnClickListener listener = new OnClickListener() {
 
@@ -306,12 +329,16 @@ public class OpenExternalDirectoryActivity extends Activity {
                 public void onClick(DialogInterface dialog, int which) {
                     Intent intent = null;
                     if (which == DialogInterface.BUTTON_POSITIVE) {
-                        intent = createGrantedUriPermissionsIntent(
+                        intent = createGrantedUriPermissionsIntent(mActivity,
                                 mActivity.getExternalStorageClient(), mFile);
                     }
                     if (which == DialogInterface.BUTTON_NEGATIVE || intent == null) {
+                        logValidScopedAccessRequest(activity, directory,
+                                SCOPED_DIRECTORY_ACCESS_DENIED);
                         activity.setResult(RESULT_CANCELED);
                     } else {
+                        logValidScopedAccessRequest(activity, directory,
+                                SCOPED_DIRECTORY_ACCESS_GRANTED);
                         activity.setResult(RESULT_OK, intent);
                     }
                     activity.finish();
@@ -320,7 +347,7 @@ public class OpenExternalDirectoryActivity extends Activity {
 
             final CharSequence message = TextUtils
                     .expandTemplate(
-                            getText(R.string.open_external_dialog_request), mAppLabel, folder,
+                            getText(R.string.open_external_dialog_request), mAppLabel, directory,
                             mVolumeLabel);
             return new AlertDialog.Builder(activity, R.style.AlertDialogTheme)
                     .setMessage(message)
@@ -333,6 +360,7 @@ public class OpenExternalDirectoryActivity extends Activity {
         public void onCancel(DialogInterface dialog) {
             super.onCancel(dialog);
             final Activity activity = getActivity();
+            logValidScopedAccessRequest(activity, mFile.getName(), SCOPED_DIRECTORY_ACCESS_DENIED);
             activity.setResult(RESULT_CANCELED);
             activity.finish();
         }
index 32543c8..933506c 100644 (file)
@@ -19,7 +19,6 @@ package com.android.documentsui;
 import static com.android.documentsui.services.FileOperationService.OPERATION_DELETE;
 import static com.android.documentsui.services.FileOperationService.OPERATION_MOVE;
 import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
-import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -101,7 +100,8 @@ public class PickFragment extends Fragment {
      */
     public void setPickTarget(
             int action, @OpType int copyOperationSubType, DocumentInfo pickTarget) {
-        checkArgument(copyOperationSubType != OPERATION_DELETE);
+        assert(copyOperationSubType != OPERATION_DELETE);
+
         mAction = action;
         mCopyOperationSubType = copyOperationSubType;
         mPickTarget = pickTarget;
index b0e332f..8145edc 100644 (file)
@@ -19,7 +19,6 @@ package com.android.documentsui;
 import android.os.AsyncTask;
 
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -85,7 +84,7 @@ public class ProviderExecutor extends Thread implements Executor {
     private Executor mNonPreemptingExecutor = new Executor() {
         @Override
         public void execute(Runnable command) {
-            Preconditions.checkNotNull(command);
+            assert(command != null);
             mQueue.add(command);
         }
     };
@@ -93,7 +92,7 @@ public class ProviderExecutor extends Thread implements Executor {
     @Override
     public void execute(Runnable command) {
         preempt();
-        Preconditions.checkNotNull(command);
+        assert(command != null);
         mQueue.add(command);
     }
 
index c4c5124..2b7294a 100644 (file)
@@ -17,8 +17,6 @@
 package com.android.documentsui;
 
 import static com.android.documentsui.Shared.DEBUG;
-import static com.android.documentsui.Shared.TAG;
-import static com.android.internal.util.Preconditions.checkState;
 
 import android.content.ContentProviderClient;
 import android.content.ContentResolver;
@@ -41,7 +39,6 @@ import android.util.Log;
 
 import com.android.documentsui.model.RootInfo;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.util.Preconditions;
 
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
@@ -64,6 +61,8 @@ public class RootsCache {
     public static final Uri sNotificationUri = Uri.parse(
             "content://com.android.documentsui.roots/");
 
+    private static final String TAG = "RootsCache";
+
     private final Context mContext;
     private final ContentObserver mObserver;
     private OnCacheUpdateListener mCacheUpdateListener;
@@ -117,18 +116,22 @@ public class RootsCache {
      * Gather roots from all known storage providers.
      */
     public void updateAsync() {
-        // Verifying an assumption about the recents root being immutable.
-        if (DEBUG) {
-            checkState(mRecentsRoot.authority == null);
-            checkState(mRecentsRoot.rootId == null);
-            checkState(mRecentsRoot.derivedIcon == R.drawable.ic_root_recent);
-            checkState(mRecentsRoot.derivedType == RootInfo.TYPE_RECENTS);
-            checkState(mRecentsRoot.flags == (Root.FLAG_LOCAL_ONLY
-                    | Root.FLAG_SUPPORTS_IS_CHILD
-                    | Root.FLAG_SUPPORTS_CREATE));
-            checkState(mRecentsRoot.title == mContext.getString(R.string.root_recent));
-            checkState(mRecentsRoot.availableBytes == -1);
-        }
+
+        // NOTE: This method is called when the UI language changes.
+        // For that reason we upadte our RecentsRoot to reflect
+        // the current language.
+        mRecentsRoot.title = mContext.getString(R.string.root_recent);
+
+        // Nothing else about the root should ever change.
+        assert(mRecentsRoot.authority == null);
+        assert(mRecentsRoot.rootId == null);
+        assert(mRecentsRoot.derivedIcon == R.drawable.ic_root_recent);
+        assert(mRecentsRoot.derivedType == RootInfo.TYPE_RECENTS);
+        assert(mRecentsRoot.flags == (Root.FLAG_LOCAL_ONLY
+                | Root.FLAG_SUPPORTS_IS_CHILD
+                | Root.FLAG_SUPPORTS_CREATE));
+        assert(mRecentsRoot.availableBytes == -1);
+
         new UpdateTask().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
     }
 
@@ -415,45 +418,64 @@ public class RootsCache {
     static List<RootInfo> getMatchingRoots(Collection<RootInfo> roots, State state) {
         final List<RootInfo> matching = new ArrayList<>();
         for (RootInfo root : roots) {
-            // Exclude read-only devices when creating
-            if (state.action == State.ACTION_CREATE && !root.supportsCreate()) continue;
+
+            if (DEBUG) Log.d(TAG, "Evaluating " + root);
+
+            if (state.action == State.ACTION_CREATE && !root.supportsCreate()) {
+                if (DEBUG) Log.d(TAG, "Excluding read-only root because: ACTION_CREATE.");
+                continue;
+            }
+
             if (state.action == State.ACTION_PICK_COPY_DESTINATION
-                    && !root.supportsCreate()) continue;
-            // Exclude roots that don't support directory picking
-            if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) continue;
-            // Exclude advanced devices when not requested
-            if (!state.showAdvanced && root.isAdvanced()) continue;
-            // Exclude non-local devices when local only
-            if (state.localOnly && !root.isLocalOnly()) continue;
-            // Exclude downloads roots as it doesn't support directory creation (actually
-            // we just don't show them).
-            // TODO: Add flag to check the root supports directory creation.
-            if (state.directoryCopy && !root.isDownloads()) continue;
-
-            // Only show empty roots when creating, or in browse mode.
-            if (root.isEmpty() && (state.action == State.ACTION_OPEN
-                    || state.action == State.ACTION_GET_CONTENT)) {
-                if (DEBUG) Log.i(TAG, "Skipping empty root: " + root);
+                    && !root.supportsCreate()) {
+                if (DEBUG) Log.d(
+                        TAG, "Excluding read-only root because: ACTION_PICK_COPY_DESTINATION.");
+                continue;
+            }
+
+            if (state.action == State.ACTION_OPEN_TREE && !root.supportsChildren()) {
+                if (DEBUG) Log.d(
+                        TAG, "Excluding root !supportsChildren because: ACTION_OPEN_TREE.");
+                continue;
+            }
+
+            if (state.localOnly && !root.isLocalOnly()) {
+                if (DEBUG) Log.d(TAG, "Excluding root because: unwanted non-local device.");
+                continue;
+            }
+
+            if (state.directoryCopy && root.isDownloads()) {
+                if (DEBUG) Log.d(
+                        TAG, "Excluding downloads root because: unsupported directory copy.");
+                continue;
+            }
+
+            if (state.action == State.ACTION_OPEN && root.isEmpty()) {
+                if (DEBUG) Log.d(TAG, "Excluding empty root because: ACTION_OPEN.");
+                continue;
+            }
+
+            if (state.action == State.ACTION_GET_CONTENT && root.isEmpty()) {
+                if (DEBUG) Log.d(TAG, "Excluding empty root because: ACTION_GET_CONTENT.");
                 continue;
             }
 
-            // Only include roots that serve requested content
             final boolean overlap =
                     MimePredicate.mimeMatches(root.derivedMimeTypes, state.acceptMimes) ||
                     MimePredicate.mimeMatches(state.acceptMimes, root.derivedMimeTypes);
             if (!overlap) {
+                if (DEBUG) Log.d(
+                        TAG, "Excluding root because: unsupported content types > "
+                        + state.acceptMimes);
                 continue;
             }
 
-            // Exclude roots from the calling package.
             if (state.excludedAuthorities.contains(root.authority)) {
-                if (DEBUG) Log.d(
-                        TAG, "Excluding root " + root.authority + " from calling package.");
+                if (DEBUG) Log.d(TAG, "Excluding root because: owned by calling package.");
                 continue;
             }
 
-            if (DEBUG) Log.d(
-                    TAG, "Including root " + root + " in roots list.");
+            if (DEBUG) Log.d(TAG, "Including " + root);
             matching.add(root);
         }
         return matching;
index 8beb245..63dc2ee 100644 (file)
@@ -61,7 +61,8 @@ final class SearchViewManager implements
     }
 
     public void install(DocumentsToolbar actionBar) {
-        assert (mActionBar == null);
+        // assert(mActionBar == null);
+
         mActionBar = actionBar;
         mMenu = actionBar.getSearchMenu();
         mView = (SearchView) mMenu.getActionView();
index a288fe8..26900a7 100644 (file)
 package com.android.documentsui;
 
 import android.content.Context;
+import android.content.res.Configuration;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.text.format.Time;
+import android.view.WindowManager;
+import android.app.AlertDialog;
 
 import java.text.Collator;
 import java.util.ArrayList;
@@ -28,6 +31,10 @@ import java.util.List;
 /** @hide */
 public final class Shared {
 
+    public static final String TAG = "Documents";
+
+    public static final boolean DEBUG = true;
+
     /** Intent action name to pick a copy destination. */
     public static final String ACTION_PICK_COPY_DESTINATION =
             "com.android.documentsui.PICK_COPY_DESTINATION";
@@ -79,9 +86,6 @@ public final class Shared {
      */
     public static final String EXTRA_IGNORE_STATE = "ignoreState";
 
-    public static final boolean DEBUG = true;
-    public static final String TAG = "Documents";
-
 
     /**
      * String prefix used to indicate the document is a directory.
@@ -154,4 +158,15 @@ public final class Shared {
 
         return sCollator.compare(lhs, rhs);
     }
+
+    public static boolean isHardwareKeyboardAvailable(Context context) {
+        return context.getResources().getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS;
+    }
+
+    public static void ensureKeyboardPresent(Context context, AlertDialog dialog) {
+        if (!isHardwareKeyboardAvailable(context)) {
+            dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
+        }
+    }
+
 }
index 48c1a73..b4d7971 100644 (file)
@@ -16,8 +16,6 @@
 
 package com.android.documentsui;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-
 import android.app.Activity;
 import android.support.design.widget.Snackbar;
 import android.view.View;
@@ -26,12 +24,13 @@ public final class Snackbars {
     private Snackbars() {}
 
     public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) {
-        return Snackbars.makeSnackbar(activity, activity.getResources().getText(messageId), duration);
+        return Snackbars.makeSnackbar(
+                activity, activity.getResources().getText(messageId), duration);
     }
 
-    public static final Snackbar makeSnackbar(Activity activity, CharSequence message, int duration)
-    {
-        final View view = checkNotNull(activity.findViewById(R.id.coordinator_layout));
+    public static final Snackbar makeSnackbar(
+            Activity activity, CharSequence message, int duration) {
+        final View view = activity.findViewById(R.id.coordinator_layout);
         return Snackbar.make(view, message, duration);
     }
 }
index 62f9ea7..4f460b4 100644 (file)
@@ -82,8 +82,6 @@ public class State implements android.os.Parcelable {
     public boolean forceSize;
     public boolean showSize;
     public boolean localOnly;
-    public boolean forceAdvanced;
-    public boolean showAdvanced;
     public boolean restored;
 
     // Indicates that a copy operation (or move) includes a directory.
@@ -181,8 +179,6 @@ public class State implements android.os.Parcelable {
         out.writeInt(forceSize ? 1 : 0);
         out.writeInt(showSize ? 1 : 0);
         out.writeInt(localOnly ? 1 : 0);
-        out.writeInt(forceAdvanced ? 1 : 0);
-        out.writeInt(showAdvanced ? 1 : 0);
         out.writeInt(restored ? 1 : 0);
         DurableUtils.writeToParcel(out, stack);
         out.writeMap(dirState);
@@ -211,8 +207,6 @@ public class State implements android.os.Parcelable {
             state.forceSize = in.readInt() != 0;
             state.showSize = in.readInt() != 0;
             state.localOnly = in.readInt() != 0;
-            state.forceAdvanced = in.readInt() != 0;
-            state.showAdvanced = in.readInt() != 0;
             state.restored = in.readInt() != 0;
             DurableUtils.readFromParcel(in, state.stack);
             in.readMap(state.dirState, loader);
index d1b2264..83838d3 100644 (file)
@@ -23,9 +23,6 @@ import static com.android.documentsui.State.MODE_LIST;
 import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
-import static com.google.common.base.Preconditions.checkArgument;
 
 import android.annotation.IntDef;
 import android.annotation.StringRes;
@@ -102,6 +99,7 @@ import com.android.documentsui.model.RootInfo;
 import com.android.documentsui.services.FileOperationService;
 import com.android.documentsui.services.FileOperationService.OpType;
 import com.android.documentsui.services.FileOperations;
+
 import com.google.common.collect.Lists;
 
 import java.lang.annotation.Retention;
@@ -170,6 +168,7 @@ public class DirectoryFragment extends Fragment
     private GridLayoutManager mLayout;
     private int mColumnCount = 1;  // This will get updated when layout changes.
 
+    private LayoutInflater mInflater;
     private MessageBar mMessageBar;
     private View mProgressBar;
 
@@ -184,13 +183,12 @@ public class DirectoryFragment extends Fragment
     @Override
     public View onCreateView(
             LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
+        mInflater = inflater;
         final View view = inflater.inflate(R.layout.fragment_directory, container, false);
 
         mMessageBar = MessageBar.create(getChildFragmentManager());
         mProgressBar = view.findViewById(R.id.progressbar);
-
         mEmptyView = view.findViewById(android.R.id.empty);
-
         mRecView = (RecyclerView) view.findViewById(R.id.dir_list);
         mRecView.setRecyclerListener(
                 new RecyclerListener() {
@@ -359,7 +357,9 @@ public class DirectoryFragment extends Fragment
 
     private boolean handleViewItem(String id) {
         final Cursor cursor = mModel.getItem(id);
-        checkNotNull(cursor, "Cursor cannot be null.");
+
+        assert(cursor != null);
+
         final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
         final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
         if (mTuner.isDocumentEnabled(docMimeType, docFlags)) {
@@ -430,7 +430,8 @@ public class DirectoryFragment extends Fragment
         int cellMargin = 2 * getResources().getDimensionPixelSize(R.dimen.grid_item_margin);
         int viewPadding = mRecView.getPaddingLeft() + mRecView.getPaddingRight();
 
-        checkState(mRecView.getWidth() > 0);
+        assert(mRecView.getWidth() > 0);
+
         int columnCount = Math.max(1,
                 (mRecView.getWidth() - viewPadding) / (cellWidth + cellMargin));
 
@@ -471,7 +472,9 @@ public class DirectoryFragment extends Fragment
         public boolean onBeforeItemStateChange(String modelId, boolean selected) {
             if (selected) {
                 final Cursor cursor = mModel.getItem(modelId);
-                checkNotNull(cursor, "Cursor cannot be null.");
+
+                assert(cursor != null);
+
                 final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
                 final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
                 return mTuner.canSelectType(docMimeType, docFlags);
@@ -564,7 +567,7 @@ public class DirectoryFragment extends Fragment
         }
 
         private void updateActionMenu() {
-            checkNotNull(mMenu);
+            assert(mMenu != null);
 
             // Delegate update logic to our owning action, since specialized logic is desired.
             mTuner.updateActionMenu(mMenu, mType, canDeleteSelection(), canRenameSelection());
@@ -699,19 +702,33 @@ public class DirectoryFragment extends Fragment
     }
 
     private void deleteDocuments(final Selection selected) {
+        assert(!selected.isEmpty());
 
-        checkArgument(!selected.isEmpty());
         final DocumentInfo srcParent = getDisplayState().stack.peek();
         new GetDocumentsTask() {
             @Override
             void onDocumentsReady(final List<DocumentInfo> docs) {
+
+                TextView message =
+                        (TextView) mInflater.inflate(R.layout.dialog_delete_confirmation, null);
+                message.setText(
+                        Shared.getQuantityString(
+                                getActivity(),
+                                R.plurals.delete_confirmation_message,
+                                docs.size()));
+
+                // This "insta-hides" files that are being deleted, because
+                // the delete operation may be not execute immediately (it
+                // may be queued up on the FileOperationService.)
+                // To hide the files locally, we call the hide method on the adapter
+                // ...which a live object...cannot be parceled.
+                // For that reason, for now, we implement this dialog NOT
+                // as a fragment (which can survive rotation and have its own state),
+                // but as a simple runtime dialog. So rotating a device with an
+                // active delete dialog...results in that dialog disappearing.
+                // We can do better, but don't have cycles for it now.
                 new AlertDialog.Builder(getActivity())
-                    .setTitle(R.string.delete_confirmation_title)
-                    .setMessage(
-                            Shared.getQuantityString(
-                                    getActivity(),
-                                    R.plurals.delete_confirmation_message,
-                                    docs.size()))
+                    .setView(message)
                     .setPositiveButton(
                          android.R.string.yes,
                          new DialogInterface.OnClickListener() {
@@ -777,7 +794,7 @@ public class DirectoryFragment extends Fragment
     private void renameDocuments(Selection selected) {
         // Batch renaming not supported
         // Rename option is only available in menu when 1 document selected
-        checkArgument(selected.size() == 1);
+        assert(selected.size() == 1);
 
         new GetDocumentsTask() {
             @Override
@@ -890,7 +907,8 @@ public class DirectoryFragment extends Fragment
     }
 
     private void copyFromClipData(final ClipData clipData, final DocumentInfo destination) {
-        checkNotNull(clipData);
+        assert(clipData != null);
+
         new AsyncTask<Void, Void, List<DocumentInfo>>() {
 
             @Override
@@ -941,7 +959,7 @@ public class DirectoryFragment extends Fragment
     }
 
     void copySelectionToClipboard(Selection selection) {
-        checkArgument(!selection.isEmpty());
+        assert(!selection.isEmpty());
         new GetDocumentsTask() {
             @Override
             void onDocumentsReady(List<DocumentInfo> docs) {
@@ -1059,7 +1077,7 @@ public class DirectoryFragment extends Fragment
             String id = getModelId(v);
             if (id != null) {
                 Cursor dstCursor = mModel.getItem(id);
-                checkNotNull(dstCursor, "Cursor cannot be null.");
+                assert(dstCursor != null);
                 return DocumentInfo.fromDirectoryCursor(dstCursor);
             }
 
@@ -1132,10 +1150,11 @@ public class DirectoryFragment extends Fragment
         }
 
         final Cursor cursor = mModel.getItem(modelId);
-        checkNotNull(cursor, "Cursor cannot be null.");
-        final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
 
-        return Lists.newArrayList(doc);
+        assert(cursor != null);
+
+        return Lists.newArrayList(
+                DocumentInfo.fromDirectoryCursor(cursor));
     }
 
     private Drawable getDragShadowIcon(List<DocumentInfo> docs) {
@@ -1285,6 +1304,11 @@ public class DirectoryFragment extends Fragment
                 showDirectory();
                 mAdapter.notifyDataSetChanged();
             }
+
+            if (!model.isLoading()) {
+                ((BaseActivity) getActivity()).notifyDirectoryLoaded(
+                    model.doc != null ? model.doc.derivedUri : null);
+            }
         }
 
         @Override
index 2967a90..3b5ce87 100644 (file)
@@ -16,9 +16,6 @@
 
 package com.android.documentsui.dirlist;
 
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
-
 import android.content.Context;
 import android.database.Cursor;
 import android.graphics.Rect;
@@ -97,19 +94,20 @@ public abstract class DocumentHolder
     @Override
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         // Event listener should always be set.
-        checkNotNull(mEventListener);
+        assert(mEventListener != null);
+
         return mEventListener.onKey(this,  keyCode,  event);
     }
 
     public void addEventListener(DocumentHolder.EventListener listener) {
         // Just handle one for now; switch to a list if necessary.
-        checkState(mEventListener == null);
+        assert(mEventListener == null);
         mEventListener = listener;
     }
 
     public void addOnKeyListener(View.OnKeyListener listener) {
         // Just handle one for now; switch to a list if necessary.
-        checkState(mKeyListener == null);
+        assert(mKeyListener == null);
         mKeyListener = listener;
     }
 
index 0930c22..0bbecf9 100644 (file)
@@ -74,13 +74,6 @@ abstract class DocumentsAdapter
     abstract public SparseArray<String> hide(String... ids);
 
     /**
-     * Unhides a set of previously hidden items.
-     *
-     * @param ids A sparse array of IDs from a previous call to {@link #hide}.
-     */
-    abstract void unhide(SparseArray<String> ids);
-
-    /**
      * Returns a class that yields the span size for a particular element. This is
      * primarily useful in {@link SectionBreakDocumentsAdapterWrapper} where
      * we adjust sizes.
index 8ef8910..f99ec85 100644 (file)
@@ -22,7 +22,6 @@ import static com.android.documentsui.State.ACTION_GET_CONTENT;
 import static com.android.documentsui.State.ACTION_MANAGE;
 import static com.android.documentsui.State.ACTION_OPEN;
 import static com.android.documentsui.State.ACTION_OPEN_TREE;
-import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.content.Context;
 import android.provider.DocumentsContract.Document;
@@ -172,7 +171,7 @@ public abstract class FragmentTuner {
         @Override
         public void updateActionMenu(
                 Menu menu, @ResultType int resultType, boolean canDelete, boolean canRename) {
-            checkArgument(resultType != DirectoryFragment.TYPE_RECENT_OPEN);
+            assert(resultType != DirectoryFragment.TYPE_RECENT_OPEN);
 
             MenuItem open = menu.findItem(R.id.menu_open);
             MenuItem delete = menu.findItem(R.id.menu_delete);
index a0ff1b5..90b2341 100644 (file)
@@ -17,7 +17,6 @@
 package com.android.documentsui.dirlist;
 
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.content.Context;
 import android.database.Cursor;
@@ -58,7 +57,7 @@ final class GridDirectoryHolder extends DocumentHolder {
      * @param state Current display state.
      */
     public void bind(Cursor cursor, String modelId, State state) {
-        checkNotNull(cursor, "Cursor cannot be null.");
+        assert(cursor != null);
 
         this.modelId = modelId;
 
index 8eaed17..a4bce16 100644 (file)
@@ -19,7 +19,6 @@ package com.android.documentsui.dirlist;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.content.Context;
 import android.database.Cursor;
@@ -79,9 +78,9 @@ final class GridDocumentHolder extends DocumentHolder {
      * @param state Current display state.
      */
     public void bind(Cursor cursor, String modelId, State state) {
-        this.modelId = modelId;
+        assert(cursor != null);
 
-        checkNotNull(cursor, "Cursor cannot be null.");
+        this.modelId = modelId;
 
         final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
         final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
index be6413b..0831dbf 100644 (file)
@@ -19,7 +19,6 @@ package com.android.documentsui.dirlist;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.content.Context;
 import android.database.Cursor;
@@ -30,6 +29,7 @@ import android.text.format.Formatter;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.documentsui.R;
@@ -39,9 +39,10 @@ import com.android.documentsui.State;
 
 final class ListDocumentHolder extends DocumentHolder {
     final TextView mTitle;
-    final TextView mSummary;
+    final LinearLayout mDetails;  // Container of date/size/summary
     final TextView mDate;
     final TextView mSize;
+    final TextView mSummary;
     final ImageView mIconMime;
     final ImageView mIconThumb;
     final ImageView mIconCheck;
@@ -51,12 +52,14 @@ final class ListDocumentHolder extends DocumentHolder {
         super(context, parent, R.layout.item_doc_list);
 
         mTitle = (TextView) itemView.findViewById(android.R.id.title);
-        mSummary = (TextView) itemView.findViewById(android.R.id.summary);
         mDate = (TextView) itemView.findViewById(R.id.date);
         mSize = (TextView) itemView.findViewById(R.id.size);
+        mSummary = (TextView) itemView.findViewById(android.R.id.summary);
         mIconMime = (ImageView) itemView.findViewById(R.id.icon_mime);
         mIconThumb = (ImageView) itemView.findViewById(R.id.icon_thumb);
         mIconCheck = (ImageView) itemView.findViewById(R.id.icon_check);
+        // Warning: mDetails view doesn't exists in layout-sw720dp-land layout
+        mDetails = (LinearLayout) itemView.findViewById(R.id.line2);
 
         mIconHelper = iconHelper;
     }
@@ -79,9 +82,9 @@ final class ListDocumentHolder extends DocumentHolder {
      */
     @Override
     public void bind(Cursor cursor, String modelId, State state) {
-        this.modelId = modelId;
+        assert(cursor != null);
 
-        checkNotNull(cursor, "Cursor cannot be null.");
+        this.modelId = modelId;
 
         final String docAuthority = getCursorString(cursor, RootCursorWrapper.COLUMN_AUTHORITY);
         final String docId = getCursorString(cursor, Document.COLUMN_DOCUMENT_ID);
@@ -92,6 +95,7 @@ final class ListDocumentHolder extends DocumentHolder {
         final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
         final String docSummary = getCursorString(cursor, Document.COLUMN_SUMMARY);
         final long docSize = getCursorLong(cursor, Document.COLUMN_SIZE);
+        final boolean isDirectory = Document.MIME_TYPE_DIR.equals(docMimeType);
 
         mIconHelper.stopLoading(mIconThumb);
 
@@ -106,24 +110,39 @@ final class ListDocumentHolder extends DocumentHolder {
         mTitle.setText(docDisplayName, TextView.BufferType.SPANNABLE);
         mTitle.setVisibility(View.VISIBLE);
 
-        if (docSummary != null) {
-            mSummary.setText(docSummary);
-            mSummary.setVisibility(View.VISIBLE);
-        } else {
-            mSummary.setVisibility(View.INVISIBLE);
-        }
 
-        if (docLastModified == -1) {
-            mDate.setText(null);
+        boolean hasDetails = false;
+        if (isDirectory) {
+            // Note, we don't show any details for any directory...ever.
+            hasDetails = false;
         } else {
-            mDate.setText(Shared.formatTime(mContext, docLastModified));
+            if (docSummary != null) {
+                hasDetails = true;
+                mSummary.setText(docSummary);
+                mSummary.setVisibility(View.VISIBLE);
+            } else {
+                mSummary.setVisibility(View.INVISIBLE);
+            }
+
+            if (docLastModified > 0) {
+                hasDetails = true;
+                mDate.setText(Shared.formatTime(mContext, docLastModified));
+            } else {
+                mDate.setText(null);
+            }
+
+            if (state.showSize && docSize > -1) {
+                hasDetails = true;
+                mSize.setVisibility(View.VISIBLE);
+                mSize.setText(Formatter.formatFileSize(mContext, docSize));
+            } else {
+                mSize.setVisibility(View.GONE);
+            }
         }
 
-        if (!state.showSize || Document.MIME_TYPE_DIR.equals(docMimeType) || docSize == -1) {
-            mSize.setVisibility(View.GONE);
-        } else {
-            mSize.setVisibility(View.VISIBLE);
-            mSize.setText(Formatter.formatFileSize(mContext, docSize));
+        // mDetails view doesn't exists in layout-sw720dp-land layout
+        if (mDetails != null) {
+            mDetails.setVisibility(hasDetails ? View.VISIBLE : View.GONE);
         }
     }
 
index 9684a5a..8170e2a 100644 (file)
@@ -22,11 +22,9 @@ import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
 import static com.android.documentsui.State.SORT_ORDER_SIZE;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.database.Cursor;
 import android.os.Bundle;
-import android.os.Looper;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
 import android.support.annotation.Nullable;
@@ -66,6 +64,7 @@ public class Model {
 
     @Nullable String info;
     @Nullable String error;
+    @Nullable DocumentInfo doc;
 
     /**
      * Generates a Model ID for a cursor entry that refers to a document. The Model ID is a unique
@@ -113,6 +112,7 @@ public class Model {
             mPositions.clear();
             info = null;
             error = null;
+            doc = null;
             mIsLoading = false;
             notifyUpdateListeners();
             return;
@@ -127,6 +127,7 @@ public class Model {
         mCursor = result.cursor;
         mCursorCount = mCursor.getCount();
         mSortOrder = result.sortOrder;
+        doc = result.doc;
 
         updateModelData();
 
@@ -381,9 +382,9 @@ public class Model {
         final List<DocumentInfo> docs =  new ArrayList<>(size);
         for (String modelId: items.getAll()) {
             final Cursor cursor = getItem(modelId);
-            checkNotNull(cursor, "Cursor cannot be null.");
-            final DocumentInfo doc = DocumentInfo.fromDirectoryCursor(cursor);
-            docs.add(doc);
+            assert(cursor != null);
+
+            docs.add(DocumentInfo.fromDirectoryCursor(cursor));
         }
         return docs;
     }
index 42dba45..2b07339 100644 (file)
@@ -24,12 +24,12 @@ import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
 import android.database.Cursor;
 import android.provider.DocumentsContract.Document;
-import android.support.annotation.VisibleForTesting;
 import android.util.Log;
 import android.util.SparseArray;
 import android.view.ViewGroup;
 
 import com.android.documentsui.State;
+
 import com.google.common.collect.Sets;
 
 import java.util.ArrayList;
@@ -181,29 +181,6 @@ final class ModelBackedDocumentsAdapter extends DocumentsAdapter {
         return hiddenItems;
     }
 
-    @VisibleForTesting
-    @Override
-    public void unhide(SparseArray<String> ids) {
-        if (DEBUG) Log.d(TAG, "Unhiding ids: " + ids);
-
-        // An ArrayList can shrink at runtime...and in fact
-        // it does when we clear it completely.
-        // This means we can't call add(pos, id) without
-        // first checking the list size.
-        List<String> oldIds = mModelIds;
-        mModelIds = new ArrayList<>(oldIds.size() + ids.size());
-        mModelIds.addAll(oldIds);
-
-        // Finally insert the unhidden items.
-        for (int i = 0; i < ids.size(); i++) {
-            int pos = ids.keyAt(i);
-            String id = ids.get(pos);
-            mHiddenIds.remove(id);
-            mModelIds.add(pos, id);
-            notifyItemInserted(pos);
-        }
-    }
-
     @Override
     public List<String> getModelIds() {
         return mModelIds;
index 4cf1048..b0cc09a 100644 (file)
@@ -19,9 +19,6 @@ package com.android.documentsui.dirlist;
 import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.dirlist.ModelBackedDocumentsAdapter.ITEM_TYPE_DIRECTORY;
 import static com.android.documentsui.dirlist.ModelBackedDocumentsAdapter.ITEM_TYPE_DOCUMENT;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
 
 import android.annotation.IntDef;
 import android.graphics.Point;
@@ -134,8 +131,12 @@ public final class MultiSelectManager {
             @SelectionMode int mode,
             @Nullable Selection initialSelection) {
 
-        mEnvironment = checkNotNull(environment, "'environment' cannot be null.");
-        mAdapter = checkNotNull(adapter, "'adapter' cannot be null.");
+        assert(environment != null);
+        assert(adapter != null);
+
+        mEnvironment = environment;
+        mAdapter = adapter;
+
         mSingleSelect = mode == MODE_SINGLE;
         if (initialSelection != null) {
             mSelection.copyFrom(initialSelection);
@@ -168,8 +169,8 @@ public final class MultiSelectManager {
 
                     @Override
                     public void onItemRangeRemoved(int startPosition, int itemCount) {
-                        checkState(startPosition >= 0);
-                        checkState(itemCount > 0);
+                        assert(startPosition >= 0);
+                        assert(itemCount > 0);
 
                         mSelection.cancelProvisionalSelection();
                         // Remove any disappeared IDs from the selection.
@@ -356,7 +357,8 @@ public final class MultiSelectManager {
      * @param modelId
      */
     public void toggleSelection(String modelId) {
-        checkNotNull(modelId);
+        assert(modelId != null);
+
         boolean changed = false;
         if (mSelection.contains(modelId)) {
             changed = attemptDeselect(modelId);
@@ -389,7 +391,8 @@ public final class MultiSelectManager {
      * @param pos The new end position for the selection range.
      */
     void snapRangeSelection(int pos) {
-        checkNotNull(mRanger);
+        assert(mRanger != null);
+
         mRanger.snapSelection(pos);
         notifySelectionChanged();
     }
@@ -436,7 +439,7 @@ public final class MultiSelectManager {
      * @param selected New selection state.
      */
     private void updateRange(int begin, int end, boolean selected) {
-        checkState(end >= begin);
+        assert(end >= begin);
         for (int i = begin; i <= end; i++) {
             String id = mAdapter.getModelId(i);
             if (id == null) {
@@ -474,7 +477,7 @@ public final class MultiSelectManager {
      * @return True if the update was applied.
      */
     private boolean attemptDeselect(String id) {
-        checkArgument(id != null);
+        assert(id != null);
         if (notifyBeforeItemStateChange(id, false)) {
             mSelection.remove(id);
             notifyItemStateChanged(id, false);
@@ -491,7 +494,7 @@ public final class MultiSelectManager {
      * @return True if the update was applied.
      */
     private boolean attemptSelect(String id) {
-        checkArgument(id != null);
+        assert(id != null);
         boolean canSelect = notifyBeforeItemStateChange(id, true);
         if (!canSelect) {
             return false;
@@ -519,7 +522,7 @@ public final class MultiSelectManager {
      * (identified by {@code position}) changes.
      */
     private void notifyItemStateChanged(String id, boolean selected) {
-        checkArgument(id != null);
+        assert(id != null);
         int lastListener = mCallbacks.size() - 1;
         for (int i = lastListener; i > -1; i--) {
             mCallbacks.get(i).onItemStateChanged(id, selected);
@@ -555,8 +558,8 @@ public final class MultiSelectManager {
         }
 
         private void snapSelection(int position) {
-            checkState(mRanger != null);
-            checkArgument(position != RecyclerView.NO_POSITION);
+            assert(mRanger != null);
+            assert(position != RecyclerView.NO_POSITION);
 
             if (mEnd == UNDEFINED || mEnd == mBegin) {
                 // Reset mEnd so it can be established in establishRange.
@@ -568,7 +571,7 @@ public final class MultiSelectManager {
         }
 
         private void establishRange(int position) {
-            checkState(mRanger.mEnd == UNDEFINED);
+            assert(mRanger.mEnd == UNDEFINED);
 
             if (position == mBegin) {
                 mEnd = position;
@@ -584,8 +587,8 @@ public final class MultiSelectManager {
         }
 
         private void reviseRange(int position) {
-            checkState(mEnd != UNDEFINED);
-            checkState(mBegin != mEnd);
+            assert(mEnd != UNDEFINED);
+            assert(mBegin != mEnd);
 
             if (position == mEnd) {
                 if (DEBUG) Log.i(TAG, "Skipping no-op revision click on mEndRange.");
@@ -1185,7 +1188,7 @@ public final class MultiSelectManager {
          * @param input
          */
         private void processInputEvent(InputEvent input) {
-            checkArgument(input.isMouseEvent());
+            assert(input.isMouseEvent());
 
             if (shouldStop(input)) {
                 endBandSelect();
@@ -1199,7 +1202,6 @@ public final class MultiSelectManager {
             }
 
             mCurrentPosition = input.getOrigin();
-            mModel.resizeSelection(input.getOrigin());
             scrollViewIfNecessary();
             resizeBandSelectRectangle();
         }
@@ -1488,6 +1490,7 @@ public final class MultiSelectManager {
          *     top-left of the viewport would have a relative origin of (0, 0), even though its
          *     absolute point has a higher y-value.
          */
+        @VisibleForTesting
         void resizeSelection(Point relativePointer) {
             mPointer = mHelper.createAbsolutePoint(relativePointer);
             updateModel();
@@ -1615,7 +1618,7 @@ public final class MultiSelectManager {
         private void updateSelection(Rect rect) {
             int columnStart =
                     Collections.binarySearch(mColumnBounds, new Limits(rect.left, rect.left));
-            checkState(columnStart >= 0);
+            assert(columnStart >= 0);
             int columnEnd = columnStart;
 
             for (int i = columnStart; i < mColumnBounds.size()
index 38a71ec..884abbb 100644 (file)
@@ -17,7 +17,6 @@
 package com.android.documentsui.dirlist;
 
 import static com.android.documentsui.Shared.TAG;
-import static com.android.internal.util.Preconditions.checkArgument;
 
 import android.app.AlertDialog;
 import android.app.Dialog;
@@ -36,9 +35,9 @@ import android.support.annotation.Nullable;
 import android.support.design.widget.Snackbar;
 import android.util.Log;
 import android.view.KeyEvent;
-import android.view.inputmethod.EditorInfo;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.inputmethod.EditorInfo;
 import android.widget.EditText;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
@@ -93,6 +92,9 @@ public class RenameDocumentFragment extends DialogFragment {
 
         final AlertDialog dialog = builder.create();
 
+        // Workaround for the problem - virtual keyboard doesn't show on the phone.
+        Shared.ensureKeyboardPresent(context, dialog);
+
         mEditText.setOnEditorActionListener(
                 new OnEditorActionListener() {
                     @Override
@@ -205,7 +207,7 @@ public class RenameDocumentFragment extends DialogFragment {
 
         @Override
         protected DocumentInfo doInBackground(DocumentInfo... document) {
-            checkArgument(document.length == 1);
+            assert(document.length == 1);
             final ContentResolver resolver = mActivity.getContentResolver();
             ContentProviderClient client = null;
 
index 2485ad9..b698059 100644 (file)
@@ -16,8 +16,6 @@
 
 package com.android.documentsui.dirlist;
 
-import static com.android.internal.util.Preconditions.checkArgument;
-
 import android.content.Context;
 import android.database.Cursor;
 import android.support.v7.widget.GridLayoutManager;
@@ -171,13 +169,6 @@ final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter {
     }
 
     @Override
-    void unhide(SparseArray<String> ids) {
-        // NOTE: We hear about these changes and adjust break position
-        // in our AdapterDataObserver.
-        mDelegate.unhide(ids);
-    }
-
-    @Override
     List<String> getModelIds() {
         return mDelegate.getModelIds();
     }
@@ -204,12 +195,12 @@ final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter {
         }
 
         public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
-            checkArgument(itemCount == 1);
+            assert(itemCount == 1);
             notifyItemRangeChanged(toViewPosition(positionStart), itemCount, payload);
         }
 
         public void onItemRangeInserted(int positionStart, int itemCount) {
-            checkArgument(itemCount == 1);
+            assert(itemCount == 1);
             if (positionStart < mBreakPosition) {
                 mBreakPosition++;
             }
@@ -217,7 +208,7 @@ final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter {
         }
 
         public void onItemRangeRemoved(int positionStart, int itemCount) {
-            checkArgument(itemCount == 1);
+            assert(itemCount == 1);
             if (positionStart < mBreakPosition) {
                 mBreakPosition--;
             }
index 3897058..3eaf10a 100644 (file)
@@ -16,6 +16,7 @@
 
 package com.android.documentsui.model;
 
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.compareToIgnoreCaseNullable;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
@@ -31,6 +32,7 @@ import android.os.Parcelable;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
 import android.text.TextUtils;
+import android.util.Log;
 
 import com.android.documentsui.IconUtils;
 import com.android.documentsui.R;
@@ -47,6 +49,8 @@ import java.util.Objects;
  * Representation of a {@link Root}.
  */
 public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
+
+    private static final String TAG = "RootInfo";
     private static final int VERSION_INIT = 1;
     private static final int VERSION_DROP_TYPE = 2;
 
@@ -59,6 +63,8 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
             TYPE_DOWNLOADS,
             TYPE_LOCAL,
             TYPE_MTP,
+            TYPE_SD,
+            TYPE_USB,
             TYPE_OTHER
     })
     @Retention(RetentionPolicy.SOURCE)
@@ -70,7 +76,9 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
     public static final int TYPE_DOWNLOADS = 5;
     public static final int TYPE_LOCAL = 6;
     public static final int TYPE_MTP = 7;
-    public static final int TYPE_OTHER = 8;
+    public static final int TYPE_SD = 8;
+    public static final int TYPE_USB = 9;
+    public static final int TYPE_OTHER = 10;
 
     public String authority;
     public String rootId;
@@ -185,33 +193,40 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
     private void deriveFields() {
         derivedMimeTypes = (mimeTypes != null) ? mimeTypes.split("\n") : null;
 
-        // TODO: remove these special case icons
         if (isHome()) {
-            derivedIcon = R.drawable.ic_root_documents;
             derivedType = TYPE_LOCAL;
+            derivedIcon = R.drawable.ic_root_documents;
+        } else if (isMtp()) {
+            derivedType = TYPE_MTP;
+            derivedIcon = R.drawable.ic_usb_storage;
+        } else if (isUsb()) {
+            derivedType = TYPE_USB;
+            derivedIcon = R.drawable.ic_usb_storage;
+        } else if (isSd()) {
+            derivedType = TYPE_SD;
+            derivedIcon = R.drawable.ic_sd_storage;
         } else if (isExternalStorage()) {
-            derivedIcon = R.drawable.ic_root_smartphone;
             derivedType = TYPE_LOCAL;
-            // TODO: Apply SD card icon to SD devices.
+            derivedIcon = R.drawable.ic_root_smartphone;
         } else if (isDownloads()) {
-            derivedIcon = R.drawable.ic_root_download;
             derivedType = TYPE_DOWNLOADS;
+            derivedIcon = R.drawable.ic_root_download;
         } else if (isImages()) {
-            derivedIcon = R.drawable.ic_doc_image;
             derivedType = TYPE_IMAGES;
+            derivedIcon = R.drawable.ic_doc_image;
         } else if (isVideos()) {
-            derivedIcon = R.drawable.ic_doc_video;
             derivedType = TYPE_VIDEO;
+            derivedIcon = R.drawable.ic_doc_video;
         } else if (isAudio()) {
-            derivedIcon = R.drawable.ic_doc_audio;
             derivedType = TYPE_AUDIO;
+            derivedIcon = R.drawable.ic_doc_audio;
         } else if (isRecents()) {
             derivedType = TYPE_RECENTS;
-        } else if (isMtp()) {
-            derivedType = TYPE_MTP;
         } else {
             derivedType = TYPE_OTHER;
         }
+
+        if (DEBUG) Log.d(TAG, "Finished deriving fields: " + this);
     }
 
     public Uri getUri() {
@@ -283,10 +298,6 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
         return (flags & Root.FLAG_SUPPORTS_SEARCH) != 0;
     }
 
-    public boolean isAdvanced() {
-        return (flags & Root.FLAG_ADVANCED) != 0;
-    }
-
     public boolean isLocalOnly() {
         return (flags & Root.FLAG_LOCAL_ONLY) != 0;
     }
@@ -295,6 +306,14 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
         return (flags & Root.FLAG_EMPTY) != 0;
     }
 
+    public boolean isSd() {
+        return (flags & Root.FLAG_REMOVABLE_SD) != 0;
+    }
+
+    public boolean isUsb() {
+        return (flags & Root.FLAG_REMOVABLE_USB) != 0;
+    }
+
     public Drawable loadIcon(Context context) {
         if (derivedIcon != 0) {
             return context.getDrawable(derivedIcon);
@@ -362,7 +381,14 @@ public class RootInfo implements Durable, Parcelable, Comparable<RootInfo> {
 
     @Override
     public String toString() {
-        return "Root{authority=" + authority + ", rootId=" + rootId + ", title=" + title + "}";
+        return "Root{"
+                + "authority=" + authority
+                + ", rootId=" + rootId
+                + ", title=" + title
+                + ", isUsb=" + isUsb()
+                + ", isSd=" + isSd()
+                + ", isMtp=" + isMtp()
+                + "}";
     }
 
     public String getDirectoryString() {
index faedd5e..ad48a70 100644 (file)
@@ -29,7 +29,6 @@ import static com.android.documentsui.services.FileOperationService.EXTRA_DIALOG
 import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
 import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
 import static com.android.documentsui.services.FileOperationService.OPERATION_COPY;
-import static com.google.common.base.Preconditions.checkArgument;
 
 import android.annotation.StringRes;
 import android.app.Notification;
@@ -95,7 +94,7 @@ class CopyJob extends Job {
             String id, DocumentStack stack, List<DocumentInfo> srcs) {
         super(service, appContext, listener, OPERATION_COPY, id, stack);
 
-        checkArgument(!srcs.isEmpty());
+        assert(!srcs.isEmpty());
         this.mSrcs = srcs;
     }
 
@@ -108,7 +107,7 @@ class CopyJob extends Job {
             @OpType int opType, String id, DocumentStack destination, List<DocumentInfo> srcs) {
         super(service, appContext, listener, opType, id, destination);
 
-        checkArgument(!srcs.isEmpty());
+        assert(!srcs.isEmpty());
         this.mSrcs = srcs;
     }
 
index 05a3f11..580fa38 100644 (file)
@@ -17,9 +17,6 @@
 package com.android.documentsui.services;
 
 import static com.android.documentsui.Shared.DEBUG;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.internal.util.Preconditions.checkState;
 
 import android.annotation.IntDef;
 import android.app.NotificationManager;
@@ -136,12 +133,12 @@ public class FileOperationService extends Service implements Job.Listener {
 
         String jobId = intent.getStringExtra(EXTRA_JOB_ID);
         @OpType int operationType = intent.getIntExtra(EXTRA_OPERATION, OPERATION_UNKNOWN);
-        checkArgument(jobId != null);
+        assert(jobId != null);
 
         if (intent.hasExtra(EXTRA_CANCEL)) {
             handleCancel(intent);
         } else {
-            checkArgument(operationType != OPERATION_UNKNOWN);
+            assert(operationType != OPERATION_UNKNOWN);
             handleOperation(intent, serviceId, jobId, operationType);
         }
 
@@ -173,9 +170,9 @@ public class FileOperationService extends Service implements Job.Listener {
             mWakeLock.acquire();
         }
 
-        checkState(job != null);
+        assert(job != null);
         int delay = intent.getIntExtra(EXTRA_DELAY, DEFAULT_DELAY);
-        checkArgument(delay <= MAX_DELAY);
+        assert(delay <= MAX_DELAY);
         if (DEBUG) Log.d(
                 TAG, "Scheduling job " + job.id + " to run in " + delay + " milliseconds.");
         ScheduledFuture<?> future = executor.schedule(job, delay, TimeUnit.MILLISECONDS);
@@ -188,8 +185,10 @@ public class FileOperationService extends Service implements Job.Listener {
      * @param intent The cancellation intent.
      */
     private void handleCancel(Intent intent) {
-        checkArgument(intent.hasExtra(EXTRA_CANCEL));
-        String jobId = checkNotNull(intent.getStringExtra(EXTRA_JOB_ID));
+        assert(intent.hasExtra(EXTRA_CANCEL));
+        assert(intent.getStringExtra(EXTRA_JOB_ID) != null);
+
+        String jobId = intent.getStringExtra(EXTRA_JOB_ID);
 
         if (DEBUG) Log.d(TAG, "handleCancel: " + jobId);
 
@@ -253,7 +252,8 @@ public class FileOperationService extends Service implements Job.Listener {
                 throw new UnsupportedOperationException();
         }
 
-        return checkNotNull(job);
+        assert(job != null);
+        return job;
     }
 
     @GuardedBy("mRunning")
@@ -261,7 +261,7 @@ public class FileOperationService extends Service implements Job.Listener {
         if (DEBUG) Log.d(TAG, "deleteJob: " + job.id);
 
         JobRecord record = mRunning.remove(job.id);
-        checkArgument(record != null);
+        assert(record != null);
         record.job.cleanup();
 
         if (mRunning.isEmpty()) {
index a158654..c723ac6 100644 (file)
@@ -23,8 +23,6 @@ import static com.android.documentsui.services.FileOperationService.EXTRA_JOB_ID
 import static com.android.documentsui.services.FileOperationService.EXTRA_OPERATION;
 import static com.android.documentsui.services.FileOperationService.EXTRA_SRC_LIST;
 import static com.android.documentsui.services.FileOperationService.OPERATION_UNKNOWN;
-import static com.android.internal.util.Preconditions.checkArgument;
-import static com.android.internal.util.Preconditions.checkNotNull;
 
 import android.annotation.DrawableRes;
 import android.annotation.PluralsRes;
@@ -98,7 +96,7 @@ abstract public class Job implements Runnable {
     Job(Context service, Context appContext, Listener listener,
             @OpType int operationType, String id, DocumentStack stack) {
 
-        checkArgument(operationType != OPERATION_UNKNOWN);
+        assert(operationType != OPERATION_UNKNOWN);
 
         this.service = service;
         this.appContext = appContext;
@@ -150,7 +148,8 @@ abstract public class Job implements Runnable {
             mClients.put(doc.authority, client);
         }
 
-        return checkNotNull(client);
+        assert(client != null);
+        return client;
     }
 
     final void cleanup() {
index b5826a4..dc39235 100644 (file)
@@ -21,11 +21,9 @@ import static com.android.documentsui.services.FileOperationService.OPERATION_MO
 import android.app.Notification;
 import android.app.Notification.Builder;
 import android.content.Context;
-import android.net.Uri;
 import android.os.RemoteException;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
-import android.util.Log;
 
 import com.android.documentsui.R;
 import com.android.documentsui.model.DocumentInfo;
@@ -36,7 +34,6 @@ import java.util.List;
 // TODO: Stop extending CopyJob.
 final class MoveJob extends CopyJob {
 
-    private static final String TAG = "MoveJob";
     final DocumentInfo mSrcParent;
 
     /**
index adcfef3..683fd6c 100644 (file)
@@ -32,8 +32,11 @@ import android.support.test.uiautomator.Configurator;
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObjectNotFoundException;
 import android.test.ActivityInstrumentationTestCase2;
+import android.util.Log;
 import android.view.MotionEvent;
 
+import com.android.documentsui.BaseActivity;
+import com.android.documentsui.EventListener;
 import com.android.documentsui.bots.DirectoryListBot;
 import com.android.documentsui.bots.KeyboardBot;
 import com.android.documentsui.bots.RootsListBot;
@@ -64,7 +67,6 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen
 
     public RootInfo rootDir0;
     public RootInfo rootDir1;
-
     ContentResolver mResolver;
     DocumentsProviderHelper mDocsHelper;
     ContentProviderClient mClient;
@@ -84,6 +86,23 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen
         return rootDir0;
     }
 
+    /**
+     * Returns the authority of the testing provider begin used.
+     * By default it's StubProvider's authority.
+     * @return Authority of the provider.
+     */
+    protected String getTestingProviderAuthority() {
+        return DEFAULT_AUTHORITY;
+    }
+
+    /**
+     * Resolves testing roots.
+     */
+    protected void setupTestingRoots() throws RemoteException {
+        rootDir0 = mDocsHelper.getRoot(ROOT_0_ID);
+        rootDir1 = mDocsHelper.getRoot(ROOT_1_ID);
+    }
+
     @Override
     public void setUp() throws Exception {
         device = UiDevice.getInstance(getInstrumentation());
@@ -93,18 +112,14 @@ public abstract class ActivityTest<T extends Activity> extends ActivityInstrumen
         bots = new Bots(device, context, TIMEOUT);
 
         Configurator.getInstance().setToolType(MotionEvent.TOOL_TYPE_MOUSE);
-        bots.main.revealLauncher();
 
         mResolver = context.getContentResolver();
-        mClient = mResolver.acquireUnstableContentProviderClient(DEFAULT_AUTHORITY);
-        mDocsHelper = new DocumentsProviderHelper(DEFAULT_AUTHORITY, mClient);
+        mClient = mResolver.acquireUnstableContentProviderClient(getTestingProviderAuthority());
+        mDocsHelper = new DocumentsProviderHelper(getTestingProviderAuthority(), mClient);
 
-        rootDir0 = mDocsHelper.getRoot(ROOT_0_ID);
-        rootDir1 = mDocsHelper.getRoot(ROOT_1_ID);
+        setupTestingRoots();
 
         launchActivity();
-
-        bots.main.revealApp();
         resetStorage();
     }
 
index 7d3498e..e73dd8c 100644 (file)
@@ -16,6 +16,9 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.RootsCache.getMatchingRoots;
+import static com.google.common.collect.Lists.newArrayList;
+
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
@@ -28,23 +31,18 @@ import java.util.List;
 @SmallTest
 public class RootsCacheTest extends AndroidTestCase {
 
-    private static RootInfo buildForMimeTypes(String... mimeTypes) {
-        final RootInfo root = new RootInfo();
-        root.derivedMimeTypes = mimeTypes;
-        return root;
-    }
-
-    private RootInfo mNull = new RootInfo();
-    private RootInfo mEmpty = buildForMimeTypes();
-    private RootInfo mWild = buildForMimeTypes("*/*");
-    private RootInfo mImages = buildForMimeTypes("image/*");
-    private RootInfo mAudio = buildForMimeTypes("audio/*", "application/ogg", "application/x-flac");
-    private RootInfo mDocs = buildForMimeTypes("application/msword", "application/vnd.ms-excel");
-    private RootInfo mMalformed1 = buildForMimeTypes("meow");
-    private RootInfo mMalformed2 = buildForMimeTypes("*/meow");
+    private static RootInfo mNull = new RootInfo();
+    private static RootInfo mEmpty = buildForMimeTypes();
+    private static RootInfo mWild = buildForMimeTypes("*/*");
+    private static RootInfo mImages = buildForMimeTypes("image/*");
+    private static RootInfo mAudio = buildForMimeTypes(
+            "audio/*", "application/ogg", "application/x-flac");
+    private static RootInfo mDocs = buildForMimeTypes(
+            "application/msword", "application/vnd.ms-excel");
+    private static RootInfo mMalformed1 = buildForMimeTypes("meow");
+    private static RootInfo mMalformed2 = buildForMimeTypes("*/meow");
 
-    private List<RootInfo> mRoots = Lists.newArrayList(
-            mNull, mWild, mEmpty, mImages, mAudio, mDocs, mMalformed1, mMalformed2);
+    private List<RootInfo> mRoots;
 
     private State mState;
 
@@ -52,70 +50,86 @@ public class RootsCacheTest extends AndroidTestCase {
     protected void setUp() throws Exception {
         super.setUp();
 
+        mRoots = Lists.newArrayList(
+                mNull, mWild, mEmpty, mImages, mAudio, mDocs, mMalformed1, mMalformed2);
+
         mState = new State();
         mState.action = State.ACTION_OPEN;
-        mState.showAdvanced = true;
         mState.localOnly = false;
     }
 
-    public void testMatchingRootsEverything() throws Exception {
+    public void testMatchingRoots_Everything() throws Exception {
+        mState.acceptMimes = new String[] { "*/*" };
+        assertContainsExactly(
+                newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+                getMatchingRoots(mRoots, mState));
+    }
+
+    public void testMatchingRoots_DirectoryCopy() throws Exception {
+        RootInfo downloads = buildForMimeTypes("*/*");
+        downloads.authority = "com.android.providers.downloads.documents";
+        mRoots.add(downloads);
+
         mState.acceptMimes = new String[] { "*/*" };
+        mState.directoryCopy = true;
+
+        // basically we're asserting that the results don't contain downloads
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsPngOrWild() throws Exception {
+    public void testMatchingRoots_PngOrWild() throws Exception {
         mState.acceptMimes = new String[] { "image/png", "*/*" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mImages, mAudio, mDocs, mMalformed1, mMalformed2),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsAudioWild() throws Exception {
+    public void testMatchingRoots_AudioWild() throws Exception {
         mState.acceptMimes = new String[] { "audio/*" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mAudio),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mAudio),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsAudioWildOrImageWild() throws Exception {
+    public void testMatchingRoots_AudioWildOrImageWild() throws Exception {
         mState.acceptMimes = new String[] { "audio/*", "image/*" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mAudio, mImages),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mAudio, mImages),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsAudioSpecific() throws Exception {
+    public void testMatchingRoots_AudioSpecific() throws Exception {
         mState.acceptMimes = new String[] { "audio/mpeg" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mAudio),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mAudio),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsDocument() throws Exception {
+    public void testMatchingRoots_Document() throws Exception {
         mState.acceptMimes = new String[] { "application/msword" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mDocs),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mDocs),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsApplication() throws Exception {
+    public void testMatchingRoots_Application() throws Exception {
         mState.acceptMimes = new String[] { "application/*" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mAudio, mDocs),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mAudio, mDocs),
+                getMatchingRoots(mRoots, mState));
     }
 
-    public void testMatchingRootsFlacOrPng() throws Exception {
+    public void testMatchingRoots_FlacOrPng() throws Exception {
         mState.acceptMimes = new String[] { "application/x-flac", "image/png" };
         assertContainsExactly(
-                Lists.newArrayList(mNull, mWild, mAudio, mImages),
-                RootsCache.getMatchingRoots(mRoots, mState));
+                newArrayList(mNull, mWild, mAudio, mImages),
+                getMatchingRoots(mRoots, mState));
     }
 
     public void testExcludedAuthorities() throws Exception {
-        final List<RootInfo> roots = Lists.newArrayList();
+        final List<RootInfo> roots = newArrayList();
 
         // Set up some roots
         for (int i = 0; i < 5; ++i) {
@@ -124,7 +138,7 @@ public class RootsCacheTest extends AndroidTestCase {
             roots.add(root);
         }
         // Make some allowed authorities
-        List<RootInfo> allowedRoots = Lists.newArrayList(
+        List<RootInfo> allowedRoots = newArrayList(
             roots.get(0), roots.get(2), roots.get(4));
         // Set up the excluded authority list
         for (RootInfo root: roots) {
@@ -136,7 +150,7 @@ public class RootsCacheTest extends AndroidTestCase {
 
         assertContainsExactly(
             allowedRoots,
-            RootsCache.getMatchingRoots(roots, mState));
+            getMatchingRoots(roots, mState));
     }
 
     private static void assertContainsExactly(List<?> expected, List<?> actual) {
@@ -145,4 +159,10 @@ public class RootsCacheTest extends AndroidTestCase {
             assertTrue(actual.contains(o));
         }
     }
+
+    private static RootInfo buildForMimeTypes(String... mimeTypes) {
+        final RootInfo root = new RootInfo();
+        root.derivedMimeTypes = mimeTypes;
+        return root;
+    }
 }
index a112081..11f5194 100644 (file)
@@ -212,16 +212,6 @@ public class UiBot extends BaseBot {
         return mDevice.findObject(selector);
     }
 
-    public void revealLauncher() {
-        mDevice.pressHome();
-        mDevice.wait(Until.hasObject(By.pkg(LAUNCHER_PKG).depth(0)), mTimeout);
-    }
-
-    public void revealApp() {
-        mDevice.wait(Until.hasObject(By.pkg(TARGET_PKG).depth(0)), mTimeout);
-        mDevice.waitForIdle();
-    }
-
     public void pressKey(int keyCode) {
         mDevice.pressKeyCode(keyCode);
     }
index 2244be9..adc8141 100644 (file)
@@ -73,28 +73,6 @@ public class ModelBackedDocumentsAdapterTest extends AndroidTestCase {
         assertEquals(mModel.getItemCount() - 2, mAdapter.getItemCount());
     }
 
-    // Tests that the items can be hidden and unhidden.
-    public void testUnhide_ItemCount() {
-        List<String> ids = mModel.getModelIds();
-        SparseArray<String> hidden = mAdapter.hide(ids.toArray(new String[ids.size()]));
-        mAdapter.unhide(hidden);
-        assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
-    }
-
-    // Tests that the items can be hidden and unhidden.
-    public void testUnhide_PreservesOrder() {
-        List<String> ids = mModel.getModelIds();
-        SparseArray<String> hidden = mAdapter.hide(
-                ids.get(0), ids.get(1), ids.get(5), ids.get(9));
-        mAdapter.unhide(hidden);
-
-        // Finally ensure the restored items are in the original order
-        // by checking them against the model.
-        for (int i = 0; i < mAdapter.getItemCount(); i++) {
-            assertEquals(mModel.idForPosition(i), mAdapter.getModelId(i));
-        }
-    }
-
     private final class TestEnvironment implements DocumentsAdapter.Environment {
         private final Context testContext;
 
index 267f47d..e170dbb 100644 (file)
@@ -61,11 +61,6 @@ public class TestDocumentsAdapter extends DocumentsAdapter {
     }
 
     @Override
-    void unhide(SparseArray<String> ids) {
-        throw new UnsupportedOperationException();
-    }
-
-    @Override
     public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
         throw new UnsupportedOperationException();
     }
index 97dfd47..9a51b05 100644 (file)
@@ -34,6 +34,7 @@ import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.os.ParcelFileDescriptor.OnCloseListener;
 import android.os.UserHandle;
+import android.os.storage.DiskInfo;
 import android.os.storage.StorageManager;
 import android.os.storage.VolumeInfo;
 import android.provider.DocumentsContract;
@@ -41,6 +42,7 @@ import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsProvider;
 import android.provider.MediaStore;
+import android.provider.Settings;
 import android.support.provider.DocumentArchiveHelper;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -62,6 +64,7 @@ import java.util.List;
 public class ExternalStorageProvider extends DocumentsProvider {
     private static final String TAG = "ExternalStorage";
 
+    private static final boolean DEBUG = false;
     private static final boolean LOG_INOTIFY = false;
 
     public static final String AUTHORITY = "com.android.externalstorage.documents";
@@ -136,10 +139,25 @@ public class ExternalStorageProvider extends DocumentsProvider {
             if (volume.getType() == VolumeInfo.TYPE_EMULATED) {
                 // We currently only support a single emulated volume mounted at
                 // a time, and it's always considered the primary
+                if (DEBUG) Log.d(TAG, "Found primary volume: " + volume);
                 rootId = ROOT_ID_PRIMARY_EMULATED;
+
                 if (VolumeInfo.ID_EMULATED_INTERNAL.equals(volume.getId())) {
-                    title = getContext().getString(R.string.root_internal_storage);
+                    // This is basically the user's primary device storage.
+                    // Use device name for the volume since this is likely same thing
+                    // the user sees when they mount their phone on another device.
+                    String deviceName = Settings.Global.getString(
+                            getContext().getContentResolver(), Settings.Global.DEVICE_NAME);
+
+                    // Device name should always be set. In case it isn't, though,
+                    // fall back to a localized "Internal Storage" string.
+                    title = !TextUtils.isEmpty(deviceName)
+                            ? deviceName
+                            : getContext().getString(R.string.root_internal_storage);
                 } else {
+                    // This should cover all other storage devices, like an SD card
+                    // or USB OTG drive plugged in. Using getBestVolumeDescription()
+                    // will give us a nice string like "Samsung SD card" or "SanDisk USB drive"
                     final VolumeInfo privateVol = mStorageManager.findPrivateForEmulated(volume);
                     title = mStorageManager.getBestVolumeDescription(privateVol);
                 }
@@ -167,10 +185,17 @@ public class ExternalStorageProvider extends DocumentsProvider {
             root.flags = Root.FLAG_LOCAL_ONLY
                     | Root.FLAG_SUPPORTS_SEARCH | Root.FLAG_SUPPORTS_IS_CHILD;
 
+            final DiskInfo disk = volume.getDisk();
+            if (DEBUG) Log.d(TAG, "Disk for root " + rootId + " is " + disk);
+            if (disk != null && disk.isSd()) {
+                root.flags |= Root.FLAG_REMOVABLE_SD;
+            } else if (disk != null && disk.isUsb()) {
+                root.flags |= Root.FLAG_REMOVABLE_USB;
+            }
+
             if (volume.isPrimary()) {
                 // save off the primary volume for subsequent "Home" dir initialization.
                 primaryVolume = volume;
-                root.flags |= Root.FLAG_ADVANCED;
             }
             // Dunno when this would NOT be the case, but never hurts to be correct.
             if (volume.isMountedWritable()) {
@@ -193,8 +218,9 @@ public class ExternalStorageProvider extends DocumentsProvider {
             }
         }
 
-        // Finally, if primary storage is available we add the "Home" directory,
-        // creating it as needed.
+        // Finally, if primary storage is available we add the "Documents" directory.
+        // If I recall correctly the actual directory is created on demand
+        // by calling either getPathForUser, or getInternalPathForUser.
         if (primaryVolume != null && primaryVolume.isVisible()) {
             final RootInfo root = new RootInfo();
             root.rootId = ROOT_ID_HOME;
@@ -211,8 +237,7 @@ public class ExternalStorageProvider extends DocumentsProvider {
                 root.flags |= Root.FLAG_SUPPORTS_CREATE;
             }
 
-            // Create the "Home" directory on disk, but don't the localized root.title
-            // since the directories shouldn't be localized.
+            // Create the "Documents" directory on disk (don't use the localized title).
             root.visiblePath = new File(
                     primaryVolume.getPathForUser(userId), Environment.DIRECTORY_DOCUMENTS);
             root.path = new File(
@@ -391,6 +416,10 @@ public class ExternalStorageProvider extends DocumentsProvider {
             if (mArchiveHelper.isArchivedDocument(docId)) {
                 return mArchiveHelper.isChildDocument(parentDocId, docId);
             }
+            // Archives do not contain regular files.
+            if (mArchiveHelper.isArchivedDocument(parentDocId)) {
+                return false;
+            }
 
             final File parent = getFileForDocId(parentDocId).getCanonicalFile();
             final File doc = getFileForDocId(docId).getCanonicalFile();
index 409f6a7..b1d42e7 100644 (file)
@@ -519,6 +519,9 @@ public class KeyguardSecurityContainer extends FrameLayout implements KeyguardSe
     @Override
     public void showPromptReason(int reason) {
         if (mCurrentSecuritySelection != SecurityMode.None) {
+            if (reason != PROMPT_REASON_NONE) {
+                Log.i(TAG, "Strong auth required, reason: " + reason);
+            }
             getSecurityView(mCurrentSecuritySelection).showPromptReason(reason);
         }
     }
index 63c4ef8..c031f34 100644 (file)
@@ -404,6 +404,7 @@ public class MtpDocumentsProvider extends DocumentsProvider {
                 for (final int id : keySet) {
                     closeDeviceInternal(id);
                 }
+                mRootScanner.pause();
             } catch (InterruptedException|IOException e) {
                 // It should fail unit tests by throwing runtime exception.
                 throw new RuntimeException(e);
index 82ba21f..2f66c5c 100644 (file)
@@ -26,7 +26,6 @@ import java.io.FileNotFoundException;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-import java.util.concurrent.FutureTask;
 import java.util.concurrent.TimeUnit;
 
 final class RootScanner {
@@ -56,7 +55,7 @@ final class RootScanner {
     final MtpDatabase mDatabase;
 
     ExecutorService mExecutor;
-    FutureTask<Void> mCurrentTask;
+    private UpdateRootsRunnable mCurrentTask;
 
     RootScanner(
             ContentResolver resolver,
@@ -84,13 +83,12 @@ final class RootScanner {
             mExecutor = Executors.newSingleThreadExecutor();
         }
         if (mCurrentTask != null) {
-            // Cancel previous task.
-            mCurrentTask.cancel(true);
+            // Stop previous task.
+            mCurrentTask.stop();
         }
-        final UpdateRootsRunnable runnable = new UpdateRootsRunnable();
-        mCurrentTask = new FutureTask<Void>(runnable, null);
-        mExecutor.submit(mCurrentTask);
-        return runnable.mFirstScanCompleted;
+        mCurrentTask = new UpdateRootsRunnable();
+        mExecutor.execute(mCurrentTask);
+        return mCurrentTask.mFirstScanCompleted;
     }
 
     /**
@@ -112,13 +110,21 @@ final class RootScanner {
      * Runnable to scan roots and update the database information.
      */
     private final class UpdateRootsRunnable implements Runnable {
+        /**
+         * Count down latch that specifies the runnable is stopped.
+         */
+        final CountDownLatch mStopped = new CountDownLatch(1);
+
+        /**
+         * Count down latch that specifies the first scan is completed.
+         */
         final CountDownLatch mFirstScanCompleted = new CountDownLatch(1);
 
         @Override
         public void run() {
             Process.setThreadPriority(Process.THREAD_PRIORITY_BACKGROUND);
             int pollingCount = 0;
-            while (true) {
+            while (mStopped.getCount() > 0) {
                 boolean changed = false;
 
                 // Update devices.
@@ -171,12 +177,16 @@ final class RootScanner {
                     // Use SHORT_POLLING_PERIOD for the first SHORT_POLLING_TIMES because it is
                     // more likely to add new root just after the device is added.
                     // TODO: Use short interval only for a device that is just added.
-                    Thread.sleep(pollingCount > SHORT_POLLING_TIMES ?
-                        LONG_POLLING_INTERVAL : SHORT_POLLING_INTERVAL);
+                    mStopped.await(pollingCount > SHORT_POLLING_TIMES ?
+                            LONG_POLLING_INTERVAL : SHORT_POLLING_INTERVAL, TimeUnit.MILLISECONDS);
                 } catch (InterruptedException exp) {
                     break;
                 }
             }
         }
+
+        void stop() {
+            mStopped.countDown();
+        }
     }
 }
index 64f5cc6..4b62f24 100644 (file)
@@ -731,7 +731,10 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
 
         // The activity is a component name, therefore it is one or none.
         if (resolvedActivities.get(0).activityInfo.exported) {
-            intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, mPrintJob);
+            PrintJobInfo.Builder printJobBuilder = new PrintJobInfo.Builder(mPrintJob);
+            printJobBuilder.setPages(mSelectedPages);
+
+            intent.putExtra(PrintService.EXTRA_PRINT_JOB_INFO, printJobBuilder.build());
             intent.putExtra(PrintService.EXTRA_PRINTER_INFO, printer);
             intent.putExtra(PrintService.EXTRA_PRINT_DOCUMENT_INFO,
                     mPrintedDocument.getDocumentInfo().info);
@@ -759,10 +762,14 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
         // Take the advanced options without interpretation.
         mPrintJob.setAdvancedOptions(printJobInfo.getAdvancedOptions());
 
-        // Take copies without interpretation as the advanced print dialog
-        // cannot create a print job info with invalid copies.
-        mCopiesEditText.setText(String.valueOf(printJobInfo.getCopies()));
-        mPrintJob.setCopies(printJobInfo.getCopies());
+        if (printJobInfo.getCopies() < 1) {
+            Log.w(LOG_TAG, "Cannot apply return value from advanced options activity. Copies " +
+                    "must be 1 or more. Actual value is: " + printJobInfo.getCopies() + ". " +
+                    "Ignoring.");
+        } else {
+            mCopiesEditText.setText(String.valueOf(printJobInfo.getCopies()));
+            mPrintJob.setCopies(printJobInfo.getCopies());
+        }
 
         PrintAttributes currAttributes = mPrintJob.getAttributes();
         PrintAttributes newAttributes = printJobInfo.getAttributes();
@@ -771,7 +778,7 @@ public class PrintActivity extends Activity implements RemotePrintDocument.Updat
             // Take the media size only if the current printer supports is.
             MediaSize oldMediaSize = currAttributes.getMediaSize();
             MediaSize newMediaSize = newAttributes.getMediaSize();
-            if (!oldMediaSize.equals(newMediaSize)) {
+            if (newMediaSize != null && !oldMediaSize.equals(newMediaSize)) {
                 final int mediaSizeCount = mMediaSizeSpinnerAdapter.getCount();
                 MediaSize newMediaSizePortrait = newAttributes.getMediaSize().asPortrait();
                 for (int i = 0; i < mediaSizeCount; i++) {
diff --git a/packages/SettingsLib/res/drawable/ic_info.xml b/packages/SettingsLib/res/drawable/ic_info.xml
new file mode 100644 (file)
index 0000000..afe7e6b
--- /dev/null
@@ -0,0 +1,25 @@
+<!--
+    Copyright (C) 2016 The Android Open Source Project
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24"
+        android:tint="?android:attr/colorAccent">
+    <path
+        android:fillColor="@android:color/white"
+        android:pathData="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml b/packages/SettingsLib/res/drawable/ic_settings_lock_outline.xml
deleted file mode 100644 (file)
index b3d7cf9..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-     Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="21dp"
-        android:height="21dp"
-        android:viewportWidth="21.0"
-        android:viewportHeight="21.0"
-        android:tint="?android:attr/colorAccent">
-    <path
-            android:fillColor="@android:color/white"
-            android:pathData="M8,16c1.1,0,2-0.9,2-2s-0.9-2-2-2s-2,0.9-2,2S6.9,16,8,16zM14,7h-1V5c0-2.8-2.2-5-5-5S3,2.2,3,5v2H2C0.9,7,0,7.9,0,9v10c0,1.1,0.9,2,2,2h12c1.1,0,2-0.9,2-2V9C16,7.9,15.1,7,14,7z M4.9,5c0-1.7,1.4-3.1,3.1-3.1s3.1,1.4,3.1,3.1v2H4.9V5z M14,19H2V9h12V19z" />
-</vector>
diff --git a/packages/SettingsLib/res/layout/restricted_icon.xml b/packages/SettingsLib/res/layout/restricted_icon.xml
new file mode 100644 (file)
index 0000000..d57fb80
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/restricted_icon"
+    android:layout_width="@dimen/restricted_icon_size"
+    android:layout_height="@dimen/restricted_icon_size"
+    android:src="@drawable/ic_info"
+    android:gravity="end|center_vertical" />
\ No newline at end of file
diff --git a/packages/SettingsLib/res/layout/restricted_switch_widget.xml b/packages/SettingsLib/res/layout/restricted_switch_widget.xml
new file mode 100644 (file)
index 0000000..6183812
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <ImageView xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/restricted_icon"
+        android:layout_width="@dimen/restricted_icon_size"
+        android:layout_height="@dimen/restricted_icon_size"
+        android:src="@drawable/ic_info"
+        android:gravity="end|center_vertical" />
+    <!-- Based off frameworks/base/core/res/res/layout/preference_widget_switch.xml -->
+    <Switch xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+android:id/switch_widget"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:focusable="false"
+        android:clickable="false"
+        android:background="@null" />
+</merge>
\ No newline at end of file
index 57a749d..a01d2e9 100644 (file)
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"Ejecuta procesadores de WebView en un proceso aislado."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"Implementación de WebView"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"Establecer implementación de WebView"</string>
-    <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"La implementación de WebView seleccionada no es válida porque la lista de opciones de implementación no estaba activada. Esta ya debería estar actualizada."</string>
+    <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"La implementación de WebView seleccionada no es válida porque la lista de opciones de implementación estaba inactiva. Esta ya debería estar actualizada."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Convertir a cifrado de archivo"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Convertir…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Ya está cifrado"</string>
index a683c55..0a2d111 100644 (file)
     <string name="inactive_app_active_summary" msgid="4174921824958516106">"فعال. برای تغییر حالت ضربه بزنید."</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"سرویس‌های در حال اجرا"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"مشاهده و کنترل سرویس‌های در حال اجرای فعلی"</string>
-    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"‏فعال کردن WebView چند پردازشی"</string>
-    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"‏اجرای تولیدکننده تصویر WebView در یک پردازش مجزا."</string>
-    <string name="select_webview_provider_title" msgid="4628592979751918907">"‏اجرای WebView"</string>
-    <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"‏تنظیم اجرای WebView"</string>
-    <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"‏اجرای WebView انتخابی نامعتبر است چون فهرست گزینه‌های اجرای انتخابی قدیمی شده است. این فهرست اکنون باید به‌روزرسانی شود."</string>
+    <string name="enable_webview_multiprocess" msgid="3405948012467585908">"فعال کردن وب‌نما چند پردازشی"</string>
+    <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"اجرای تولیدکننده تصویر وب‌نما در یک پردازش مجزا."</string>
+    <string name="select_webview_provider_title" msgid="4628592979751918907">"اجرای وب‌نما"</string>
+    <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"تنظیم اجرای وب‌نما"</string>
+    <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"اجرای وب‌نما انتخابی نامعتبر است چون فهرست گزینه‌های اجرای انتخابی قدیمی شده است. این فهرست اکنون باید به‌روزرسانی شود."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"تبدیل به رمزگذاری برحسب فایل"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"تبدیل…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"از قبل به رمزگذاری بر حسب فایل تبدیل شده است"</string>
index e05d82e..178d47e 100644 (file)
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"WebView рендерерлерин корголгон процессте иштетүү."</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView аткарылышы"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"WebView аткарылышын коюу"</string>
-    <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Ð\90Ñ\82каÑ\80Ñ\83Ñ\83лаÑ\80дÑ\8b Ñ\82андоо Ñ\82измеÑ\81и Ñ\8dÑ\81киÑ\80ип ÐºÐµÑ\82кендикÑ\82ен Ñ\82андалган WebView Ð°Ñ\82каÑ\80Ñ\8bлÑ\8bÑ\88Ñ\8b Ð¶Ð°Ñ\80акÑ\81Ñ\8bз. Ð¢Ð¸Ð·Ð¼Ðµ Ð°Ð·Ñ\8bÑ\80 Ð¶Ð°Ò£Ñ\8bÑ\80Ñ\82Ñ\8bлÑ\8bÑ\88Ñ\8b ÐºÐµÑ\80ек."</string>
+    <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"Тандалган WebView ÐºÑ\8bзмаÑ\82Ñ\8b ÐºÐ¾Ð»Ð´Ð¾Ð¾Ð³Ð¾ Ð°Ð»Ñ\8bнбайÑ\82. Ð\9aÑ\8bзмаÑ\82Ñ\82аÑ\80дÑ\8bн Ñ\82измеÑ\81и Ñ\8dÑ\81киÑ\80ип ÐºÐ°Ð»Ð³Ð°Ð½Ð´Ñ\8bкÑ\82ан Ð°Ð» Ð°Ð·Ñ\8bÑ\80 Ð¶Ð°Ò£Ñ\8bÑ\80Ñ\82Ñ\8bлаÑ\82."</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"Файл шифрлөөсүнө айландыруу"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"Айландыруу…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"Файл мурунтан эле шифрленген"</string>
index adc75e9..fac31df 100644 (file)
     <string name="tts_default_rate_title" msgid="6030550998379310088">"பேச்சு வீதம்"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"பேசப்படும் உரையின் வேகம்"</string>
     <string name="tts_default_pitch_title" msgid="6135942113172488671">"ஒலித்திறன்"</string>
-    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"தà¯\8aà®\95à¯\81à®\95à¯\8dà®\95பà¯\8dபà®\9fà¯\8dà®\9f à®\89à®°à¯\88யின் டோன் பாதிக்கப்படும்"</string>
+    <string name="tts_default_pitch_summary" msgid="1944885882882650009">"à®\89à®°à¯\81வாà®\95à¯\8dà®\95பà¯\8dபà®\9fà¯\81à®®à¯\8d à®ªà¯\87à®\9aà¯\8dà®\9aின் டோன் பாதிக்கப்படும்"</string>
     <string name="tts_default_lang_title" msgid="8018087612299820556">"மொழி"</string>
     <string name="tts_lang_use_system" msgid="2679252467416513208">"முறைமையின் மொழியைப் பயன்படுத்து"</string>
     <string name="tts_lang_not_selected" msgid="7395787019276734765">"மொழி தேர்ந்தெடுக்கப்படவில்லை"</string>
index 53bd985..4001d2c 100644 (file)
     <string name="enable_webview_multiprocess_desc" msgid="852226124223847283">"在独立进程中运行 WebView 渲染程序。"</string>
     <string name="select_webview_provider_title" msgid="4628592979751918907">"WebView 实现"</string>
     <string name="select_webview_provider_dialog_title" msgid="4370551378720004872">"设置 WebView 实现"</string>
-    <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"所选的 WebView 实现无效,因为相关的实现选项列表已过时。请立即更新这份列表。"</string>
+    <string name="select_webview_provider_toast_text" msgid="8168796505966635684">"所选的 WebView 实现无效,因为实现选项列表已过时。请立即更新列表。"</string>
     <string name="convert_to_file_encryption" msgid="3060156730651061223">"转换为文件加密"</string>
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"转换…"</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"文件已加密"</string>
index 9f78e87..c3b3cfc 100644 (file)
@@ -33,8 +33,8 @@
     <dimen name="user_spinner_item_height">56dp</dimen>
 
     <!-- Lock icon for preferences locked by admin -->
-    <dimen name="restricted_lock_icon_size">16dp</dimen>
-    <dimen name="restricted_lock_icon_padding">4dp</dimen>
+    <dimen name="restricted_icon_size">16dp</dimen>
+    <dimen name="restricted_icon_padding">4dp</dimen>
 
     <dimen name="wifi_preference_badge_padding">8dip</dimen>
 
index 72fa939..ae2c6e7 100644 (file)
     <!-- Summary for settings preference disabled by administrator [CHAR LIMIT=50] -->
     <string name="disabled_by_admin_summary_text">Controlled by admin</string>
 
+    <!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
+    <string name="enabled_by_admin">Enabled by administrator</string>
+    <!-- Summary for switch preference to denote it is switched on [CHAR LIMIT=50] -->
+    <string name="disabled_by_admin">Disabled by administrator</string>
+
     <!-- Option in navigation drawer that leads to Settings main screen [CHAR LIMIT=30] -->
     <string name="home">Home</string>
 
index c2f885d..4c0450e 100644 (file)
@@ -49,7 +49,7 @@ public class RestrictedDropDownPreference extends DropDownPreference {
 
         mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(context);
         mRestrictedPadlockPadding = context.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_padding);
+                R.dimen.restricted_icon_padding);
     }
 
     private final OnItemSelectedListener mItemSelectedListener = new OnItemSelectedListener() {
index e63130d..360a34c 100644 (file)
@@ -36,7 +36,7 @@ public class RestrictedLockImageSpan extends ImageSpan {
 
         mContext = context;
         mExtraPadding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_padding);
+                R.dimen.restricted_icon_padding);
         mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(mContext);
     }
 
@@ -53,7 +53,7 @@ public class RestrictedLockImageSpan extends ImageSpan {
 
         // Add extra padding before the padlock.
         float transX = x + mExtraPadding;
-        float transY = bottom - drawable.getBounds().bottom - paint.getFontMetricsInt().descent;
+        float transY = (bottom - drawable.getBounds().bottom) / 2.0f;
 
         canvas.translate(transX, transY);
         drawable.draw(canvas);
index 6d29c5f..d0c249f 100644 (file)
@@ -49,9 +49,9 @@ public class RestrictedLockUtils {
      * @return drawables for displaying with settings that are locked by a device admin.
      */
     public static Drawable getRestrictedPadlock(Context context) {
-        Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_settings_lock_outline);
+        Drawable restrictedPadlock = context.getDrawable(R.drawable.ic_info);
         final int iconSize = context.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_size);
+                R.dimen.restricted_icon_size);
         restrictedPadlock.setBounds(0, 0, iconSize, iconSize);
         return restrictedPadlock;
     }
index 810f6eb..e69497a 100644 (file)
@@ -23,6 +23,7 @@ import android.support.v7.preference.Preference;
 import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.util.AttributeSet;
+import android.view.View;
 
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
@@ -36,6 +37,7 @@ public class RestrictedPreference extends Preference {
     public RestrictedPreference(Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        setWidgetLayoutResource(R.layout.restricted_icon);
         mHelper = new RestrictedPreferenceHelper(context, this, attrs);
     }
 
@@ -56,6 +58,10 @@ public class RestrictedPreference extends Preference {
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
         mHelper.onBindViewHolder(holder);
+        final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
+        if (restrictedIcon != null) {
+            restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
+        }
     }
 
     @Override
index 227b1e8..0c0af24 100644 (file)
@@ -54,7 +54,7 @@ public class RestrictedPreferenceHelper {
 
         mRestrictedPadlock = RestrictedLockUtils.getRestrictedPadlock(mContext);
         mRestrictedPadlockPadding = mContext.getResources().getDimensionPixelSize(
-                R.dimen.restricted_lock_icon_padding);
+                R.dimen.restricted_icon_padding);
 
         if (attrs != null) {
             final TypedArray attributes = context.obtainStyledAttributes(attrs,
@@ -91,12 +91,8 @@ public class RestrictedPreferenceHelper {
      * Modify PreferenceViewHolder to add padlock if restriction is disabled.
      */
     public void onBindViewHolder(PreferenceViewHolder holder) {
-        final TextView titleView = (TextView) holder.findViewById(android.R.id.title);
-        if (titleView != null) {
-            RestrictedLockUtils.setTextViewPadlock(mContext, titleView, mDisabledByAdmin);
-            if (mDisabledByAdmin) {
-                holder.itemView.setEnabled(true);
-            }
+        if (mDisabledByAdmin) {
+            holder.itemView.setEnabled(true);
         }
         if (mUseAdminDisabledSummary) {
             final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
index 6cae8aa..f381286 100644 (file)
@@ -23,6 +23,8 @@ import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.support.v14.preference.SwitchPreference;
 import android.util.AttributeSet;
+import android.view.View;
+import android.widget.TextView;
 
 import static com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
 
@@ -36,6 +38,7 @@ public class RestrictedSwitchPreference extends SwitchPreference {
     public RestrictedSwitchPreference(Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        setWidgetLayoutResource(R.layout.restricted_switch_widget);
         mHelper = new RestrictedPreferenceHelper(context, this, attrs);
     }
 
@@ -56,6 +59,20 @@ public class RestrictedSwitchPreference extends SwitchPreference {
     public void onBindViewHolder(PreferenceViewHolder holder) {
         super.onBindViewHolder(holder);
         mHelper.onBindViewHolder(holder);
+        final View restrictedIcon = holder.findViewById(R.id.restricted_icon);
+        final View switchWidget = holder.findViewById(android.R.id.switch_widget);
+        if (restrictedIcon != null) {
+            restrictedIcon.setVisibility(isDisabledByAdmin() ? View.VISIBLE : View.GONE);
+        }
+        if (switchWidget != null) {
+            switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
+        }
+        final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
+        if (summaryView != null && isDisabledByAdmin()) {
+            summaryView.setText(
+                    isChecked() ? R.string.enabled_by_admin : R.string.disabled_by_admin);
+            summaryView.setVisibility(View.VISIBLE);
+        }
     }
 
     @Override
index 1859207..741b0ea 100644 (file)
@@ -25,6 +25,12 @@ import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Pair;
 import android.util.Xml;
+import android.provider.Settings;
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.content.ContentValues;
+import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.view.InflateException;
 import com.android.settingslib.drawer.Tile;
 import com.android.settingslib.drawer.TileUtils;
@@ -42,6 +48,12 @@ public class SuggestionParser {
     // If defined, only returns this suggestion if the feature is supported.
     public static final String META_DATA_REQUIRE_FEATURE = "com.android.settings.require_feature";
 
+    // If defined, only display this optional step if an account of that type exists.
+    private static final String META_DATA_REQUIRE_ACCOUNT = "com.android.settings.require_account";
+
+    // If defined and not true, do not should optional step.
+    private static final String META_DATA_IS_SUPPORTED = "com.android.settings.is_supported";
+
     /**
      * Allows suggestions to appear after a certain number of days, and to re-appear if dismissed.
      * For instance:
@@ -110,7 +122,10 @@ public class SuggestionParser {
         TileUtils.getTilesForIntent(mContext, new UserHandle(UserHandle.myUserId()), intent,
                 addCache, null, suggestions, true, false);
         for (int i = countBefore; i < suggestions.size(); i++) {
-            if (!isAvailable(suggestions.get(i)) || isDismissed(suggestions.get(i))) {
+            if (!isAvailable(suggestions.get(i)) ||
+                    !isSupported(suggestions.get(i)) ||
+                    !satisfiesRequiredAccount(suggestions.get(i)) ||
+                    isDismissed(suggestions.get(i))) {
                 suggestions.remove(i--);
             }
         }
@@ -124,7 +139,10 @@ public class SuggestionParser {
                     item = last;
                 }
             }
-            suggestions.add(item);
+            // If category is marked as done, do not add any item.
+            if (!isCategoryDone(category.category)) {
+                suggestions.add(item);
+            }
         }
     }
 
@@ -136,6 +154,41 @@ public class SuggestionParser {
         return true;
     }
 
+    public boolean satisfiesRequiredAccount(Tile suggestion) {
+        String requiredAccountType = suggestion.metaData.getString(META_DATA_REQUIRE_ACCOUNT);
+        if (requiredAccountType == null) {
+            return true;
+        }
+        AccountManager accountManager = AccountManager.get(mContext);
+        Account[] accounts = accountManager.getAccountsByType(requiredAccountType);
+        return accounts.length > 0;
+    }
+
+    public boolean isSupported(Tile suggestion) {
+        int isSupportedResource = suggestion.metaData.getInt(META_DATA_IS_SUPPORTED);
+        try {
+            if (suggestion.intent == null) {
+                return false;
+            }
+            final Resources res = mContext.getPackageManager().getResourcesForActivity(
+                    suggestion.intent.getComponent());
+            return isSupportedResource != 0 ? res.getBoolean(isSupportedResource) : true;
+        } catch (PackageManager.NameNotFoundException e) {
+            Log.w(TAG, "Cannot find resources for " + suggestion.intent.getComponent());
+            return false;
+        }
+    }
+
+    public boolean isCategoryDone(String category) {
+        String name = Settings.Secure.COMPLETED_CATEGORY_PREFIX + category;
+        return Settings.Secure.getInt(mContext.getContentResolver(), name, 0) != 0;
+    }
+
+    public void markCategoryDone(String category) {
+        String name = Settings.Secure.COMPLETED_CATEGORY_PREFIX + category;
+        Settings.Secure.putInt(mContext.getContentResolver(), name, 1);
+    }
+
     private boolean isDismissed(Tile suggestion) {
         Object dismissObj = suggestion.metaData.get(META_DATA_DISMISS_CONTROL);
         if (dismissObj == null) {
index a578055..7a1c741 100644 (file)
@@ -69,16 +69,18 @@ public class SettingsDrawerActivity extends Activity {
 
         long startTime = System.currentTimeMillis();
 
-        getWindow().addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
-        getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);
-        requestWindowFeature(Window.FEATURE_NO_TITLE);
+        TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
+        if (!theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
+            getWindow().addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
+            getWindow().addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);
+            requestWindowFeature(Window.FEATURE_NO_TITLE);
+        }
         super.setContentView(R.layout.settings_with_drawer);
         mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout);
         if (mDrawerLayout == null) {
             return;
         }
         Toolbar toolbar = (Toolbar) findViewById(R.id.action_bar);
-        TypedArray theme = getTheme().obtainStyledAttributes(android.R.styleable.Theme);
         if (theme.getBoolean(android.R.styleable.Theme_windowNoTitle, false)) {
             toolbar.setVisibility(View.GONE);
             mDrawerLayout.setDrawerLockMode(DrawerLayout.LOCK_MODE_LOCKED_CLOSED);
index 2dfdfda..418b138 100644 (file)
@@ -41,7 +41,7 @@ import java.util.Map;
 public class TileUtils {
 
     private static final boolean DEBUG = false;
-    private static final boolean DEBUG_TIMING = true;
+    private static final boolean DEBUG_TIMING = false;
 
     private static final String LOG_TAG = "TileUtils";
 
index 9842e28..a424d55 100644 (file)
@@ -1128,10 +1128,15 @@ public class SettingsProvider extends ContentProvider {
 
     private PackageInfo getCallingPackageInfoOrThrow(int userId) {
         try {
-            return mPackageManager.getPackageInfo(getCallingPackage(), 0, userId);
+            PackageInfo packageInfo = mPackageManager.getPackageInfo(
+                    getCallingPackage(), 0, userId);
+            if (packageInfo != null) {
+                return packageInfo;
+            }
         } catch (RemoteException e) {
-            throw new IllegalStateException("Calling package doesn't exist");
+            /* ignore */
         }
+        throw new IllegalStateException("Calling package doesn't exist");
     }
 
     private int getGroupParentLocked(int userId) {
index 5d1e9f9..b6b8d6b 100644 (file)
 
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:orientation="vertical"
+    android:paddingTop="15dp"
+    android:paddingStart="24dp"
+    android:paddingEnd="24dp"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content">
+    <TextView
+        android:inputType="textNoSuggestions"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/bugreport_info_name"/>
     <EditText
         android:id="@+id/name"
         android:maxLength="30"
         android:singleLine="true"
+        android:selectAllOnFocus="true"
         android:inputType="textNoSuggestions"
         android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+    <TextView
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:hint="@string/bugreport_info_name"/>
+        android:text="@string/bugreport_info_title"/>
     <EditText
         android:id="@+id/title"
         android:maxLength="80"
         android:singleLine="true"
+        android:inputType="textAutoCorrect|textCapSentences"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"/>
+    <TextView
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:hint="@string/bugreport_info_title"/>
+        android:editable="false"
+        android:text="@string/bugreport_info_description"/>
     <EditText
         android:id="@+id/description"
         android:singleLine="false"
-        android:inputType="textMultiLine"
+        android:inputType="textMultiLine|textAutoCorrect|textCapSentences"
         android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:hint="@string/bugreport_info_description"/>
+        android:layout_height="wrap_content"/>
 </LinearLayout>
index 9d399c1..f86b551 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kon nie skermkiekie neem nie."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Foutverslag <xliff:g id="ID">#%d</xliff:g> se besonderhede"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Lêernaam"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beskrywing"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Fouttitel"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Foutopsomming"</string>
+    <string name="save" msgid="4781509040564835759">"Stoor"</string>
 </resources>
index 2545222..55c5390 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ቅጽበታዊ ገጽ እይታ ሊነሳ አይችልም"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"የሳንካ ሪፖርት <xliff:g id="ID">#%d</xliff:g> ዝርዝሮች"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"የፋይል ስም"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ርዕስ"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"ዝርዝር መግለጫ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"የሳንካ ርዕስ"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"የሳንካ ማጠቃለያ"</string>
+    <string name="save" msgid="4781509040564835759">"አስቀምጥ"</string>
 </resources>
index 7593110..f0af8ce 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"تعذر التقاط لقطة الشاشة."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"تفاصيل تقرير الخطأ <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"اسم الملف"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"العنوان"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"وصف تفصيلي"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"عنوان الخطأ"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ملخص الخطأ"</string>
+    <string name="save" msgid="4781509040564835759">"حفظ"</string>
 </resources>
index 9130255..6d375fe 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Displey görüntüsü əlçatan deyil."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Baq hesabatı <xliff:g id="ID">#%d</xliff:g> detalları"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Fayl adı"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Başlıq"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Ətraflı təsvir"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Baq başlığı"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Baq xülasə"</string>
+    <string name="save" msgid="4781509040564835759">"Yadda saxlayın"</string>
 </resources>
index 597e545..ad84941 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje ekrana nije uspelo."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalji izveštaja o grešci <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Naziv datoteke"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljni opis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov greške"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Rezime greške"</string>
+    <string name="save" msgid="4781509040564835759">"Sačuvaj"</string>
 </resources>
index 6ca7914..e543839 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Екранната снимка не можа да бъде направена."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Подробности за сигнала за програмна грешка „<xliff:g id="ID">#%d</xliff:g>“"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Име на файла"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Заглавие"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Подробно описание"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Заглавие на сигнала за програмна грешка"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Обобщена информация за сигнала за програмна грешка"</string>
+    <string name="save" msgid="4781509040564835759">"Запазване"</string>
 </resources>
index 5390315..bba778d 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"স্ক্রীনশট নেওয়া যায়নি৷"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ত্রুটির প্রতিবেদন <xliff:g id="ID">#%d</xliff:g> এর বিশদ বিবরণ"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ফাইলের নাম"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"শীর্ষক"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"বিস্তারিত বিবরণ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ত্রুটির শীর্ষক"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ত্রুটির সারাংশ"</string>
+    <string name="save" msgid="4781509040564835759">"সংরক্ষণ করুন"</string>
 </resources>
index 903c2ab..54be955 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran nije moguće snimiti."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalji izvještaja o grešci <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Naziv fajla"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljan opis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov greške"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Sažetak greške"</string>
+    <string name="save" msgid="4781509040564835759">"Sačuvaj"</string>
 </resources>
index 0836946..a92177e 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No s\'ha pogut fer la captura de pantalla."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalls de l\'informe d\'errors <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nom del fitxer"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Títol"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descripció detallada"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Títol de l\'error"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resum d\'errors"</string>
+    <string name="save" msgid="4781509040564835759">"Desa"</string>
 </resources>
index 215ec87..6f7549a 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímek obrazovky se nepodařilo pořídit."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti zprávy o chybě <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Název souboru"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Název"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Název chyby"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Přehled chyby"</string>
+    <string name="save" msgid="4781509040564835759">"Uložit"</string>
 </resources>
index e956d3a..72a9a99 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Der kunne ikke tages et skærmbillede."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Oplysninger om fejlrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljeret beskrivelse"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Fejlrapportens titel"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Oversigt over fejl"</string>
+    <string name="save" msgid="4781509040564835759">"Gem"</string>
 </resources>
index 07f8898..f848c9d 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot konnte nicht aufgenommen werden."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Details zum Fehlerbericht <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Dateiname"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaillierte Beschreibung"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titel des Programmfehlers"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Zusammenfassung des Programmfehlers"</string>
+    <string name="save" msgid="4781509040564835759">"Speichern"</string>
 </resources>
index 6746976..0c04809 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Δεν ήταν δυνατή η λήψη του στιγμιότυπου οθόνης."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Λεπτομέρειες της αναφοράς σφάλματος <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Όνομα αρχείου"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Τίτλος"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Αναλυτική περιγραφή"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Τίτλος σφάλματος"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Περίληψη σφάλματος"</string>
+    <string name="save" msgid="4781509040564835759">"Αποθήκευση"</string>
 </resources>
index ac681e2..ad637f5 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Bug title"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Bug summary"</string>
+    <string name="save" msgid="4781509040564835759">"Save"</string>
 </resources>
index ac681e2..ad637f5 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Bug title"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Bug summary"</string>
+    <string name="save" msgid="4781509040564835759">"Save"</string>
 </resources>
index ac681e2..ad637f5 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot could not be taken."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Bug report <xliff:g id="ID">#%d</xliff:g> details"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Title"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detailed description"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Bug title"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Bug summary"</string>
+    <string name="save" msgid="4781509040564835759">"Save"</string>
 </resources>
index 96ca14c..a9a1e08 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se pudo tomar la captura de pantalla."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles del informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nombre del archivo"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Título del error"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumen del error"</string>
+    <string name="save" msgid="4781509040564835759">"Guardar"</string>
 </resources>
index 00874c6..b82d372 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"No se puede realizar la captura de pantalla."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles del informe de errores <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nombre de archivo"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descripción completa"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Nombre del informe de errores"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumen del informe de errores"</string>
+    <string name="save" msgid="4781509040564835759">"Guardar"</string>
 </resources>
index bc469bc..cdb774a 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekraanipilti ei saanud teha."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Veaaruande <xliff:g id="ID">#%d</xliff:g> üksikasjad"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Faili nimi"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Pealkiri"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Üksikasjalik kirjeldus"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Vea pealkiri"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Vea kokkuvõte"</string>
+    <string name="save" msgid="4781509040564835759">"Salvesta"</string>
 </resources>
index 614f17e..42dfe27 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ezin izan da atera pantaila-argazkia."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Akatsen <xliff:g id="ID">#%d</xliff:g> txostenaren xehetasunak"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Fitxategi-izena"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Izena"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Azalpen xehatua"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Akatsaren izena"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Akatsaren laburpena"</string>
+    <string name="save" msgid="4781509040564835759">"Gorde"</string>
 </resources>
index ab00562..e825f3a 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"نمی‌توان عکس صفحه‌نمایش گرفت."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"جزئیات گزارش اشکال <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"نام فایل"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"عنوان"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"جزئیات دقیق"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"عنوان اشکال"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"خلاصه اشکال"</string>
+    <string name="save" msgid="4781509040564835759">"ذخیره کردن"</string>
 </resources>
index be7aabd..8c67c66 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Kuvakaappauksen tallentaminen epäonnistui."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Virheraportin <xliff:g id="ID">#%d</xliff:g> tiedot"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Tiedostonimi"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Otsikko"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Yksityiskohtainen kuvaus"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Virheen nimi"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Virheen yhteenveto"</string>
+    <string name="save" msgid="4781509040564835759">"Tallenna"</string>
 </resources>
index 7d9f97d..3daa120 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Une erreur s\'est produite lors de la saisie d\'écran."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Détails du rapport de bogue <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nom de fichier"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titre"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titre du bogue"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Sommaire des bogues"</string>
+    <string name="save" msgid="4781509040564835759">"Enregistrer"</string>
 </resources>
index 74025d9..c512aca 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossible d\'effectuer une capture d\'écran."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Informations sur le rapport de bug \"<xliff:g id="ID">#%d</xliff:g>\""</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nom de fichier"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titre"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Description détaillée"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titre du bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Résumé du bug"</string>
+    <string name="save" msgid="4781509040564835759">"Enregistrer"</string>
 </resources>
index d3be7c5..ea95c97 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Non se puido realizar a captura de pantalla."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalles do informe de erros <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nome do ficheiro"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descrición detallada"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Título do informe de erros"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo do informe de erros"</string>
+    <string name="save" msgid="4781509040564835759">"Gardar"</string>
 </resources>
index 45df7b3..1436c3d 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"સ્ક્રીનશોટ લઇ શકાયો નથી."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"બગ રિપોર્ટ <xliff:g id="ID">#%d</xliff:g> ની વિગતો"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ફાઇલનું નામ"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"શીર્ષક"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"વિગતવાર વર્ણન"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"બગનું શીર્ષક"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"બગનો સારાંશ"</string>
+    <string name="save" msgid="4781509040564835759">"સાચવો"</string>
 </resources>
index 8858bc3..9a735f2 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट नहीं लिया जा सका."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g> के विवरण"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"फ़ाइल नाम"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत वर्णन"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"बग शीर्षक"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"बग सारांश"</string>
+    <string name="save" msgid="4781509040564835759">"सहेजें"</string>
 </resources>
index cb03f9c..71d50b8 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snimanje zaslona nije uspjelo."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Pojedinosti izvješća o programskoj pogrešci <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Naziv datoteke"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljan opis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov izvješća o programskoj pogrešci"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Sažetak izvješća o programskoj pogrešci"</string>
+    <string name="save" msgid="4781509040564835759">"Spremi"</string>
 </resources>
index 390cd2f..cf10315 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nem sikerült elkészíteni a képernyőképet."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Hibajelentés (<xliff:g id="ID">#%d</xliff:g>) részletei"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Fájlnév"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Név"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Részletes leírás"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Hibajelentés címe"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Hibajelentés összefoglalója"</string>
+    <string name="save" msgid="4781509040564835759">"Mentés"</string>
 </resources>
index 68478ab..1cf5c94 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Չհաջողվեց ստանալ էկրանի պատկերը:"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"<xliff:g id="ID">#%d</xliff:g> վրիպակի զեկույցի մանրամասները"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Ֆայլի անունը"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Անվանումը"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Մանրամասն նկարագրություն"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Վրիպակի զեկույցի վերնագիրը"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Վրիպակի զեկույցի ամփոփագիրը"</string>
+    <string name="save" msgid="4781509040564835759">"Պահել"</string>
 </resources>
index 4416fc7..1e8fe87 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan layar tidak dapat diambil."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detail laporan bug <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nama file"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Judul"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Deskripsi detail"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Judul bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Ringkasan bug"</string>
+    <string name="save" msgid="4781509040564835759">"Simpan"</string>
 </resources>
index 0d43719..afcea59 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekki tókst að taka skjámynd."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Upplýsingar villutilkynningar <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Skráarheiti"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titill"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Ítarleg lýsing"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Heiti villu"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Villusamantekt"</string>
+    <string name="save" msgid="4781509040564835759">"Vista"</string>
 </resources>
index fc9383a..d7ac9a5 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Impossibile acquisire lo screenshot."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Dettagli sulla segnalazione di bug <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nome file"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titolo"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descrizione dettagliata"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titolo bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Riepilogo bug"</string>
+    <string name="save" msgid="4781509040564835759">"Salva"</string>
 </resources>
index 335a2e8..fd64ee1 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"לא ניתן היה לצלם מסך."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"פרטי הדוח על הבאג <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"שם קובץ"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"כותרת"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"תיאור מפורט"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"כותרת הבאג"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"סיכום הבאג"</string>
+    <string name="save" msgid="4781509040564835759">"שמור"</string>
 </resources>
index b98b05f..050c5df 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"スクリーンショットを撮影できませんでした。"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"バグレポート <xliff:g id="ID">#%d</xliff:g> の詳細"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ファイル名"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"タイトル"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"詳細説明"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"バグのタイトル"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"バグの概要"</string>
+    <string name="save" msgid="4781509040564835759">"保存"</string>
 </resources>
index 24d83a4..8c5c6fb 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ეკრანის ანაბეჭდის გადაღება ვერ მოხერხდა."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ხარვეზების შესახებ ანგარიში <xliff:g id="ID">#%d</xliff:g>-ის დეტალები"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ფაილის სახელი"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"სათაური"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"დეტალური აღწერა"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"შეცდომის სათაური"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"შეცდომის რეზიუმე"</string>
+    <string name="save" msgid="4781509040564835759">"შენახვა"</string>
 </resources>
index 5878b17..edb2dd0 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот түсіру мүмкін болмады."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"<xliff:g id="ID">#%d</xliff:g> қате туралы есебі туралы мәліметтер"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Файл атауы"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Атауы"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Егжей-тегжейлі сипаттама"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Қатенің атауы"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Қате туралы жиынтық мәліметтер"</string>
+    <string name="save" msgid="4781509040564835759">"Сақтау"</string>
 </resources>
index 9c95e98..ba0de9f 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"មិនអាចថតរូបថតអេក្រង់បានទេ"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ព័ត៌មានលម្អិតពី <xliff:g id="ID">#%d</xliff:g> របាយការណ៍កំហុស"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ឈ្មោះ​ឯកសារ"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ចំណងជើង"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"ការពិពណ៌នាលម្អិត"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ចំណងជើងកំហុស"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"សង្ខេបកំហុស"</string>
+    <string name="save" msgid="4781509040564835759">"រក្សាទុក"</string>
 </resources>
index ce6f3c0..b041f35 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ಸ್ಕ್ರೀನ್‌ಶಾಟ್‌ ತೆಗೆದುಕೊಳ್ಳಲು ಸಾಧ್ಯವಾಗುವುದಿಲ್ಲ."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ದೋಷ ವರದಿಯ <xliff:g id="ID">#%d</xliff:g> ವಿವರಗಳು"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ಫೈಲ್‌ಹೆಸರು"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ಶೀರ್ಷಿಕೆ"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"ವಿವರವಾದ ವಿವರಣೆ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ಬಗ್ ಶೀರ್ಷಿಕೆ"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ಬಗ್ ಸಾರಾಂಶ"</string>
+    <string name="save" msgid="4781509040564835759">"ಉಳಿಸು"</string>
 </resources>
index 70df8e2..2a86360 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"스크린샷을 찍을 수 없습니다."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"버그 신고 <xliff:g id="ID">#%d</xliff:g> 세부정보"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"파일 이름"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"제목"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"자세한 설명"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"버그 제목"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"버그 요약"</string>
+    <string name="save" msgid="4781509040564835759">"저장"</string>
 </resources>
index 49d8d8d..1903109 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Скриншот тартылбай койду."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Мүчүлүштүк тууралуу билдирүүнүн <xliff:g id="ID">#%d</xliff:g> чоо-жайы"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Файлдын аталышы"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Аталышы"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Кененирээк маалымат"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Мүчүлүштүктүн аталышы"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Мүчүлүштүктүн корутундусу"</string>
+    <string name="save" msgid="4781509040564835759">"Сактоо"</string>
 </resources>
index 61b06c8..4348250 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ບໍ່ສາມາດຖ່າຍພາບໜ້າຈໍໄດ້."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ລາຍລະອຽດຂອງລາຍງານຂໍ້ຜິດພາດ <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ຊື່ໄຟລ໌"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ຊື່"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"ຄຳອະທິບາຍແບບລະອຽດ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ຊື່ຂໍ້ຜິດພາດ"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ສະຫຼຸບຂໍ້ຜິດພາດ"</string>
+    <string name="save" msgid="4781509040564835759">"ບັນທຶກ"</string>
 </resources>
index 3418213..a714efc 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nepavyko padaryti ekrano kopijos."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Išsami informacija apie pranešimą apie riktą (<xliff:g id="ID">#%d</xliff:g>)"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Failo pavadinimas"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Pavadinimas"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Išsamus aprašas"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Rikto pavadinimas"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Rikto suvestinė"</string>
+    <string name="save" msgid="4781509040564835759">"Išsaugoti"</string>
 </resources>
index 6108716..880d651 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nevarēja veikt ekrānuzņēmumu."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Kļūdas pārskats <xliff:g id="ID">#%d</xliff:g>: detalizēta informācija"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Faila nosaukums"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Nosaukums"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detalizēts apraksts"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Kļūdas nosaukums"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Kļūdas kopsavilkums"</string>
+    <string name="save" msgid="4781509040564835759">"Saglabāt"</string>
 </resources>
index 500196d..478c189 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не може да се направи слика од екранот."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детали за извештајот за грешки <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Име на датотека"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Наслов"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Детален опис"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Наслов на грешката"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Преглед на грешката"</string>
+    <string name="save" msgid="4781509040564835759">"Зачувај"</string>
 </resources>
index 696aab2..70e6333 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"സ്ക്രീൻഷോട്ട് എടുക്കാൻ കഴിഞ്ഞില്ല."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ബഗ് റിപ്പോർട്ട് <xliff:g id="ID">#%d</xliff:g> വിശദാംശങ്ങൾ"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ഫയല്‍നാമം"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"പേര്"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"വിശദമായ വിവരണം"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ബഗിന്റെ പേര്"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ബഗ് സംഗ്രഹം"</string>
+    <string name="save" msgid="4781509040564835759">"സംരക്ഷിക്കുക"</string>
 </resources>
index 62d83cb..49196a2 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Дэлгэцийн зураг авах боломжгүй."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Програмд гарсан алдааны мэдээллийн <xliff:g id="ID">#%d</xliff:g>-ны дэлгэрэнгүй"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Файлын нэр"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Гарчиг"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Дэлгэрэнгүй тайлбар"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Алдааны нэр"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Алдааны хураангуй"</string>
+    <string name="save" msgid="4781509040564835759">"Хадгалах"</string>
 </resources>
index e6b2b04..19a8706 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रीनशॉट घेणे शक्य झाले नाही."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"दोष अहवाल <xliff:g id="ID">#%d</xliff:g> तपशील"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"फाईलनाव"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"तपशीलवार वर्णन"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"दोष शीर्षक"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"दोष सारांश"</string>
+    <string name="save" msgid="4781509040564835759">"जतन करा"</string>
 </resources>
index 1d04253..c9f5375 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Tangkapan skrin tidak dapat diambil."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Butiran laporan pepijat <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nama fail"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Tajuk"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Perihalan terperinci"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Tajuk pepijat"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Ringkasan pepijat"</string>
+    <string name="save" msgid="4781509040564835759">"Simpan"</string>
 </resources>
index f63c8c5..4250eda 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"မျက်နှာပြင် လျှပ်တစ်ပြက်ပုံ မရိုက်နိုင်ပါ"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ချွတ်ယွင်းမှုအစီရင်ခံချက် <xliff:g id="ID">#%d</xliff:g> အသေးစိတ်များ"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ဖိုင်အမည်"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ခေါင်းစဉ်"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"အသေးစိတ် ဖော်ပြချက်"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ချွတ်ယွင်းချက် ခေါင်းစဉ်"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ချွတ်ယွင်းချက် အကျဉ်းချုပ်"</string>
+    <string name="save" msgid="4781509040564835759">"သိမ်းဆည်းပါ"</string>
 </resources>
index 328e8ae..aa86ae4 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skjermdumpen kunne ikke tas."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaljer om feilrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filnavn"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Tittel"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljert beskrivelse"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Navn på feil"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Oppsummering av feil"</string>
+    <string name="save" msgid="4781509040564835759">"Lagre"</string>
 </resources>
index 62bfead..43c2a5c 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"स्क्रिनशट लिन सकिएन।"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"बग रिपोर्ट <xliff:g id="ID">#%d</xliff:g>का विवरणहरू"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"फाइलको नाम"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"शीर्षक"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"विस्तृत विवरण"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"बगको शीर्षक"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"बगको सारांश"</string>
+    <string name="save" msgid="4781509040564835759">"सुरक्षित गर्नुहोस्"</string>
 </resources>
index 2f4b215..01fd577 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Screenshot kan niet worden gemaakt."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Details van bugrapport <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Bestandsnaam"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titel"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Gedetailleerde beschrijving"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titel van bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Overzicht van bug"</string>
+    <string name="save" msgid="4781509040564835759">"Opslaan"</string>
 </resources>
index dc2277f..3494199 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਨਹੀਂ ਲਿਆ ਜਾ ਸਕਿਆ।"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"ਬੱਗ ਰਿਪੋਰਟ <xliff:g id="ID">#%d</xliff:g> ਵੇਰਵੇ"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ਫ਼ਾਈਲ ਨਾਮ"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ਸਿਰਲੇਖ"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"ਵਿਸਥਾਰ ਸਹਿਤ ਵਰਣਨ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ਬੱਗ ਸਿਰਲੇਖ"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"ਬੱਗ ਸਾਰਾਂਸ਼"</string>
+    <string name="save" msgid="4781509040564835759">"ਰੱਖਿਅਤ ਕਰੋ"</string>
 </resources>
index c585568..91934c9 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Nie udało się zrobić zrzutu ekranu."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Szczegóły raportu o błędzie <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nazwa pliku"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Tytuł"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Szczegółowy opis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Tytuł raportu o błędzie"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Podsumowanie raportu o błędzie"</string>
+    <string name="save" msgid="4781509040564835759">"Zapisz"</string>
 </resources>
index fc6e21c..41f4e24 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de bugs <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nome do arquivo"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Título do bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo do bug"</string>
+    <string name="save" msgid="4781509040564835759">"Salvar"</string>
 </resources>
index 252edb1..416db80 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível tirar a captura de ecrã."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de erro <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nome do ficheiro"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Título do erro"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo de erros"</string>
+    <string name="save" msgid="4781509040564835759">"Guardar"</string>
 </resources>
index fc6e21c..41f4e24 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Não foi possível fazer a captura de tela."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detalhes do relatório de bugs <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Nome do arquivo"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Título"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descrição detalhada"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Título do bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Resumo do bug"</string>
+    <string name="save" msgid="4781509040564835759">"Salvar"</string>
 </resources>
index d720417..4112e60 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Captura de ecran nu a putut fi făcută."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detaliile raportului de eroare <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Numele fișierului"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titlu"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Descriere detaliată"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titlul erorii"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Rezumat privind eroarea"</string>
+    <string name="save" msgid="4781509040564835759">"Salvați"</string>
 </resources>
index ed5ecaf..ffd2e66 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не удалось сделать скриншот"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Данные отчета об ошибке <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Название файла"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Название"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Подробное описание"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Название ошибки"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Описание ошибки"</string>
+    <string name="save" msgid="4781509040564835759">"Сохранить"</string>
 </resources>
index cd8fba3..807ebb1 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"තිර රුවක් ගත නොහැකි විය."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"දෝෂ වාර්තා <xliff:g id="ID">#%d</xliff:g> විස්තර"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ගොනුවේ නම"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"මාතෘකාව"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"සවිස්තර විස්තරය"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"දෝෂ මාතෘකාව"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"දෝෂ සාරාංශය"</string>
+    <string name="save" msgid="4781509040564835759">"සුරකින්න"</string>
 </resources>
index 23e67f5..a62a6eb 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Snímku obrazovky sa nepodarilo zaznamenať."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti hlásenia chyby <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Názov súboru"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Názov"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Podrobný popis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Názov chyby"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Súhrn chyby"</string>
+    <string name="save" msgid="4781509040564835759">"Uložiť"</string>
 </resources>
index 519f3f2..6d1be5a 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Posnetka zaslon ni bilo mogoče ustvariti."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Podrobnosti poročila o napaki <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Ime datoteke"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Naslov"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Podroben opis"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Naslov poročila o napakah"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Povzetek poročila o napakah"</string>
+    <string name="save" msgid="4781509040564835759">"Shrani"</string>
 </resources>
index 5e3c706..ce990e9 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Pamja e ekranit nuk mund të realizohej."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Detajet e raportit të defekteve në kod <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Emri i skedarit"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Titulli"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Përshkrimi i detajuar"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Titulli i defektit në kod"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Përmbledhja e defekteve në kod"</string>
+    <string name="save" msgid="4781509040564835759">"Ruaj"</string>
 </resources>
index 55119b6..0157a25 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Снимање екрана није успело."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Детаљи извештаја о грешци <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Назив датотеке"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Наслов"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Детаљни опис"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Наслов грешке"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Резиме грешке"</string>
+    <string name="save" msgid="4781509040564835759">"Сачувај"</string>
 </resources>
index 085f57e..88af0db 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Det gick inte att ta skrämdump."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Information för felrapporten <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filnamn"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Namn"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detaljerad beskrivning"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Felets titel"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Sammanfattning av felet"</string>
+    <string name="save" msgid="4781509040564835759">"Spara"</string>
 </resources>
index c5a8ef1..01df55e 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Haikupiga picha ya skrini."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Maelezo ya ripoti ya hitilafu ya <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Jina la faili"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Kichwa"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Maelezo ya kina"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Jina la hitilafu"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Muhtasari wa hitilafu"</string>
+    <string name="save" msgid="4781509040564835759">"Hifadhi"</string>
 </resources>
index 7ef89e2..8238d25 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ஸ்கிரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"பிழை அறிக்கை <xliff:g id="ID">#%d</xliff:g> இன் விவரங்கள்"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"கோப்புப்பெயர்"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"தலைப்பு"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"விரிவான விளக்கம்"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"பிழைத் தலைப்பு"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"பிழை குறித்த சுருக்க விவரம்"</string>
+    <string name="save" msgid="4781509040564835759">"சேமி"</string>
 </resources>
index 6ba816b..3ed1f95 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"స్క్రీన్‌షాట్‌ను తీయడం సాధ్యపడలేదు."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"బగ్ నివేదిక <xliff:g id="ID">#%d</xliff:g> వివరాలు"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ఫైల్ పేరు"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"శీర్షిక"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"సమగ్ర వివరణ"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"బగ్ శీర్షిక"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"బగ్ సారాంశం"</string>
+    <string name="save" msgid="4781509040564835759">"సేవ్ చేయి"</string>
 </resources>
index d68ca26..f28bac6 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"ไม่สามารถจับภาพหน้าจอได้"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"รายละเอียดรายงานข้อบกพร่อง <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"ชื่อไฟล์"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"ชื่อ"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"คำอธิบายโดยละเอียด"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"ชื่อข้อบกพร่อง"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"สรุปข้อบกพร่อง"</string>
+    <string name="save" msgid="4781509040564835759">"บันทึก"</string>
 </resources>
index 432eb90..d270401 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Hindi makunan ng screenshot."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Mga detalye ng ulat ng bug na <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Filename"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Pamagat"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Detalyadong paglalarawan"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Pamagat ng bug"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Buod ng bug"</string>
+    <string name="save" msgid="4781509040564835759">"I-save"</string>
 </resources>
index dae377f..6da3490 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Ekran görüntüsü alınamadı."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Hata raporu (<xliff:g id="ID">#%d</xliff:g>) ayrıntıları"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Dosya adı"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Başlık"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Ayrıntılı açıklama"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Hata başlığı"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Hata özeti"</string>
+    <string name="save" msgid="4781509040564835759">"Kaydet"</string>
 </resources>
index 02eeb2f..00a7793 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Не вдалося зробити знімок екрана."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Деталі повідомлення про помилку <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Назва файлу"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Назва"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Детальний опис"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Назва помилки"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Опис помилки"</string>
+    <string name="save" msgid="4781509040564835759">"Зберегти"</string>
 </resources>
index 23cada6..abf6940 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"سکرین شاٹ نہیں لیا جا سکا۔"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"بگ رپورٹ <xliff:g id="ID">#%d</xliff:g> کی تفصیلات"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"فائل کا نام"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"عنوان"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"تفصیلی وضاحت"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"بَگ کا عنوان"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"بَگ کا خلاصہ"</string>
+    <string name="save" msgid="4781509040564835759">"محفوظ کریں"</string>
 </resources>
index 39703a2..7782b42 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Skrinshot olib bo‘lmadi."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Xatoliklar hisoboti (<xliff:g id="ID">#%d</xliff:g>) tafsilotlari"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Fayl nomi"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Nomi"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Batafsil ta’rif"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Xatolik nomi"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Xatolik ta’rifi"</string>
+    <string name="save" msgid="4781509040564835759">"Saqlash"</string>
 </resources>
index 16ffaff..27a9c7f 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Không thể chụp ảnh màn hình."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Chi tiết báo cáo lỗi <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Tên tệp"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Tiêu đề"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Mô tả chi tiết"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Tiêu đề lỗi"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Tóm tắt lỗi"</string>
+    <string name="save" msgid="4781509040564835759">"Lưu"</string>
 </resources>
index 382478e..65cfbbc 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"无法截图。"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"错误报告 <xliff:g id="ID">#%d</xliff:g> 详情"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"文件名"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"标题"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"详细说明"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"错误标题"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"错误摘要"</string>
+    <string name="save" msgid="4781509040564835759">"保存"</string>
 </resources>
index 04b5e48..34a849e 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法擷取螢幕畫面。"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 的詳情"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"檔案名稱"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"標題"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"錯誤標題"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"錯誤摘要"</string>
+    <string name="save" msgid="4781509040564835759">"儲存"</string>
 </resources>
index 7a1ab77..fff73bb 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"無法拍攝螢幕擷取畫面。"</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"錯誤報告 <xliff:g id="ID">#%d</xliff:g> 的詳細資料"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"檔案名稱"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"標題"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"詳細說明"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"錯誤標題"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"錯誤摘要"</string>
+    <string name="save" msgid="4781509040564835759">"儲存"</string>
 </resources>
index 29b7dd8..868de3e 100644 (file)
@@ -34,6 +34,7 @@
     <string name="bugreport_screenshot_failed" msgid="5853049140806834601">"Isithombe-skrini asikwazanga ukuthathwa."</string>
     <string name="bugreport_info_dialog_title" msgid="1355948594292983332">"Imininingwane yombiko wesiphazamisi ongu-<xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_info_name" msgid="4414036021935139527">"Igama lefayela"</string>
-    <string name="bugreport_info_title" msgid="5599558206004371052">"Isihloko"</string>
-    <string name="bugreport_info_description" msgid="4117088998733546784">"Incazelo enemininingwane"</string>
+    <string name="bugreport_info_title" msgid="2306030793918239804">"Isihloko sesiphazamisi"</string>
+    <string name="bugreport_info_description" msgid="5072835127481627722">"Isifinyezo sesiphazamisi"</string>
+    <string name="save" msgid="4781509040564835759">"Londoloza"</string>
 </resources>
index c26b549..38ea880 100644 (file)
     <!--  Title of the dialog asking for user-defined bug report details like name, title, and description. -->
     <string name="bugreport_info_dialog_title">Bug report <xliff:g id="id">#%d</xliff:g> details</string>
 
-    <!-- Text of the hint asking for the bug report name, which when set will define a suffix in the
+    <!-- Text of the label identifying the bug report name, which when set will define a suffix in the
          bug report file names. [CHAR LIMIT=30] -->
     <string name="bugreport_info_name">Filename</string>
-    <!-- Text of hint asking for the bug report title, which when set will define the
+    <!-- Text of the label identifying the bug report title, which when set will define the
          Subject of the email message. [CHAR LIMIT=60] -->
-    <string name="bugreport_info_title">Title</string>
-    <!-- Text of hint asking for the bug report description, which when set will describe
+    <string name="bugreport_info_title">Bug title</string>
+    <!-- Text of the label identifying the bug report description, which when set will describe
          what the bug report is about. [CHAR LIMIT=NONE] -->
-    <string name="bugreport_info_description">Detailed description</string>
+    <string name="bugreport_info_description">Bug summary</string>
+
+    <!-- Label of button that save bugreport details.  -->
+    <string name="save">Save</string>
 </resources>
index 36097a1..0b52588 100644 (file)
@@ -601,7 +601,8 @@ public class BugreportProgressService extends Service {
             // Most likely am killed Shell before user tapped the notification. Since system might
             // be too busy anwyays, it's better to ignore the notification and switch back to the
             // non-interactive mode (where the bugerport will be shared upon completion).
-            Log.d(TAG, "launchBugreportInfoDialog(" + id + "): cancel notification");
+            Log.w(TAG, "launchBugreportInfoDialog(): canceling notification because id " + id
+                    + " was not found");
             // TODO: add test case to make sure notification is canceled.
             NotificationManager.from(mContext).cancel(TAG, id);
             return;
@@ -627,7 +628,8 @@ public class BugreportProgressService extends Service {
             // Most likely am killed Shell before user tapped the notification. Since system might
             // be too busy anwyays, it's better to ignore the notification and switch back to the
             // non-interactive mode (where the bugerport will be shared upon completion).
-            Log.d(TAG, "takeScreenshot(" + id + ", " + delayed + "): cancel notification");
+            Log.w(TAG, "takeScreenshot(): canceling notification because id " + id
+                    + " was not found");
             // TODO: add test case to make sure notification is canceled.
             NotificationManager.from(mContext).cancel(TAG, id);
             return;
@@ -1268,6 +1270,9 @@ public class BugreportProgressService extends Service {
                         if (hasFocus) {
                             return;
                         }
+                        // Select-all is useful just initially, since the date-based filename is
+                        // full of hyphens.
+                        mInfoName.setSelectAllOnFocus(false);
                         sanitizeName();
                     }
                 });
@@ -1276,7 +1281,7 @@ public class BugreportProgressService extends Service {
                         .setView(view)
                         .setTitle(dialogTitle)
                         .setCancelable(false)
-                        .setPositiveButton(context.getString(com.android.internal.R.string.ok),
+                        .setPositiveButton(context.getString(R.string.save),
                                 null)
                         .setNegativeButton(context.getString(com.android.internal.R.string.cancel),
                                 new DialogInterface.OnClickListener()
index 814aa8c..49759c5 100644 (file)
@@ -56,7 +56,7 @@ public class BugreportStorageProvider extends DocumentsProvider {
         final MatrixCursor result = new MatrixCursor(resolveRootProjection(projection));
         final RowBuilder row = result.newRow();
         row.add(Root.COLUMN_ROOT_ID, DOC_ID_ROOT);
-        row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY | Root.FLAG_ADVANCED);
+        row.add(Root.COLUMN_FLAGS, Root.FLAG_LOCAL_ONLY);
         row.add(Root.COLUMN_ICON, android.R.mipmap.sym_def_app_icon);
         row.add(Root.COLUMN_TITLE, getContext().getString(R.string.bugreport_storage_title));
         row.add(Root.COLUMN_DOCUMENT_ID, DOC_ID_ROOT);
index d0499a5..a629aac 100644 (file)
@@ -400,8 +400,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
 
         DetailsUi detailsUi = new DetailsUi(mUiBot, ID);
         detailsUi.assertName(NAME);
-        detailsUi.assertTitle(mContext.getString(R.string.bugreport_info_title));
-        detailsUi.assertDescription(mContext.getString(R.string.bugreport_info_description));
+        detailsUi.assertTitle("");
+        detailsUi.assertDescription("");
         detailsUi.nameField.setText(NEW_NAME);
         detailsUi.titleField.setText(TITLE);
         detailsUi.descField.setText(DESCRIPTION);
@@ -415,8 +415,8 @@ public class BugreportReceiverTest extends InstrumentationTestCase {
 
         detailsUi = new DetailsUi(mUiBot, ID2);
         detailsUi.assertName(NAME2);
-        detailsUi.assertTitle(mContext.getString(R.string.bugreport_info_title));
-        detailsUi.assertDescription(mContext.getString(R.string.bugreport_info_description));
+        detailsUi.assertTitle("");
+        detailsUi.assertDescription("");
         detailsUi.nameField.setText(NEW_NAME2);
         detailsUi.titleField.setText(TITLE2);
         detailsUi.descField.setText(DESCRIPTION2);
index c590ec7..637551c 100644 (file)
@@ -82,6 +82,7 @@
     <uses-permission android:name="android.permission.GET_TOP_ACTIVITY_INFO" />
     <uses-permission android:name="android.permission.MANAGE_ACTIVITY_STACKS" />
     <uses-permission android:name="android.permission.START_TASKS_FROM_RECENTS" />
+    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
 
     <!-- WindowManager -->
     <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
                   android:stateNotNeeded="true"
                   android:resumeWhilePausing="true"
                   android:screenOrientation="behind"
-                  android:theme="@style/RecentsTheme.Wallpaper">
+                  android:theme="@style/RecentsTvTheme.Wallpaper">
             <intent-filter>
                 <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
             </intent-filter>
diff --git a/packages/SystemUI/res/color/notification_guts_buttons.xml b/packages/SystemUI/res/color/notification_guts_buttons.xml
new file mode 100644 (file)
index 0000000..f7a4ee9
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:state_checked="true"
+          android:color="@*android:color/material_deep_teal_500" />
+    <item android:color="@android:color/black"
+          android:alpha=".87" />
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/qs_btn_borderless_rect.xml b/packages/SystemUI/res/drawable/qs_btn_borderless_rect.xml
new file mode 100644 (file)
index 0000000..03bfd1a
--- /dev/null
@@ -0,0 +1,32 @@
+<!--
+     Copyright (C) 2016 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.
+-->
+<inset
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:insetTop="4dp"
+    android:insetBottom="4dp">
+    <ripple
+        android:color="?android:attr/colorControlHighlight" >
+
+        <item android:id="@android:id/mask">
+            <shape>
+                <corners android:radius="@dimen/borderless_button_radius" />
+
+                <solid android:color="@android:color/white" />
+            </shape>
+        </item>
+
+    </ripple>
+</inset>
index 6bb27cc..d90f820 100644 (file)
@@ -15,5 +15,5 @@
 -->
 <transition xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:drawable="@color/qs_detail_transition" />
-    <item android:drawable="?android:attr/windowBackground" />
+    <item android:drawable="@color/system_primary_color" />
 </transition>
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2016 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.
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android">
-    <solid android:color="@color/system_secondary_color" />
-    <corners
-        android:topLeftRadius="0dp"
-        android:topRightRadius="0dp" />
-</shape>
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+       android:shape="rectangle">
+    <gradient
+            android:startColor="#99000000"
+            android:endColor="#E6000000"
+            android:angle="90"/>
+</shape>
\ No newline at end of file
index 62f2b47..1ab6bf9 100644 (file)
@@ -39,7 +39,7 @@
             android:layout_gravity="center_vertical|start">
 
         <ImageView
-                android:id="@android:id/icon"
+                android:id="@+id/app_icon"
                 android:layout_width="18dp"
                 android:layout_height="18dp"
                 android:layout_marginEnd="6dp"
             android:id="@+id/importance_buttons"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingTop="8dp"
-            android:paddingBottom="8dip"
+            android:paddingTop="4dp"
+            android:paddingBottom="16dip"
             android:paddingEnd="8dp" >
         <RadioButton
                 android:id="@+id/silent_importance"
                 android:layout_width="wrap_content"
                 android:layout_height="48dp"
+                android:paddingStart="32dp"
                 android:text="@string/show_silently"
-                style="@style/TextAppearance.NotificationGuts.Primary"
-                android:buttonTint="#858383" />
+                style="@style/TextAppearance.NotificationGuts.Radio"
+                android:buttonTint="@color/notification_guts_buttons" />
         <RadioButton
                 android:id="@+id/block_importance"
                 android:layout_width="wrap_content"
                 android:layout_height="48dp"
+                android:paddingStart="32dp"
                 android:text="@string/block"
-                style="@style/TextAppearance.NotificationGuts.Primary"
-                android:buttonTint="#858383" />
+                style="@style/TextAppearance.NotificationGuts.Radio"
+                android:buttonTint="@color/notification_guts_buttons" />
         <RadioButton
                 android:id="@+id/reset_importance"
                 android:layout_width="wrap_content"
                 android:layout_height="48dp"
-                style="@style/TextAppearance.NotificationGuts.Primary"
-                android:buttonTint="#858383" />
+                android:paddingStart="32dp"
+                style="@style/TextAppearance.NotificationGuts.Radio"
+                android:buttonTint="@color/notification_guts_buttons" />
     </RadioGroup>
     <!-- Importance slider -->
     <LinearLayout
index 52d07fc..f47083a 100644 (file)
@@ -19,6 +19,7 @@
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
+    android:visibility="invisible"
     >
 
     <com.android.systemui.statusbar.AlphaOptimizedImageView
@@ -31,7 +32,6 @@
         android:paddingBottom="@dimen/notification_gear_padding"
         android:src="@drawable/ic_settings"
         android:tint="@color/notification_gear_color"
-        android:visibility="invisible"
         android:alpha="0"
         android:background="?android:attr/selectableItemBackgroundBorderless"
         />
index 603ebbf..b0dca9a 100644 (file)
         android:layout_height="wrap_content"
         android:orientation="horizontal">
      <TextView android:id="@+id/tile_label"
-             android:layout_width="wrap_content"
-             android:layout_height="wrap_content"
-             android:textColor="@color/qs_tile_text"
-             android:gravity="center_horizontal"
-             android:minLines="2"
-             android:padding="0dp"
-             android:fontFamily="sans-serif-condensed"
-             android:textStyle="normal"
-             android:textSize="@dimen/qs_tile_text_size"
-             android:clickable="false" />
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textColor="@color/qs_tile_text"
+            android:gravity="center_horizontal"
+            android:minLines="2"
+            android:padding="0dp"
+            android:fontFamily="sans-serif-condensed"
+            android:textStyle="normal"
+            android:textSize="@dimen/qs_tile_text_size"
+            android:clickable="false" />
      <ImageView android:id="@+id/restricted_padlock"
-             android:layout_width="@dimen/qs_tile_text_size"
-             android:layout_height="@dimen/qs_tile_text_size"
-             android:src="@drawable/ic_settings_lock_outline"
-             android:layout_marginLeft="@dimen/restricted_padlock_pading"
-             android:baselineAlignBottom="true"
-             android:scaleType="centerInside"
-             android:visibility="gone" />
+            android:layout_width="@dimen/qs_tile_text_size"
+            android:layout_height="match_parent"
+            android:paddingBottom="@dimen/qs_tile_text_size"
+            android:src="@drawable/ic_info"
+            android:layout_marginLeft="@dimen/restricted_padlock_pading"
+            android:scaleType="centerInside"
+            android:visibility="gone" />
 </LinearLayout>
\ No newline at end of file
index a22c360..661d74a 100644 (file)
         <ImageView
                 android:id="@+id/restricted_padlock"
                 android:layout_width="@dimen/qs_detail_item_secondary_text_size"
-                android:layout_height="@dimen/qs_detail_item_secondary_text_size"
-                android:src="@drawable/ic_settings_lock_outline"
+                android:layout_height="match_parent"
+                android:gravity="center_vertical"
+                android:src="@drawable/ic_info"
                 android:layout_marginLeft="@dimen/restricted_padlock_pading"
-                android:baselineAlignBottom="true"
                 android:scaleType="centerInside"
                 android:visibility="gone" />
     </LinearLayout>
index 94b099e..3a7c1d1 100644 (file)
     android:id="@+id/recents_view"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:background="@drawable/recents_tv_background_gradient"
     android:clipChildren="false"
-    android:clipToPadding="false" >
-
+    android:clipToPadding="false"
+    android:layoutDirection="rtl">
     <com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
         android:id="@+id/task_list"
         android:layout_width="wrap_content"
     android:focusable="true"
     android:focusableInTouchMode="true"
     android:layout_gravity="center"
-    android:layout_centerInParent="true">
+    android:layout_centerInParent="true"
+    android:layoutDirection="ltr">
 
-    <RelativeLayout
+    <LinearLayout
             android:layout_width="@dimen/recents_tv_card_width"
             android:layout_height="wrap_content"
             android:layout_centerInParent="true"
-            android:layout_gravity="center">
-        <ImageView
-                android:id="@+id/card_view_thumbnail"
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/recents_tv_card_height"
-                android:scaleType="centerCrop"
-                android:gravity="center"
-                android:layout_alignParentTop="true"
-                android:layout_centerHorizontal="true"/>
-
-        <RelativeLayout
+            android:layout_gravity="center"
+            android:orientation="vertical" >
+        <LinearLayout
                 android:id="@+id/card_info_field"
                 android:layout_width="match_parent"
-                android:layout_height="wrap_content"
-                android:layout_below="@id/card_view_thumbnail"
-                android:background="@color/recents_tv_card_background_color" >
+                android:layout_height="wrap_content">
+            <ImageView
+                    android:id="@+id/card_extra_badge"
+                    android:layout_width="@dimen/recents_tv_card_extra_badge_size"
+                    android:layout_height="@dimen/recents_tv_card_extra_badge_size"
+                    android:layout_marginBottom="@dimen/recents_tv_icon_padding_bottom"
+                    android:layout_marginEnd="@dimen/recents_tv_icon_padding_end"
+                    android:scaleType="fitCenter"
+                    android:layout_centerVertical="true"
+                    android:layout_alignParentRight="true" />
             <TextView
                     android:id="@+id/card_title_text"
                     android:layout_width="match_parent"
                     android:layout_alignParentTop="false"
                     android:includeFontPadding="true"
                     android:minLines="1"
-                    android:maxLines="2"
+                    android:maxLines="1"
                     android:textColor="@color/recents_tv_card_title_text_color"
-                    android:ellipsize="end" />
-            <TextView
-                    android:id="@+id/card_content_text"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_alignParentStart="true"
-                    android:layout_below="@id/card_title_text"
-                    android:includeFontPadding="true"
-                    android:minLines="1"
-                    android:maxLines="2"
-                    android:textColor="@color/recents_tv_card_content_text_color"
-                    android:ellipsize="end" />
-            <ImageView
-                    android:id="@+id/card_extra_badge"
-                    android:layout_width="@dimen/recents_tv_card_extra_badge_size"
-                    android:layout_height="@dimen/recents_tv_card_extra_badge_size"
-                    android:scaleType="fitCenter"
-                    android:background="@android:color/transparent"
-                    android:contentDescription="@null"
-                    android:layout_centerVertical="true"
-                    android:layout_alignParentRight="true"/>
-        </RelativeLayout>
-    </RelativeLayout>
+                    android:fontFamily="@string/font_roboto_regular"
+                    android:textSize="@dimen/recents_tv_title_text_size"
+                    android:layout_marginBottom="@dimen/recents_tv_text_padding_bottom"
+                    android:ellipsize="end"/>
+        </LinearLayout>
+        <ImageView
+                android:id="@+id/card_view_thumbnail"
+                android:layout_width="match_parent"
+                android:layout_height="@dimen/recents_tv_card_height"
+                android:scaleType="centerCrop"
+                android:gravity="center"
+                android:layout_alignParentTop="true"
+                android:layout_centerHorizontal="true"
+                android:layout_below="@id/card_title_text" />
+    </LinearLayout>
 </com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
index 818df3b..75195c4 100644 (file)
@@ -43,7 +43,7 @@
             android:singleLine="true"
             android:ellipsize="start"
             android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
-            android:imeOptions="actionSend" />
+            android:imeOptions="actionSend|flagNoExtractUi" />
 
     <FrameLayout
             android:layout_width="wrap_content"
index 289b1d9..656941f 100644 (file)
@@ -39,8 +39,9 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <include
-            layout="@layout/qs_panel"
+        <com.android.systemui.DensityContainer
+            android:id="@+id/qs_density_container"
+            android:layout="@layout/qs_panel"
             android:layout_width="@dimen/notification_panel_width"
             android:layout_height="wrap_content"
             android:layout_gravity="@integer/notification_panel_layout_gravity" />
index 61d4f14..30d9ed7 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meer tyd."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minder tyd."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Flitslig af."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Flitslig is nie beskikbaar nie."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Flitslig aan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Flitslig afgeskakel."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Flitslig aangeskakel."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Skakel Bluetooth aan?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jy moet Bluetooth aanskakel om jou sleutelbord aan jou tablet te koppel."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Skakel aan"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Wys kennisgewings sonder klank"</string>
+    <string name="block" msgid="2734508760962682611">"Blokkeer alle kennisgewings"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Moenie stilmaak nie"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Moenie stilmaak of blokkeer nie"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Wys volledige belangrikheidinstellings"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Geblokkeer"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Onbelangrik"</string>
     <string name="low_importance" msgid="4109929986107147930">"Min belang"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normale belang"</string>
     <string name="high_importance" msgid="1527066195614050263">"Groot belang"</string>
     <string name="max_importance" msgid="5089005872719563894">"Dringende belang"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Moet nooit hierdie kennisgewings wys nie"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Wys sonder klank aan die onderkant van die kennisgewinglys"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Wys hierdie kennisgewings sonder klank"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Laat hierdie kennisgewing toe om geluide te maak"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Verskyn vlugtig op die skerm en laat klank toe"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Wys boaan die kennisgewingslys, verskyn vlugtig op die skerm en laat klank toe"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
     <string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Kleur en voorkoms"</string>
     <item msgid="2139628951880142927">"Wys persentasie wanneer gelaai word (verstek)"</item>
     <item msgid="3327323682209964956">"Moenie hierdie ikoon wys nie"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Ander"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Skermverdeler"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Skuif af"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Skuif op"</string>
index 6d70c8a..9692ae8 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"ተጨማሪ ጊዜ።"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ያነሰ ጊዜ።"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"የባትሪ ብርሃን ጠፍቷል።"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"የባትሪ ብርሃን አይገኝም።"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"የባትሪ ብርሃን በርቷል።"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"የባትሪ ብርሃን ጠፍቷል።"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"የባትሪ ብርሃን በርቷል።"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ብሉቱዝ ይብራ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"የቁልፍ ሰሌዳዎን ከእርስዎ ጡባዊ ጋር ለማገናኘት በመጀመሪያ ብሉቱዝን ማብራት አለብዎት።"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"አብራ"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"ማሳወቂያዎችን በጸጥታ አሳይ"</string>
+    <string name="block" msgid="2734508760962682611">"ሁሉንም ማሳወቂያዎች አግድ"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"ድምፅ አትዝጋ"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"ድምፅ አትዝጋ ወይም አታግድ"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"ሙሉ የአስፈላጊነት ቅንብሮችን አሳይ"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"የታገዱ"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"አነስተኛ አስፈላጊነት"</string>
     <string name="low_importance" msgid="4109929986107147930">"ዝቅተኛ አስፈላጊነት"</string>
     <string name="default_importance" msgid="8192107689995742653">"መደበኛ አስፈላጊነት"</string>
     <string name="high_importance" msgid="1527066195614050263">"ከፍተኛ አስፈላጊነት"</string>
     <string name="max_importance" msgid="5089005872719563894">"አስቸኳይ አስፈላጊነት"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"እነዚህን ማሳወቂያዎች በጭራሽ አታሳይ"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"በማሳወቂያ ዝርዝሩ ታችኛውን ክፍል ላይ በጸጥታ አሳይ"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"እነዚህን ማሳወቂያዎች በጸጥታ አሳይ"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"እነዚህ ማሳወቂያዎች ድምፆችን እንዲፈጥሩ ፍቀድ"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"ወደ ማያ ገጹ አስገባና ድምፅ ፍቀድ"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"በማሳወቂያዎች ዝርዝር አናት ላይ አሳይ፣ ወደ ማያ ገጹ አሳይና ድምፅ ፍቀድ"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"ተጨማሪ ቅንብሮች"</string>
     <string name="notification_done" msgid="5279426047273930175">"ተከናውኗል"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"ቀለም እና መልክ"</string>
     <item msgid="2139628951880142927">"የባትሪ ኃይል በሚሞላበት ጊዜ መቶኛ አሳይ (ነባሪ)"</item>
     <item msgid="3327323682209964956">"ይህን አዶ አታሳይ"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"ሌላ"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"የተከፈለ የማያ ገጽ ከፋይ"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ወደ ታች ሂድ"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ወደ ላይ ሂድ"</string>
index 2e4724b..3edc805 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Baterijska lampa je isključena."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampa nije dostupna."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Baterijska lampa je uključena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Baterijska lampa je isključena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Baterijska lampa je uključena."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želite li da uključite Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da biste povezali tastaturu sa tabletom, prvo morate da uključite Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Prikazuj obaveštenja bez zvuka"</string>
+    <string name="block" msgid="2734508760962682611">"Blokiraj sva obaveštenja"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ne isključuj zvuk"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ne isključuju zvuk niti blokiraj"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Prikaži kompletna podešavanja važnosti"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokirana"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Veoma mala važnost"</string>
     <string name="low_importance" msgid="4109929986107147930">"Mala važnost"</string>
     <string name="default_importance" msgid="8192107689995742653">"Uobičajena važnost"</string>
     <string name="high_importance" msgid="1527066195614050263">"Velika važnost"</string>
     <string name="max_importance" msgid="5089005872719563894">"Važnost: hitno"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ova obaveštenja se nikada ne prikazuju"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Prikazuju se u dnu liste obaveštenja bez zvuka"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Ova obaveštenja se prikazuju bez zvuka"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Dozvolite da ova obaveštenja emituju zvuk"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Nakratko se prikazuju na ekranu i emituju zvuk"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Prikazuju se u vrhu liste obaveštenja, nakratko se prikazuju na ekranu i emituju zvuk"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
     <item msgid="2139628951880142927">"Prikaži procenat tokom punjenja (podrazumevano)"</item>
     <item msgid="3327323682209964956">"Ne prikazuj ovu ikonu"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Drugo"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Razdelnik podeljenog ekrana"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomeri nadole"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomeri nagore"</string>
index c97a6a5..84757b7 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Повече време."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"По-малко време."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Фенерчето е изключено."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Няма достъп до фенерчето."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Фенерчето е включено."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Фенерчето е изключено."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Фенерчето е включено."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Да се включи ли Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"За да свържете клавиатурата с таблета си, първо трябва да включите Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включване"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Показване на известията без звуков сигнал"</string>
+    <string name="block" msgid="2734508760962682611">"Блокиране на всички известия"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Без заглушаване на звуковите сигнали"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Без заглушаване на звуковите сигнали или блокиране"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Показване на пълните настройки за важността"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Блокирано"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Минимална важност"</string>
     <string name="low_importance" msgid="4109929986107147930">"Малка важност"</string>
     <string name="default_importance" msgid="8192107689995742653">"Нормална важност"</string>
     <string name="high_importance" msgid="1527066195614050263">"Голяма важност"</string>
     <string name="max_importance" msgid="5089005872719563894">"Неотложна важност"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Тези известия не се показват"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Показване без звуков сигнал най-долу в списъка с известия"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Показване на тези известия без звуков сигнал"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Разрешаване при тези известия да се издава звуков сигнал"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Показване на екрана и разрешаване на звуков сигнал"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Показване най-горе в списъка с известия, както и на екрана и разрешаване на звуков сигнал"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Цвят и облик"</string>
     <item msgid="2139628951880142927">"Процентът да се показва при зареждане (по подразбиране)"</item>
     <item msgid="3327323682209964956">"Тази икона да не се показва"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Друго"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Разделител в режима за разделен екран"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Преместване надолу"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Преместване нагоре"</string>
index f59f3ca..18f37e6 100644 (file)
     <string name="accessibility_divider" msgid="5903423481953635044">"বিভক্ত-স্ক্রীন বিভাজক"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"নীচে সরান"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"উপরে সরান"</string>
-    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"বামে সরান"</string>
+    <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"বাà¦\81য়ে সরান"</string>
     <string name="accessibility_action_divider_move_right" msgid="4671522715182567972">"ডানে সরান"</string>
 </resources>
index 865b1ad..5666c5f 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Više vremena."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Manje vremena."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svjetiljka isključena."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svjetiljka nije dostupna."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svjetiljka uključena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svjetiljka je isključena."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svjetiljka je uključena."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Želiti li uključiti Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Da povežete tastaturu sa tabletom, prvo morate uključiti Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Uključi"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Nečujno pokaži obavijesti"</string>
+    <string name="block" msgid="2734508760962682611">"Blokiraj sva obavještenja"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nemoj utišati"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nemoj utišati ili blokirati"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Pokaži kompletne postavke za određivanje značaja"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokirano"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Minimalni značaj"</string>
     <string name="low_importance" msgid="4109929986107147930">"Mali značaj"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normalan značaj"</string>
     <string name="high_importance" msgid="1527066195614050263">"Visok značaj"</string>
     <string name="max_importance" msgid="5089005872719563894">"Hitan značaj"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nikada ne prikazuj ova obavještenja"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Nečujno pokaži na dnu spiska obavještenja"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Nečujno prikaži ova obavještenja"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Dozvolite zvuk na ovim obavještenjima"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Kratko prikaži na ekranu i dozvoli zvuk i dozvoli zvuk"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Pokaži na vrhu liste obaveštenja, kratko prikaži na ekranu i dozvoli zvuk"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Boja i izgled"</string>
     <item msgid="2139628951880142927">"Pokaži postotak u toku punjenja (zadano)"</item>
     <item msgid="3327323682209964956">"Ne prikazuj ovu ikonu"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Ostalo"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Razdjelnik ekrana"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pomjeri dolje"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pomjeri gore"</string>
index 3243f74..3747be0 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Més temps"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menys temps"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Llanterna desactivada"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"La llanterna no està disponible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Llanterna activada"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Llanterna desactivada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Llanterna activada."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vols activar el Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connectar el teclat amb la tauleta, primer has d\'activar el Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activa"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Mostra les notificacions de manera silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloqueja totes les notificacions"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"No silenciïs"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"No silenciïs ni bloquegis"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostra la configuració de la importància completa"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloquejades"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importància mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importància baixa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importància normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importància alta"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importància urgent"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"No mostris mai aquestes notificacions"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Les notificacions es mostren de manera silenciosa al capdavall de la llista"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostra aquestes notificacions de manera silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permet que aquestes notificacions emetin sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Les notificacions apareixen a la pantalla i poden emetre sons"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Les notificacions es mostren al capdamunt de la llista, apareixen a la pantalla i poden emetre sons"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fet"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Color i aparença"</string>
     <item msgid="2139628951880142927">"Mostra el percentatge quan es carregui (opció predeterminada)"</item>
     <item msgid="3327323682209964956">"No mostris aquesta icona"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Altres"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalles"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mou avall"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mou amunt"</string>
index b5b4037..48c9c55 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Delší doba"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kratší doba"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svítilna je vypnutá."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svítilna není k dispozici."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svítilna je zapnutá."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svítilna je vypnutá."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svítilna je zapnutá."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnout Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Chcete-li klávesnici připojit k tabletu, nejdříve musíte zapnout Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnout"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Zobrazovat oznámení tiše"</string>
+    <string name="block" msgid="2734508760962682611">"Blokovat všechna oznámení"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Bez ztlumení"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Bez ztlumení a blokování"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Zobrazit všechna nastavení důležitosti"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokováno"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Minimální důležitost"</string>
     <string name="low_importance" msgid="4109929986107147930">"Nízká důležitost"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normální důležitost"</string>
     <string name="high_importance" msgid="1527066195614050263">"Vysoká důležitost"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgentní důležitost"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Tato oznámení nikdy nezobrazovat"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Tato oznámení zobrazovat na konci seznamu bez zvukového upozornění"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tato oznámení zobrazovat bez zvukového upozornění"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Povolit těmto oznámením vydávat zvuky"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Tato oznámení zobrazovat přímo na obrazovce a upozornit na ně zvukem"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Tato oznámení zobrazovat na začátku seznamu, zobrazit přímo na obrazovce a upozornit na ně zvukem"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Další nastavení"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Barva a vzhled"</string>
     <item msgid="2139628951880142927">"Zobrazovat procento při nabíjení (výchozí nastavení)"</item>
     <item msgid="3327323682209964956">"Tuto ikonu nezobrazovat"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Jiné"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Čára rozdělující obrazovku"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Přesunout dolů"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Přesunout nahoru"</string>
index f4987d7..50d01ea 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mere tid."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mindre tid."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lommelygten er slået fra."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lommelygten er ikke tilgængelig."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lommelygten er slået til."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lommelygten er slået fra."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lommelygten er slået til."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå Bluetooth til?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Bluetooth skal være slået til, før du kan knytte dit tastatur til din tablet."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå til"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Vis underretninger lydløst"</string>
+    <string name="block" msgid="2734508760962682611">"Bloker alle underretninger"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Skal ikke sættes på lydløs"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Skal ikke sættes på lydløs eller blokeres"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Vis alle indstillinger for vigtighed"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokeret"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Min vigtighed"</string>
     <string name="low_importance" msgid="4109929986107147930">"Lille vigtighed"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normal vigtighed"</string>
     <string name="high_importance" msgid="1527066195614050263">"Stor vigtighed"</string>
     <string name="max_importance" msgid="5089005872719563894">"Presserende vigtighed"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Vis aldrig disse underretninger"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Vis lydløst nederst på listen over underretninger"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Vis disse underretninger lydløst"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Giv disse underretninger tilladelse til at give lyd"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Vis på skærmen, og tillad lyd"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Vis øverst på listen over underretninger, vis på skærmen, og tillad lyd"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
     <string name="notification_done" msgid="5279426047273930175">"Færdig"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Farve og udseende"</string>
     <item msgid="2139628951880142927">"Vis procent ved opladning (standard)"</item>
     <item msgid="3327323682209964956">"Vis ikke dette ikon"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Andet"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Adskiller til delt skærm"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flyt ned"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flyt op"</string>
index ac0adbb..fd8cf89 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mehr Zeit"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Weniger Zeit"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Taschenlampe deaktiviert"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Taschenlampe nicht verfügbar."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Taschenlampe aktiviert"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Die Taschenlampe ist deaktiviert."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Die Taschenlampe ist aktiviert."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth aktivieren?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Zum Verbinden von Tastatur und Tablet muss Bluetooth aktiviert sein."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivieren"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Benachrichtigungen ohne Ton anzeigen"</string>
+    <string name="block" msgid="2734508760962682611">"Alle Benachrichtigungen blockieren"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nicht stummschalten"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nicht stummschalten oder blockieren"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Vollständige Wichtigkeitseinstellungen anzeigen"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blockiert"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Minimum-Wichtigkeit"</string>
     <string name="low_importance" msgid="4109929986107147930">"Geringe Wichtigkeit"</string>
     <string name="default_importance" msgid="8192107689995742653">"Reguläre Wichtigkeit"</string>
     <string name="high_importance" msgid="1527066195614050263">"Hohe Wichtigkeit"</string>
     <string name="max_importance" msgid="5089005872719563894">"Sehr hohe Wichtigkeit"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Diese Benachrichtigungen niemals anzeigen"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Ohne Ton am Ende der Benachrichtigungsliste anzeigen"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Diese Benachrichtigungen ohne Ton anzeigen"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Für diese Benachrichtigungen Ton zulassen"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Auf dem Display einblenden und Ton zulassen"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Ganz oben in der Benachrichtigungsliste anzeigen, auf dem Display einblenden und Ton zulassen"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Farbe und Darstellung"</string>
     <item msgid="2139628951880142927">"Prozentwert beim Laden anzeigen (Standardeinstellung)"</item>
     <item msgid="3327323682209964956">"Dieses Symbol nicht anzeigen"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Sonstiges"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Bildschirmteiler"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Nach unten verschieben"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Nach oben verschieben"</string>
index 754c92e..b5f55d9 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Περισσότερη ώρα."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Λιγότερη ώρα."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ανενεργός φακός."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Ο φακός δεν είναι διαθέσιμος."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ενεργός φακός."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ο φακός απενεργοποιήθηκε."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ο φακός ενεργοποιήθηκε."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ενεργοποίηση Bluetooth;"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Για να συνδέσετε το πληκτρολόγιο με το tablet σας, θα πρέπει πρώτα να ενεργοποιήσετε το Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ενεργοποίηση"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Εμφάνιση ειδοποιήσεων χωρίς ήχο"</string>
+    <string name="block" msgid="2734508760962682611">"Αποκλεισμός όλων των ειδοποιήσεων"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Χωρίς σίγαση"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Χωρίς σίγαση ή αποκλεισμό"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Εμφάνιση όλων των ρυθμίσεων βαρύτητας"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Αποκλεισμένες"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Ελάχιστη βαρύτητα"</string>
     <string name="low_importance" msgid="4109929986107147930">"Μικρής βαρύτητας"</string>
     <string name="default_importance" msgid="8192107689995742653">"Κανονικής βαρύτητας"</string>
     <string name="high_importance" msgid="1527066195614050263">"Μεγάλης βαρύτητας"</string>
     <string name="max_importance" msgid="5089005872719563894">"Επείγουσες"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Να μην εμφανίζονται ποτέ αυτές οι ειδοποιήσεις"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Να εμφανίζονται στο κάτω μέρος της λίστας ειδοποιήσεων χωρίς ήχο"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Να εμφανίζονται αυτές οι ειδοποιήσεις χωρίς ήχο"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Να επιτρέπονται οι ήχοι από αυτές τις ειδοποιήσεις"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Να προβάλλονται στην οθόνη και να επιτρέπεται ο ήχος"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Να εμφανίζονται στην κορυφή της λίστας ειδοποιήσεων, να προβάλλονται στην οθόνη και να επιτρέπεται ο ήχος"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
     <string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Χρώμα και εμφάνιση"</string>
     <item msgid="2139628951880142927">"Να εμφανίζεται ποσοστό κατά τη φόρτιση (προεπιλογή)"</item>
     <item msgid="3327323682209964956">"Να μην εμφανίζεται αυτό το εικονίδιο"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Άλλο"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Διαχωριστικό οθόνης"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Μετακίνηση προς τα κάτω"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Μετακίνηση προς τα επάνω"</string>
index f3c21df..856c1c1 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Más tiempo"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tiempo"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Linterna desactivada"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"La linterna no está disponible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Linterna activada"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Linterna desactivada"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Linterna activada"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar el teclado con la tablet, primero debes activar Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificaciones de manera silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas las notificaciones"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"No silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"No silenciar ni bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar configuración de importancia"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importancia mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Poca importancia"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importancia alta"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"No mostrar nunca estas notificaciones"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar en la parte inferior de la lista de notificaciones sin emitir sonido"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificaciones de manera silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que estas notificaciones emitan sonidos"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Ver en la pantalla y permitir sonidos"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar en la parte superior de la lista de notificaciones, ver en la pantalla y permitir sonidos"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
     <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Color y apariencia"</string>
     <item msgid="2139628951880142927">"Mostrar el porcentaje durante la carga (predeterminado)"</item>
     <item msgid="3327323682209964956">"No mostrar este ícono"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Otros"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalla dividida"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover hacia abajo"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover hacia arriba"</string>
index bd9cc00..b3eda73 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Más tiempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tiempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Linterna desactivada."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"La linterna no está disponible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Linterna activada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Linterna desactivada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Linterna activada."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"¿Activar Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para poder conectar tu teclado a tu tablet, debes activar el Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificaciones de forma silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas las notificaciones"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"No silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"No silenciar ni bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar ajustes de importancia por completo"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importancia mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Poco importante"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Muy importante"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"No mostrar estas notificaciones"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar en la parte inferior de la lista de notificaciones de forma silenciosa"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificaciones de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que estas notificaciones reproduzcan sonidos"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar en la pantalla y permitir sonido"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar en la parte superior de la lista de notificaciones, mostrar en la pantalla y permitir sonido"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Más ajustes"</string>
     <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Color y aspecto"</string>
     <item msgid="2139628951880142927">"Mostrar porcentaje durante la carga (predeterminado)"</item>
     <item msgid="3327323682209964956">"No mostrar este icono"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Otros"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Dividir la pantalla"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Bajar"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
index a245bf7..3f8e844 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Denbora gehiago."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Denbora gutxiago."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Flasha desaktibatuta dago."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Linterna ez dago erabilgarri."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Flasha aktibatuta dago."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Flasha desaktibatu egin da."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Flasha aktibatu egin da."</string>
     <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Garbitu"</string>
     <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Aplikazioak ez du onartzen leiho bat baino gehiago erabiltzea"</string>
     <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Aplikazioak ez du onartzen leiho bat baino gehiago erabiltzea"</string>
-    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Banaketa horizontala"</string>
-    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Banaketa bertikala"</string>
-    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Banaketa pertsonalizatua"</string>
+    <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Zatitze horizontala"</string>
+    <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Zatitze bertikala"</string>
+    <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Zatitze pertsonalizatua"</string>
     <string name="expanded_header_battery_charged" msgid="5945855970267657951">"Kargatuta"</string>
     <string name="expanded_header_battery_charging" msgid="205623198487189724">"Kargatzen"</string>
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g> falta zaizkio guztiz kargatzeko"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth eginbidea aktibatu nahi duzu?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Teklatua tabletara konektatzeko, Bluetooth eginbidea aktibatu behar duzu."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktibatu"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Erakutsi jakinarazpenak soinurik egin gabe"</string>
+    <string name="block" msgid="2734508760962682611">"Blokeatu jakinarazpen guztiak"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ez isilarazi"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ez isilarazi edo blokeatu"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Erakutsi garrantzia handiko jakinarazpenen ezarpenak"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokeatuta"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Gutxieneko garrantzia"</string>
     <string name="low_importance" msgid="4109929986107147930">"Garrantzi txikia"</string>
     <string name="default_importance" msgid="8192107689995742653">"Garrantzi normala"</string>
     <string name="high_importance" msgid="1527066195614050263">"Garrantzi handia"</string>
     <string name="max_importance" msgid="5089005872719563894">"Premiazkoa"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ez erakutsi jakinarazpen hauek inoiz"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Erakutsi jakinarazpen hauek zerrendaren behealdean, baina soinurik egin gabe"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Erakutsi jakinarazpen hauek, baina soinurik egin gabe"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Egin soinua jakinarazpen hauek jasotzean"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Agerrarazi jakinarazpen hauek pantailan eta egin soinua"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Erakutsi jakinarazpen hauek zerrendaren goialdean, agerrarazi pantailan eta egin soinua"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
     <string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Kolorea eta itxura"</string>
     <string name="use_dark_theme" msgid="2900938704964299312">"Erabili gai iluna Android sistema eragilean"</string>
     <string name="adjust_tint" msgid="3398569573231409878">"Doitu kolorea"</string>
     <string name="adjust_brightness" msgid="980039329808178246">"Doitu distira"</string>
-    <string name="night_mode_disclaimer" msgid="598914896926759578">"Gai iluna Android sistema eragileko eremu nagusietan aplikatzen da. Normalean gai argian bistaratzen dira eremu horiek, adibidez, Ezarpenak atala."</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Gai iluna Android sistema eragileko eremu nagusietan aplikatzen da. Normalean gai argian bistaratzen dira eremu horiek, adibidez, Ezarpenak atalean."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplikatu"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Berretsi ezarpenak"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Baliteke gailua kolore-ezarpen batzuekin ezin erabili izatea. Kolore-ezarpenak berresteko, sakatu Ados. Bestela, hamar segundoren buruan berrezarriko dira ezarpenak."</string>
     <item msgid="2139628951880142927">"Erakutsi ehunekoa kargatu bitartean (balio lehenetsia)"</item>
     <item msgid="3327323682209964956">"Ez erakutsi ikonoa"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Beste bat"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Pantaila-zatitzailea"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Eraman behera"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Eraman gora"</string>
index 2243191..8b3fb5e 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lisää aikaa."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Vähennä aikaa."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Taskulamppu on pois päältä."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Taskulamppu ei ole käytettävissä."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Taskulamppu on päällä."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Taskulamppu poistettiin käytöstä."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Taskulamppu otettiin käyttöön."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Otetaanko Bluetooth käyttöön?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Jotta voit yhdistää näppäimistön tablettiisi, sinun on ensin otettava Bluetooth käyttöön."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ota käyttöön"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Näytä ilmoitukset hiljennettyinä"</string>
+    <string name="block" msgid="2734508760962682611">"Estä kaikki ilmoitukset"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Älä hiljennä"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Älä hiljennä tai estä"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Näytä kaikki tärkeysasetukset"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Estetyt"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Pienin tärkeys"</string>
     <string name="low_importance" msgid="4109929986107147930">"Ei kovin tärkeä"</string>
     <string name="default_importance" msgid="8192107689995742653">"Tärkeä"</string>
     <string name="high_importance" msgid="1527066195614050263">"Hyvin tärkeä"</string>
     <string name="max_importance" msgid="5089005872719563894">"Kiireellinen"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Älä koskaan näytä näitä ilmoituksia"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Hiljennä ilmoitukset ja näytä ne ilmoitusluettelon alaosassa."</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Näytä nämä ilmoitukset hiljennettyinä."</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Salli näiden ilmoitusten äänet."</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Näytä ilmoitukset näytöllä ja salli niiden äänet."</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Näytä ilmoitukset näytöllä ja ilmoitusluettelon yläosassa ja salli niiden äänet."</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
     <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Väri ja ulkoasu"</string>
     <item msgid="2139628951880142927">"Näytä prosenttiluku latauksen aikana (oletus)"</item>
     <item msgid="3327323682209964956">"Älä näytä tätä kuvaketta"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Muu"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Näytön jakaja"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Siirrä alaspäin"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Siirrä ylöspäin"</string>
index b957dba..e0beeca 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Plus longtemps"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Moins longtemps."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampe de poche désactivée."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampe de poche indisponible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampe de poche activée."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampe de poche désactivée."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampe de poche activée."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter votre clavier à votre tablette, vous devez d\'abord activer la connectivité Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Afficher les notifications en mode silencieux"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquer toutes les notifications"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ne pas activer le mode silencieux"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ne pas activer le mode silencieux ni bloquer"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Afficher les paramètres d\'importance complets"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloquée"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importance minimale"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importance faible"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importance normale"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importance élevée"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importance urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ne jamais afficher ces notifications"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Afficher en mode silencieux au bas de la liste de notifications"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Afficher ces notifications en mode silencieux"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Autoriser ces notifications à émettre des sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Afficher sur l\'écran et émettre un son"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Afficher en haut de la liste des notifications, afficher sur l\'écran et émettre un son"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
     <string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Couleur et apparence"</string>
     <item msgid="2139628951880142927">"Montrer le pourcentage durant la charge (par défaut)"</item>
     <item msgid="3327323682209964956">"Ne pas afficher cette icône"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Autre"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Séparateur d\'écran partagé"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Déplacer vers le bas"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
index a7bf20b..9ef6392 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Plus longtemps"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Moins longtemps"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampe de poche désactivée."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampe de poche indisponible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampe de poche activée."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampe de poche désactivée."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampe de poche activée."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activer le Bluetooth ?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pour connecter un clavier à votre tablette, vous devez avoir activé le Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activer"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Afficher les notifications en mode silencieux"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquer toutes les notifications"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ne pas activer le mode silencieux"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ne pas activer le mode silencieux ni bloquer"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Afficher les paramètres d\'importance complets"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloquées"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importance minimale"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importance faible"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importance normale"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importance élevée"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgent"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ne jamais afficher ces notifications"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Afficher au bas de la liste des notifications en mode silencieux"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Afficher ces notifications en mode silencieux"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Autoriser ces notifications à émettre des sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Afficher sur l\'écran et émettre un son"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Afficher en haut de la liste des notifications, afficher sur l\'écran et émettre un son"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
     <string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Couleur et apparence"</string>
     <item msgid="2139628951880142927">"Afficher le pourcentage lorsque l\'appareil est en charge (option par défaut)"</item>
     <item msgid="3327323682209964956">"Ne plus afficher cette icône"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Autre"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Séparateur d\'écran partagé"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Déplacer vers le bas"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Déplacer vers le haut"</string>
index d24c424..bb85708 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Máis tempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desactivada."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"A lanterna non está dispoñible."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna activada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Desactivouse a lanterna."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Activouse a lanterna."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Queres activar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teu teclado co tablet, primeiro tes que activar o Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activar"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificacións de forma silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas as notificacións"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Non silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Non silenciar nin bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar a configuración completa da importancia"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueada"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importancia mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importancia baixa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importancia normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importancia alta"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importancia urxente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Non mostrar nunca estas notificacións"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar de forma silenciosa na parte inferior da lista de notificacións"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificacións de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que esta notificación emita son"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar na pantalla e permitir que emita son"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificacións, amosar na pantalla e permitir que emita son"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
     <string name="notification_done" msgid="5279426047273930175">"Feito"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aspecto"</string>
     <item msgid="2139628951880142927">"Mostrar porcentaxe durante a carga (predeterminado)"</item>
     <item msgid="3327323682209964956">"Non mostrar esta icona"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Outros"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de pantalla dividida"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Baixar"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Subir"</string>
index 08dfb23..09e7f70 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Ավելացնել ժամանակը:"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Պակասեցնել ժամանակը:"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Լապտերն անջատված է:"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Լապտերն անհասանելի է:"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Լապտերը միացված է:"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Լապտերն անջատվեց:"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Լապտերը միացավ:"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Միացնե՞լ Bluetooth-ը:"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ստեղնաշարը ձեր պլանշետին միացնելու համար նախ անհրաժեշտ է միացնել Bluetooth-ը:"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Միացնել"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Ցույց տալ ծանուցումներն առանց ձայնային ազդանշանի"</string>
+    <string name="block" msgid="2734508760962682611">"Արգելափակել բոլոր ծանուցումները"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ձայնը չանջատել"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ձայնը չանջատել և չարգելափակել"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Ցույց տալ կարևորության բոլոր կարգավորումները"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Արգելափակված"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Նվազագույն կարևորություն"</string>
     <string name="low_importance" msgid="4109929986107147930">"Ցածր կարևորություն"</string>
     <string name="default_importance" msgid="8192107689995742653">"Սովորական կարևորություն"</string>
     <string name="high_importance" msgid="1527066195614050263">"Բարձր կարևորություն"</string>
     <string name="max_importance" msgid="5089005872719563894">"Հրատապ կարևորություն"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Երբեք չցուցադրել այս ծանուցումները"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Ցուցադրել ծանուցումների ցանկի ներքևում առանց ձայնային ազդանշանի"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Ցուցադրել այս ծանուցումներն առանց ձայնային ազդանշանի"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Թույլ տալ այս ծանուցումներին ձայնային ազդանշան հնչեցնել"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Թռուցիկ ցուցադրել էկրանին և թույլատրել ձայնային ազդանշանը"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Ցույց տալ ծանուցումների ցանկի վերևում, թռուցիկ ցուցադրել էկրանին և թույլատրել ձայնային ազդանշանը"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
     <string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Գույնը և արտաքին տեսքը"</string>
     <item msgid="2139628951880142927">"Ցույց տալ տոկոսը լիցքավորելու ժամանակ (կանխադրված է)"</item>
     <item msgid="3327323682209964956">"Ցույց չտալ այս պատկերակը"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Այլ"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Տրոհված էկրանի բաժանիչ"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Տեղափոխել ներքև"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Տեղափոխել վերև"</string>
index 3fa41be..46340a7 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lebih lama."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Lebih cepat."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Senter nonaktif."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Senter tidak tersedia."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Senter aktif."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Senter dinonaktifkan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Senter diaktifkan."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Aktifkan Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menghubungkan keyboard dengan tablet, terlebih dahulu aktifkan Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktifkan"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Tampilkan notifikasi tanpa suara"</string>
+    <string name="block" msgid="2734508760962682611">"Blokir semua notifikasi"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Jangan bisukan"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Jangan bisukan atau blokir"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tampilkan setelan lengkap nilai penting"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Diblokir"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Nilai penting min"</string>
     <string name="low_importance" msgid="4109929986107147930">"Tingkat kepentingan: rendah"</string>
     <string name="default_importance" msgid="8192107689995742653">"Tingkat kepentingan: normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Tingkat kepentingan: tinggi"</string>
     <string name="max_importance" msgid="5089005872719563894">"Tingkat kepentingan: darurat"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan pernah tunjukkan notifikasi ini"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Tampilkan di bagian bawah daftar notifikasi tanpa suara"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tampilkan notifikasi ini tanpa suara"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Izinkan notifikasi ini bersuara"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Muncul di layar dan izinkan suara"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Tampilkan di bagian atas daftar notifikasi, muncul di layar, dan izinkan suara"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Setelan lainnya"</string>
     <string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Warna dan tampilan"</string>
     <item msgid="2139628951880142927">"Tampilkan persentase saat mengisi daya (default)"</item>
     <item msgid="3327323682209964956">"Jangan tampilkan ikon ini"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Lainnya"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Pembagi layar terpisah"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Turunkan"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Naikkan"</string>
index e3c3aa8..89708de 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Meiri tími."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Minni tími."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Slökkt á vasaljósi."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Vasaljós ekki tiltækt"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Kveikt á vasaljósi."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Slökkt á vasaljósi."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Kveikt á vasaljósi."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Kveikja á Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Til að geta tengt lyklaborðið við spjaldtölvuna þarftu fyrst að kveikja á Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Kveikja"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Sýna tilkynningar án hljóðs"</string>
+    <string name="block" msgid="2734508760962682611">"Loka á allar tilkynningar"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ekki þagga"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Hvorki þagga né útiloka"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Sýna stillingar fyrir mikilvægi"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Útilokuð"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Lítill forgangur"</string>
     <string name="low_importance" msgid="4109929986107147930">"Ekki svo mikilvægt"</string>
     <string name="default_importance" msgid="8192107689995742653">"Venjulegt mikilvægi"</string>
     <string name="high_importance" msgid="1527066195614050263">"Mjög mikilvægt"</string>
     <string name="max_importance" msgid="5089005872719563894">"Afar áríðandi"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Aldrei sýna þessar tilkynningar"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Sýna neðst á tilkynningalistanum án hljóðs"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Sýna þessar tilkynningar án hljóðs"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Leyfa þessum tilkynningum að spila hljóð"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Birta á skjánum og leyfa hljóð"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Sýna efst á tilkynningalistanum, birta á skjánum og leyfa hljóð"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Litur og útlit"</string>
     <item msgid="2139628951880142927">"Sýna hlutfall meðan á hleðslu stendur (sjálfgefið)"</item>
     <item msgid="3327323682209964956">"Ekki sýna þetta tákn"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Annað"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Skjáskipting"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Færa niður"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Færa upp"</string>
index 5266ba8..d6622e3 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Più tempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Meno tempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Torcia spenta."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Torcia non disponibile."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Torcia accesa."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Torcia disattivata."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Torcia attivata."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Attivare il Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Per connettere la tastiera al tablet, devi prima attivare il Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Attiva"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Mostra silenziosamente le notifiche"</string>
+    <string name="block" msgid="2734508760962682611">"Blocca tutte le notifiche"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Non disattivare i suoni"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Non disattivare i suoni e non bloccare"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostra impostazioni importanza complete"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloccata"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importanza min"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importanza scarsa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importanza normale"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importanza elevata"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importanza urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Non mostrare mai queste notifiche"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostra silenziosamente nella parte inferiore dell\'elenco delle notifiche"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostra silenziosamente queste notifiche"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Attiva i suoni per queste notifiche"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Apri sullo schermo e attiva l\'audio"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostra in cima all\'elenco delle notifiche, apri sullo schermo e attiva l\'audio"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Altre impostazioni"</string>
     <string name="notification_done" msgid="5279426047273930175">"Fine"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Colore e aspetto"</string>
     <item msgid="2139628951880142927">"Mostra la percentuale quando in carica (opzione predefinita)"</item>
     <item msgid="3327323682209964956">"Non mostrare questa icona"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Altro"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Strumento per schermo diviso"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Sposta giù"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Sposta su"</string>
index a13f975..ed44624 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"יותר זמן."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"פחות זמן."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"הפנס כבוי."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"פנס אינו זמין."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"הפנס מופעל."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"הפנס נכבה."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"הפנס הופעל."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"‏האם להפעיל את ה-Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"‏כדי לחבר את המקלדת לטאבלט, תחילה עליך להפעיל את ה-Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"הפעל"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"הצג הודעות בלי להשמיע צליל"</string>
+    <string name="block" msgid="2734508760962682611">"חסום את כל ההודעות"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"לא להשתיק"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"לא להשתיק או לחסום"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"הצג את הגדרות החשיבות במלואן"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"חסום"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"חשיבות מינימלית"</string>
     <string name="low_importance" msgid="4109929986107147930">"חשיבות נמוכה"</string>
     <string name="default_importance" msgid="8192107689995742653">"חשיבות רגילה"</string>
     <string name="high_importance" msgid="1527066195614050263">"חשיבות גבוהה"</string>
     <string name="max_importance" msgid="5089005872719563894">"חשיבות דחופה"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"לעולם אל תציג את ההודעות האלה"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"הצג בסוף רשימת ההודעות בלי להשמיע צליל"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"הצג את ההודעות האלה בלי להשמיע צליל"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"אשר להודעות אלה להשמיע צליל"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"הצג לרגע על גבי המסך ואשר השמעת צליל"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"הצג בראש רשימת ההודעות, הצג לרגע על גבי המסך ואשר השמעת צליל"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
     <string name="notification_done" msgid="5279426047273930175">"סיום"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"צבע ומראה"</string>
     <string name="use_dark_theme" msgid="2900938704964299312">"‏השתמש בעיצוב כהה למערכת ההפעלה של Android."</string>
     <string name="adjust_tint" msgid="3398569573231409878">"התאמת גוון"</string>
     <string name="adjust_brightness" msgid="980039329808178246">"התאמת בהירות"</string>
-    <string name="night_mode_disclaimer" msgid="598914896926759578">"‏העיצוב הכהה מוחל על התחומים העיקריים במערכת ההפעלה של Android שמוצגים בדרך כלל בעיצוב בהיר, כמו \'הגדרות\'."</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"‏העיצוב הכהה מוחל על התחומים העיקריים במערכת ההפעלה Android שמוצגים בדרך כלל בעיצוב בהיר, כמו \'הגדרות\'."</string>
     <string name="color_apply" msgid="9212602012641034283">"החל"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"אישור הגדרות"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"הגדרות צבע מסוימות עלולות להפוך את המכשיר הזה לבלתי שמיש. לחץ על אישור כדי לאשר את הגדרות הצבע האלה, אחרת הגדרות אלה יתאפסו לאחר 10 שניות."</string>
     <item msgid="2139628951880142927">"הצג באחוזים בזמן טעינה (ברירת מחדל)"</item>
     <item msgid="3327323682209964956">"אל תציג את הסמל הזה"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"אחר"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"מחלק מסך מפוצל"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"הזז למטה"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"הזז למעלה"</string>
index d3a8b2c..f104703 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"長くします。"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"短くします。"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ライトがOFFです。"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ライトを使用できません。"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ライトがONです。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ライトをOFFにしました。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ライトをONにしました。"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"BluetoothをONにしますか?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"タブレットでキーボードに接続するには、最初にBluetoothをONにする必要があります。"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ONにする"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"通知をマナーモードで表示する"</string>
+    <string name="block" msgid="2734508760962682611">"通知をすべてブロックする"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"音声で知らせる"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"音声で知らせる / ブロックしない"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"重要度の設定をすべて表示"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"ブロック中"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"重要度: 最低"</string>
     <string name="low_importance" msgid="4109929986107147930">"重要度: 低"</string>
     <string name="default_importance" msgid="8192107689995742653">"重要度: 中"</string>
     <string name="high_importance" msgid="1527066195614050263">"重要度: 高"</string>
     <string name="max_importance" msgid="5089005872719563894">"重要度: 緊急"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"今後はこの通知を表示しない"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"通知リストの末尾にマナーモードで表示する"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"この通知をマナーモードで表示する"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"通知を音声で知らせる"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"画面に数秒間表示し、音声でも知らせる"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"通知リストの先頭に表示し、画面に数秒間表示し、音声でも知らせる"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"詳細設定"</string>
     <string name="notification_done" msgid="5279426047273930175">"完了"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"色と表示"</string>
     <item msgid="2139628951880142927">"変更時に割合を表示(デフォルト)"</item>
     <item msgid="3327323682209964956">"このアイコンを表示しない"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"その他"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"分割画面の分割線"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"下に移動"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上に移動"</string>
index d14a3c9..b365eb3 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"მეტი დრო."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"ნაკლები დრო."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ფანარი გამორთულია."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ფანარი მიუწვდომელია."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ფანარი ჩართულია."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ფანარი გამოირთო."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"ფანარი ჩაირთო."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"გსურთ Bluetooth-ის ჩართვა?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"კლავიატურის ტაბლეტთან დასაკავშირებლად, ჯერ უნდა ჩართოთ Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"ჩართვა"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"შეტყობინებების უხმოდ ჩვენება"</string>
+    <string name="block" msgid="2734508760962682611">"ყველა შეტყობინების დაბლოკვა"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"არ გაჩუმდეს"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"არ გაჩუმდეს ან დაიბლოკოს"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"მნიშვნელობის დონის სრული პარამეტრების ჩვენება"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"დაბლოკილი"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"მინიმალური"</string>
     <string name="low_importance" msgid="4109929986107147930">"დაბალი პრიორიტეტი"</string>
     <string name="default_importance" msgid="8192107689995742653">"ჩვეულებრივი პრიორიტეტი"</string>
     <string name="high_importance" msgid="1527066195614050263">"მაღალი პრიორიტეტი"</string>
     <string name="max_importance" msgid="5089005872719563894">"გადაუდებელი"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ამ შეტყობინებების ჩვენების შეწყვეტა"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"შეტყობინებების სიის ბოლოში, უხმოდ ჩვენება"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"ამ შეტყობინებების უხმოდ ჩვენება"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ამ შეტყობინებებისთვის ხმის გამოცემის დაშვება"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"შეტყობინებების პირდაპირ ეკრანზე ჩვენება და ხმის დაშვება"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"შეტყობინებების სიის თავში ჩვენება, პირდაპირ ეკრანზე გამოჩენა და ხმის დაშვება"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
     <string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"ფერი და იერსახე"</string>
     <item msgid="2139628951880142927">"პროცენტულობის დატენვისას ჩვენება (ნაგულისხმევი)"</item>
     <item msgid="3327323682209964956">"აღარ მაჩვენო ეს ხატულა"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"სხვა"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"გაყოფილი ეკრანის რეჟიმის გამყოფი"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"ქვემოთ გადატანა"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"ზემოთ გადატანა"</string>
index a2346b3..f8c54b6 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Көбірек уақыт."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Азырақ уақыт."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Қол шам өшірулі."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Жарқыл қол жетімді емес."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Қол шам қосулы."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Қол шам өшірілді."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Қол шам қосылды."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth функциясын қосу керек пе?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Пернетақтаны планшетке қосу үшін алдымен Bluetooth функциясын қосу керек."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Қосу"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Хабарландыруларды үнсіз көрсету"</string>
+    <string name="block" msgid="2734508760962682611">"Барлық хабарландыруларды бұғаттау"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Үнін өшірмеу"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Үнін өшірмеу немесе бұғаттамау"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Толық маңыздылық параметрлерін көрсету"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Бөгелген"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Ең аз маңыздылық"</string>
     <string name="low_importance" msgid="4109929986107147930">"Төмен маңыздылық"</string>
     <string name="default_importance" msgid="8192107689995742653">"Қалыпты маңыздылық"</string>
     <string name="high_importance" msgid="1527066195614050263">"Жоғары маңыздылық"</string>
     <string name="max_importance" msgid="5089005872719563894">"Шұғыл маңыздылық"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Осы хабарландыруларды ешқашан көрсетпеу"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Хабарландырулар тізімнің төменгі жағында үнсіз көрсету"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Осы хабарландыруларды үнсіз көрсету"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Осы хабарландыруға дыбыстар шығаруға рұқсат ету"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Экранда көрсету және дыбыс шығаруға рұқсат ету"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Хабарландырулар тізімінің жоғарғы жағында көрсету, экранда көрсету және дыбысқа рұқсат ету"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
     <string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Түс және сыртқы түрі"</string>
     <string name="use_dark_theme" msgid="2900938704964299312">"Android ОЖ үшін күңгірт тақырыпты пайдалану"</string>
     <string name="adjust_tint" msgid="3398569573231409878">"Реңкті реттеу"</string>
     <string name="adjust_brightness" msgid="980039329808178246">"Жарықтықты реттеу"</string>
-    <string name="night_mode_disclaimer" msgid="598914896926759578">"Күңгірт тақырып Android операциялық жүйесінің әдетте ашық тақырыпта көрсетілетін негізгі аумақтарына қолданылады, мысалы, \"Параметрлер\" тармағына."</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Күңгірт тақырып Android операциялық жүйесінің әдетте \"Параметрлер\" сияқты ашық тақырыпта көрсетілетін негізгі аумақтарына қолданылады."</string>
     <string name="color_apply" msgid="9212602012641034283">"Қолдану"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Параметрлерді растау"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Кейбір түс параметрлері бұл құрылғыны пайдалану мүмкін емес етуі мүмкін. Бұл түс параметрлерін растау үшін OK түймесін басыңыз, әйтпесе параметрлер 10 секундтан кейін ысырылады."</string>
     <item msgid="2139628951880142927">"Зарядтау кезінде пайызды көрсету (әдепкі)"</item>
     <item msgid="3327323682209964956">"Бұл белгішені көрсетпеу"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Басқа"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Бөлінген экран бөлгіші"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Төмен қарай жылжыту"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жоғары қарай жылжыту"</string>
index d5ac252..66a34f0 100644 (file)
@@ -73,7 +73,7 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Скриншот тартылды."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Тийип, скриншотту көрүңүз."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Скриншот кылынбай жатат."</string>
-    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"ЭÑ\81Ñ\82Ñ\83Ñ\82Ñ\83мда Ð±Ð¾Ñ\88 Ð¾Ñ\80Ñ\83н Ñ\87екÑ\82елүү болгондуктан скриншот сакталбай жатат."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"СакÑ\82агÑ\8bÑ\87Ñ\82а Ð±Ð¾Ñ\88 Ð¾Ñ\80Ñ\83н Ð°Ð· болгондуктан скриншот сакталбай жатат."</string>
     <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Скриншот тартууга колдонмо же ишканаңыз уруксат бербейт."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB менен файл өткөрүү мүмкүнчүлүктөрү"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Медиа ойноткуч катары кошуу (MTP)"</string>
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Көбүрөөк убакыт."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Азыраак убакыт."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Колчырак өчүк."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Кол чырак жок."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Колчырак күйүк."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Колчырак өчүрүлдү."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Колчырак күйгүзүлдү."</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> коопсуз режиминде өчүрүлдү."</string>
     <string name="recents_history_button_label" msgid="5153358867807604821">"Таржымал"</string>
     <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"Тазалоо"</string>
-    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бул колдонмо мульти-терезени колдоого албайт"</string>
-    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Колдонмо мульти-терезени колдоого албайт"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"Бул колдонмодо бир нече терезе режими колдоого алынбайт"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"Колдонмодо бир нече терезе режими колдоого алынбайт"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"Туурасынан бөлүү"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"Тигинен бөлүү"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"Ыңгайлаштырылган бөлүү"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth күйгүзүлсүнбү?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Баскычтобуңузду планшетиңизге туташтыруу үчүн, адегенде Bluetooth\'ту күйгүзүшүңүз керек."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Күйгүзүү"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Эскертмелер үнсүз көрсөтүлсүн"</string>
+    <string name="block" msgid="2734508760962682611">"Бардык эскертмелерди бөгөттөө"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Үнсүз кылынбасын"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Үнсүз кылынып же бөгөттөлбөсүн"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Маанилүүлүк жөндөөлөрү толук көрсөтүлсүн"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Бөгөттөлгөн"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Маанилүүлүгү эң төмөн"</string>
     <string name="low_importance" msgid="4109929986107147930">"Маанилүүлүгү төмөн"</string>
     <string name="default_importance" msgid="8192107689995742653">"Маанилүүлүгү орточо"</string>
     <string name="high_importance" msgid="1527066195614050263">"Маанилүүлүгү жогору"</string>
     <string name="max_importance" msgid="5089005872719563894">"Маанилүүлүгү шашылыш"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Бул эскертмелер эч качан көрсөтүлбөсүн"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Эскертмелер тизмесинин соңунда үнсүз көрсөтүлсүн"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Бул эскертмелер үнсүз көрсөтүлсүн"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Бул эскертмелер добуш чыгарышына уруксат берилсин"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Үн менен коштолуп, экранга чыгарылсын"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Эскертмелер тизмесинин эң башында көрсөтүлүп, үн менен коштолуп, экранга чыгарылсын"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
     <string name="notification_done" msgid="5279426047273930175">"Аткарылды"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Түсү жана көрүнүшү"</string>
     <string name="use_dark_theme" msgid="2900938704964299312">"Android OS үчүн караңгы тема колдонуу"</string>
     <string name="adjust_tint" msgid="3398569573231409878">"Кошумча түсүн тууралоо"</string>
     <string name="adjust_brightness" msgid="980039329808178246">"Жарыктыгын тууралоо"</string>
-    <string name="night_mode_disclaimer" msgid="598914896926759578">"Адатта жарык темада көрсөтүлгөн Android OS\'тин, Жөндөөлөр сыяктуу негизги аймактарына караңгы тема колдонулат."</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"Адатта жарык темада көрсөтүлүүчү Android тутумунун негизги элементтерине (Жөндөөлөр сыяктуу) колдонула турган караңгы тема."</string>
     <string name="color_apply" msgid="9212602012641034283">"Колдонуу"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Жөндөөлөрдү ырастоо"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Айрым түс жөндөөлөрү бул түзмөктү колдонулгус кылып коюшу мүмкүн. Бул түс жөндөөлөрүн ырастоо үчүн OK баскычын чыкылдатыңыз, болбосо бул жөндөөлөр 10 секунддан кийин баштапкы абалына келтирилет."</string>
     <item msgid="2139628951880142927">"Кубаттоо учурунда пайызы көрсөтүлсүн (демейки)"</item>
     <item msgid="3327323682209964956">"Бул сөлөкөт көрсөтүлбөсүн"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Башка"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Экранды бөлгүч"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Төмөн жылдыруу"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Жогору жылдыруу"</string>
index a33c76f..bb49c39 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daugiau laiko."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mažiau laiko."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Blykstė išjungta."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Blykstė nepasiekiama."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Blykstė įjungta."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Blykstė išjungta."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Blykstė įjungta."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Įjungti „Bluetooth“?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Kad galėtumėte prijungti klaviatūrą prie planšetinio kompiuterio, pirmiausia turite įjungti „Bluetooth“."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Įjungti"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Tyliai rodyti pranešimus"</string>
+    <string name="block" msgid="2734508760962682611">"Blokuoti visus pranešimus"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Netylėti"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Netylėti arba blokuoti"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Rodyti visos svarbos nustatymus"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Užblokuota"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Min. svarba"</string>
     <string name="low_importance" msgid="4109929986107147930">"Maža svarba"</string>
     <string name="default_importance" msgid="8192107689995742653">"Įprasta svarba"</string>
     <string name="high_importance" msgid="1527066195614050263">"Didelė svarba"</string>
     <string name="max_importance" msgid="5089005872719563894">"Skubi svarba"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Niekada nerodyti šių pranešimų"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Tyliai rodyti pranešimų sąrašo apačioje"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tyliai rodyti šiuos pranešimus"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Leisti šiems pranešimams skambėti"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Rodyti ekrane ir leisti skambėti"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Rodyti pranešimų sąrašo viršuje, rodyti ekrane ir leisti skambėti"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Daugiau nustatymų"</string>
     <string name="notification_done" msgid="5279426047273930175">"Atlikta"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Spalva ir išvaizda"</string>
     <item msgid="2139628951880142927">"Rodyti procentus kraunant (numatytasis nustatymas)"</item>
     <item msgid="3327323682209964956">"Nerodyti šios piktogramos"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Kita"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Skaidyto ekrano daliklis"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Perkelti žemyn"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Perkelti aukštyn"</string>
index 683e00a..574889e 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Vairāk laika."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mazāk laika."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Apgaismojums ir izslēgts."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Zibspuldze nav pieejama."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Apgaismojums ir ieslēgts."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Apgaismojums ir izslēgts."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Apgaismojums ir ieslēgts."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vai ieslēgt Bluetooth savienojumu?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Lai pievienotu tastatūru planšetdatoram, vispirms ir jāieslēdz Bluetooth savienojums."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ieslēgt"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Rādīt paziņojumus bez skaņas signāla"</string>
+    <string name="block" msgid="2734508760962682611">"Bloķēt visus paziņojumus"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Neizslēgt skaņu"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Neizslēgt skaņu vai nebloķēt"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Rādīt ļoti svarīgu paziņojumu iestatījumus"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloķēts"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Minimāls svarīguma līmenis"</string>
     <string name="low_importance" msgid="4109929986107147930">"Nav svarīgs"</string>
     <string name="default_importance" msgid="8192107689995742653">"Parasts"</string>
     <string name="high_importance" msgid="1527066195614050263">"Ļoti svarīgs"</string>
     <string name="max_importance" msgid="5089005872719563894">"Steidzams"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nekad nerādīt šos paziņojumus"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Rādīt paziņojumu saraksta apakšdaļā bez skaņas signāla"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Rādīt šos paziņojumus bez skaņas signāla"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Atļaut skaņas signālu šiem paziņojumiem"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Rādīt ekrānā un atļaut skaņas signālu"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Rādīt paziņojumu saraksta augšdaļā, rādīt ekrānā ar skaņas signālu"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Citi iestatījumi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gatavs"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Krāsas un izskats"</string>
     <item msgid="2139628951880142927">"Rādīt procentuālo vērtību uzlādes laikā (noklusējums)"</item>
     <item msgid="3327323682209964956">"Nerādīt šo ikonu"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Citi"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Ekrāna sadalītājs"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pārvietot uz leju"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Pārvietot uz augšu"</string>
index fea38a9..a69be1f 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Хугацаа нэмэх."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Хугацаа хасах."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Флаш гэрэл унтарсан."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Гэрэлтүүлэгч боломжгүй байна."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Флаш гэрэл ассан."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Флаш гэрлийг унтраасан."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Флаш гэрлийг асаасан."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth-г асаах уу?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Асаах"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Мэдэгдлийг чимээгүй харуулах"</string>
+    <string name="block" msgid="2734508760962682611">"Бүх мэдэгдлийг блоклох"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Дуугүй болгох хэрэггүй"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Дууг нь хаах эсвэл блоклох хэрэггүй"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Бүрэн ач холбогдлын тохиргоог харуулах"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Блоклосон"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Хамгийн бага ач холбогдол"</string>
     <string name="low_importance" msgid="4109929986107147930">"Бага ач холбогдолтой"</string>
     <string name="default_importance" msgid="8192107689995742653">"Энгийн ач холбогдолтой"</string>
     <string name="high_importance" msgid="1527066195614050263">"Өндөр ач холбогдолтой"</string>
     <string name="max_importance" msgid="5089005872719563894">"Яаралтай ач холбогдолтой"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Эдгээр мэдэгдлийг хэзээ ч харуулахгүй"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Мэдэгдлийг жагсаалтын доод хэсэгт дуугүй харуулах"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Эдгээр мэдэгдлийг дуугүй харуулах"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Эдгээр мэдэгдлийг дуу гаргахыг зөвшөөрөх"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Дэлгэцэд яаралтайгаар дуутай гаргах"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Мэдэгдлийг жагсаалтын эхэнд яаралтай дуутай харуулах"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Бусад тохиргоо"</string>
     <string name="notification_done" msgid="5279426047273930175">"Дууссан"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Өнгө, харагдах байдал"</string>
     <item msgid="2139628951880142927">"Цэнэглэх үед хувийг тогтмол харуулах (өгөгдмөл)"</item>
     <item msgid="3327323682209964956">"Энэ дүрс тэмдгийг бүү үзүүл"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Бусад"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"\"Дэлгэц хуваах\" хуваагч"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Доош зөөх"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Дээш зөөх"</string>
index acd9d4e..d99678c 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"अधिक वेळ."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"कमी वेळ."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"फ्लॅशलाइट बंद."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"फ्लॅशलाइट अनुपलब्ध आहे."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"फ्लॅशलाइट चालू."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"फ्लॅशलाइट बंद केला."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"फ्लॅशलाइट चालू केला."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"ब्लूटुथ सुरू करायचे?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"आपला कीबोर्ड आपल्या टॅब्लेटसह कनेक्ट करण्यासाठी, आपल्याला प्रथम ब्लूटुथ चालू करणे आवश्यक आहे."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"चालू करा"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"सूचना शांतपणे दर्शवा"</string>
+    <string name="block" msgid="2734508760962682611">"सर्व सूचना अवरोधित करा"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"शांत करू नका"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"शांत किंवा अवरोधित करू नका"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"पूर्ण महत्त्व सेटिंग्ज दर्शवा"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"अवरोधित केले"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"किमान महत्त्व"</string>
     <string name="low_importance" msgid="4109929986107147930">"कमी महत्त्व"</string>
     <string name="default_importance" msgid="8192107689995742653">"सामान्य महत्त्व"</string>
     <string name="high_importance" msgid="1527066195614050263">"सर्वाधिक महत्व"</string>
     <string name="max_importance" msgid="5089005872719563894">"त्वरित महत्त्व"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"या सूचना कधीही दर्शवू नका"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"सूचना सूचीच्या तळाशी शांतपणे दर्शवा"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"या सूचना शांतपणे दर्शवा"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"या सूचनांना ध्वनी चालू करण्याची अनुमती द्या"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"स्क्रीनवर पहा आणि ध्वनीस अनुमती द्या ध्वनीस अनुमती द्या"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"सूचनांच्या शीर्षस्थानी दर्शवा, स्क्रीनवर पहा आणि ध्वनीस अनुमती द्या"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
     <string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"रंग आणि स्वरूप"</string>
     <item msgid="2139628951880142927">"चार्ज करताना टक्केवारी दर्शवा (डीफॉल्ट)"</item>
     <item msgid="3327323682209964956">"हे चिन्ह दर्शवू नका"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"अन्य"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"विभाजित-स्क्रीन विभाजक"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"खाली हलवा"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"वर हलवा"</string>
index d204830..a716eef 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Lagi masa."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kurang masa."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lampu suluh dimatikan."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lampu suluh tidak tersedia."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lampu suluh dihidupkan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lampu suluh dimatikan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lampu suluh dihidupkan."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Hidupkan Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Untuk menyambungkan papan kekunci anda dengan tablet, anda perlu menghidupkan Bluetooth terlebih dahulu."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Hidupkan"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Tunjukkan pemberitahuan secara senyap"</string>
+    <string name="block" msgid="2734508760962682611">"Sekat semua pemberitahuan"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Jangan senyapkan"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Jangan senyapkan atau sekat"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tunjukkan tetapan kepentingan penuh"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Disekat"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Kurang penting"</string>
     <string name="low_importance" msgid="4109929986107147930">"Kepentingan rendah"</string>
     <string name="default_importance" msgid="8192107689995742653">"Kepentingan biasa"</string>
     <string name="high_importance" msgid="1527066195614050263">"Kepentingan tinggi"</string>
     <string name="max_importance" msgid="5089005872719563894">"Kepentingan segera"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Jangan sekali-kali tunjukkan pemberitahuan ini"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Tunjukkan pada bahagian bawah senarai pemberitahuan secara senyap"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tunjukkan pemberitahuan ini secara senyap"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Benarkan pemberitahuan ini berbunyi"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Intai pada skrin dan benarkan bunyi"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Tunjukkan pada bahagian atas senarai pemberitahuan, intai pada skrin dan benarkan bunyi"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
     <string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Warna dan penampilan"</string>
     <item msgid="2139628951880142927">"Tunjukkan peratusan semasa mengecas (lalai)"</item>
     <item msgid="3327323682209964956">"Jangan tunjukkan ikon ini"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
-    <string name="accessibility_divider" msgid="5903423481953635044">"Pembahagi skrin terpisah"</string>
+    <string name="other" msgid="4060683095962566764">"Lain-lain"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Pembahagi skrin pisah"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Alih ke bawah"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Alih ke atas"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Alih ke kiri"</string>
index c88eda2..503b91f 100644 (file)
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"<xliff:g id="APP">%s</xliff:g> ကို ဘေးကင်းလုံခြုံသည့်မုဒ်တွင် ပိတ်ထားပါသည်။"</string>
     <string name="recents_history_button_label" msgid="5153358867807604821">"မှတ်တမ်း"</string>
     <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"ရှင်းလင်းပါ"</string>
-    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"á\80¤á\80¡á\80\80á\80ºá\80\95á\80ºá\80\9eá\80\8aá\80º á\80\9dá\80\84á\80ºá\80¸á\80\92á\80­á\80¯á\80¸á\80\99á\80»á\80¬á\80¸á\80\85á\80½á\80¬á\80\90á\80½á\80\84á\80ºá\80\96á\80½á\80\84á\80·á\80ºá\80\9bá\80\94á\80º á\80\99á\80\95á\80¶á\80·á\80\95á\80­á\80¯á\80¸ထားပါ"</string>
-    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"á\80¡á\80\80á\80ºá\80\95á\80ºá\80\9eá\80\8aá\80º á\80\9dá\80\84á\80ºá\80¸á\80\92á\80­á\80¯á\80¸á\80\99á\80»á\80¬á\80¸á\80\85á\80½á\80¬á\80\90á\80½á\80\84á\80ºá\80\96á\80½á\80\84á\80·á\80ºá\80\9bá\80\94á\80º á\80\99á\80\95á\80¶á\80·á\80\95á\80­á\80¯á\80¸ထားပါ"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"á\80¤á\80¡á\80\80á\80ºá\80\95á\80ºá\80\9eá\80\8aá\80º á\80\9dá\80\84á\80ºá\80¸á\80\92á\80­á\80¯á\80¸á\80\99á\80»á\80¬á\80¸á\80\85á\80½á\80¬á\80\96á\80½á\80\84á\80·á\80ºá\80\81á\80¼á\80\84á\80ºá\80¸á\80\80á\80­á\80¯ á\80\95á\80¶á\80·á\80\95á\80­á\80¯á\80¸á\80\99ထားပါ"</string>
+    <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"á\80¡á\80\80á\80ºá\80\95á\80ºá\80\9eá\80\8aá\80º á\80\9dá\80\84á\80ºá\80¸á\80\92á\80­á\80¯á\80¸á\80\99á\80»á\80¬á\80¸á\80\85á\80½á\80¬á\80\96á\80½á\80\84á\80·á\80ºá\80\81á\80¼á\80\84á\80ºá\80¸á\80\80á\80­á\80¯ á\80\95á\80¶á\80·á\80\95á\80­á\80¯á\80¸á\80\99ထားပါ"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"ရေပြင်ညီ ပိုင်းမည်"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"ဒေါင်လိုက်ပိုင်းမည်"</string>
     <string name="recents_multistack_add_stack_dialog_split_custom" msgid="4177837597513701943">"စိတ်ကြိုက် ပိုင်းမည်"</string>
     <item msgid="3327323682209964956">"ဤသင်္ကေတပုံကို မပြပါနှင့်"</item>
   </string-array>
     <string name="other" msgid="4060683095962566764">"အခြား"</string>
-    <string name="accessibility_divider" msgid="5903423481953635044">"မျက်နှာပြင်ခွဲခြမ်းခြင်း ပိုင်းခြားပေးသည့်စနစ်"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"မျက်နှာပြင်ခွဲခြမ်း ပိုင်းခြားပေးသည့်စနစ်"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"အောက်သို့ရွှေ့ပါ"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"အပေါ်သို့ရွှေ့ပါ"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"ဘယ်ဘက်သို့ရွှေ့ပါ"</string>
index ac8cc8d..b3de239 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mer tid."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mindre tid."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lommelykten er av."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lommelykt er ikke tilgjengelig."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lommelykten er på."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lommelykten er slått av."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lommelykten er slått på."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vil du slå på Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"For å koble tastaturet til nettbrettet ditt må du først slå på Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Slå på"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Vis varsler uten lyd"</string>
+    <string name="block" msgid="2734508760962682611">"Blokkér alle varsler"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ikke slå av lyden"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ikke slå av lyden eller blokkér anrop"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Vis alle viktighetsinnstillingene"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blokkert"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Laveste prioritet"</string>
     <string name="low_importance" msgid="4109929986107147930">"Lav viktighet"</string>
     <string name="default_importance" msgid="8192107689995742653">"Vanlig viktighet"</string>
     <string name="high_importance" msgid="1527066195614050263">"Høy viktighet"</string>
     <string name="max_importance" msgid="5089005872719563894">"Svært høy viktighet"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Aldri vis disse varslene"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Vis nederst på varsellisten uten lyd"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Vis disse varslene uten lyd"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Tillat at disse varslene vises med lyd"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Vis fort på skjermen og tillat lyd"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Vis øverst på varsellisten, vis fort på skjermen og tillat lyd"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Flere innstillinger"</string>
     <string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Farge og utseende"</string>
     <item msgid="2139628951880142927">"Vis prosentandel under lading (standard)"</item>
     <item msgid="3327323682209964956">"Ikke vis dette ikonet"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Annet"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Skilleelement for delt skjerm"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flytt ned"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flytt opp"</string>
index c9821ee..974685c 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Więcej czasu."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mniej czasu."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Latarka wyłączona."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Latarka niedostępna."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Latarka włączona."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Latarka została wyłączona."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Latarka została włączona."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Włączyć Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Aby połączyć klawiaturę z tabletem, musisz najpierw włączyć Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Włącz"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Pokazuj powiadomienia bez sygnału dźwiękowego"</string>
+    <string name="block" msgid="2734508760962682611">"Blokuj wszystkie powiadomienia"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nie ignoruj"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nie ignoruj ani nie blokuj"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Pokaż pełne ustawienia ważności"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Zablokowane"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Najmniejsza ważność"</string>
     <string name="low_importance" msgid="4109929986107147930">"Mało ważne"</string>
     <string name="default_importance" msgid="8192107689995742653">"Ważne"</string>
     <string name="high_importance" msgid="1527066195614050263">"Bardzo ważne"</string>
     <string name="max_importance" msgid="5089005872719563894">"Pilne"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nigdy nie pokazuj tych powiadomień"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Pokazuj na końcu listy powiadomień bez sygnału dźwiękowego"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Pokazuj te powiadomienia bez sygnału dźwiękowego"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Zezwól na sygnalizowanie tych powiadomień dźwiękiem"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Wyświetlaj na ekranie i sygnalizuj dźwiękiem"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Pokazuj na początku listy powiadomień, wyświetlaj na ekranie i sygnalizuj dźwiękiem"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
     <string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Kolor i wygląd"</string>
     <item msgid="2139628951880142927">"Pokazuj procent podczas ładowania (domyślnie)"</item>
     <item msgid="3327323682209964956">"Nie pokazuj tej ikony"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Inne"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Linia dzielenia ekranu"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Przesuń w dół"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Przesuń w górę"</string>
index a15a789..3797adc 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desativada."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna indisponível."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ativada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"A lanterna foi desativada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"A lanterna foi ativada."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificações de forma silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas as notificações"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Não silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Não silenciar ou bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar todas as configurações de importância"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importância mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importância elevada"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importância urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar essas notificações"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar essas notificações de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que essas notificações emitam sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar parcialmente na tela e permitir som"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar parcialmente na tela e permitir sons"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aparência"</string>
     <string name="use_dark_theme" msgid="2900938704964299312">"Usar o tema escuro para o SO Android"</string>
     <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tonalidade"</string>
     <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brilho"</string>
-    <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como asconfigurações."</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como as configurações."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirmar configurações"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Algumas configurações de cor podem tornar o dispositivo inutilizável. Clique em \"OK\" para confirmar essas configurações de cor; caso contrário, essas configurações serão redefinidas após 10 segundos."</string>
     <item msgid="2139628951880142927">"Mostrar porcentagem durante o carregamento (padrão)"</item>
     <item msgid="3327323682209964956">"Não mostrar este ícone"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Outros"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de tela"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
index 85d4c79..7ee2554 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desligada."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna indisponível."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ligada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lanterna desligada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lanterna ligada."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Pretende ativar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para ligar o teclado ao tablet, tem de ativar primeiro o Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificações sem som"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas as notificações"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Não silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Não silenciar nem bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar definições de importância completas"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueado"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importância mín."</string>
     <string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importância alta"</string>
     <string name="max_importance" msgid="5089005872719563894">"Urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar estas notificações"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar na parte inferior da lista de notificações sem som"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar estas notificações sem som"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que estas notificações emitam sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar no ecrã e permitir som"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar no ecrã e permitir som"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais definições"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aspeto"</string>
     <item msgid="2139628951880142927">"Mostrar a percentagem durante o carregamento (predefinição)"</item>
     <item msgid="3327323682209964956">"Não mostrar este ícone"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Outro"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Divisor do ecrã dividido"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
index a15a789..3797adc 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mais tempo."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Menos tempo."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna desativada."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna indisponível."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna ativada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"A lanterna foi desativada."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"A lanterna foi ativada."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Ativar o Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Para conectar o teclado ao tablet, é preciso primeiro ativar o Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Ativar"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Mostrar notificações de forma silenciosa"</string>
+    <string name="block" msgid="2734508760962682611">"Bloquear todas as notificações"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Não silenciar"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Não silenciar ou bloquear"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Mostrar todas as configurações de importância"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloqueadas"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importância mínima"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importância baixa"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importância normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importância elevada"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importância urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Nunca mostrar essas notificações"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Mostrar na parte inferior da lista de notificações de forma silenciosa"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Mostrar essas notificações de forma silenciosa"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permitir que essas notificações emitam sons"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Mostrar parcialmente na tela e permitir som"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Mostrar na parte superior da lista de notificações, mostrar parcialmente na tela e permitir sons"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
     <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Cor e aparência"</string>
     <string name="use_dark_theme" msgid="2900938704964299312">"Usar o tema escuro para o SO Android"</string>
     <string name="adjust_tint" msgid="3398569573231409878">"Ajustar tonalidade"</string>
     <string name="adjust_brightness" msgid="980039329808178246">"Ajustar brilho"</string>
-    <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como asconfigurações."</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"O tema escuro é aplicado a áreas centrais do sistema operacional Android que normalmente são exibidas em um tema claro, como as configurações."</string>
     <string name="color_apply" msgid="9212602012641034283">"Aplicar"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Confirmar configurações"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Algumas configurações de cor podem tornar o dispositivo inutilizável. Clique em \"OK\" para confirmar essas configurações de cor; caso contrário, essas configurações serão redefinidas após 10 segundos."</string>
     <item msgid="2139628951880142927">"Mostrar porcentagem durante o carregamento (padrão)"</item>
     <item msgid="3327323682209964956">"Não mostrar este ícone"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Outros"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Divisor de tela"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mover para baixo"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mover para cima"</string>
index fc1ed2f..c2bec08 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Mai mult timp."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mai puțin timp."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Lanterna este dezactivată."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Lanterna nu este disponibilă."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Lanterna este activată."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Lanterna este dezactivată."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Lanterna este activată."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Activați Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Pentru a conecta tastatura la tabletă, mai întâi trebuie să activați Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Activați"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Notificările se afișează fără a se emite un sunet"</string>
+    <string name="block" msgid="2734508760962682611">"Blocați toate notificările"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nu dezactivați sunetul"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nu dezactivați sunetul și nu blocați"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Afișați toate setările privind importanța"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blocate"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Importanță minimă"</string>
     <string name="low_importance" msgid="4109929986107147930">"Importanță redusă"</string>
     <string name="default_importance" msgid="8192107689995742653">"Importanță normală"</string>
     <string name="high_importance" msgid="1527066195614050263">"Importanță ridicată"</string>
     <string name="max_importance" msgid="5089005872719563894">"Importanță: urgente"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Aceste notificări nu se afișează niciodată"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Se afișează în partea de jos a listei cu notificări fără a se emite un sunet"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Aceste notificări se afișează fără a se emite un sunet"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Permiteți acestor notificări să emită sunete"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Se afișează pentru o scurtă durată pe ecran și se permite un sunet"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Apar în partea de sus a listei cu notificări, se afișează pentru scurt timp pe ecran și se permite un sunet"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Mai multe setări"</string>
     <string name="notification_done" msgid="5279426047273930175">"Terminat"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Culoare și aspect"</string>
     <item msgid="2139628951880142927">"Afișează procentajul când se încarcă (prestabilit)"</item>
     <item msgid="3327323682209964956">"Nu afișa această pictogramă"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Altele"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Separator pentru ecranul împărțit"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Mutați în jos"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Mutați în sus"</string>
index 5340d95..8ece7fa 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Увеличить время."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Уменьшить время."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Фонарик отключен."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Фонарик недоступен."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Фонарик включен."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Фонарик отключен."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Фонарик включен."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Подключение по Bluetooth"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Чтобы подключить клавиатуру к планшету, включите Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Включить"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Показывать без звука"</string>
+    <string name="block" msgid="2734508760962682611">"Блокировать все уведомления"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Показывать со звуком"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Не блокировать, показывать со звуком"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Показывать все настройки важности"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Блокировка"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Наименьшая важность"</string>
     <string name="low_importance" msgid="4109929986107147930">"Низкая важность"</string>
     <string name="default_importance" msgid="8192107689995742653">"Средняя важность"</string>
     <string name="high_importance" msgid="1527066195614050263">"Высокая важность"</string>
     <string name="max_importance" msgid="5089005872719563894">"Крайняя важность"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Не показывать эти уведомления."</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Показывать без звука в конце списка уведомлений"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Показывать без звука"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Показывать со звуком"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Показывать со звуком поверх всех окон"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Показывать со звуком в начале списка уведомлений и поверх всех окон"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Другие настройки"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Цвета и стиль"</string>
     <item msgid="2139628951880142927">"Показывать процент во время зарядки (по умолчанию)"</item>
     <item msgid="3327323682209964956">"Не показывать этот значок"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Другое"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Разделитель экрана"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Опустить"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Поднять"</string>
index 446590f..40daf19 100644 (file)
@@ -75,7 +75,7 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"Snímka obrazovky bola zaznamenaná."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"Snímku obrazovky zobrazíte dotykom."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"Snímku obrazovky sa nepodarilo zachytiť."</string>
-    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snímku obrazovky nie je možné vytvoriť z dôvodu nedostatku miesta na úložisku."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"Snímku obrazovky nie je možné vytvoriť z dôvodu nedostatku miesta v úložisku."</string>
     <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"Vytváranie snímok obrazovky je zakázané aplikáciou alebo vašou organizáciou."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"Možnosti prenosu súborov USB"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"Pripojiť ako prehrávač médií (MTP)"</string>
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Dlhší čas"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kratší čas"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Svietidlo je vypnuté."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Svietidlo nie je k dispozícii."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Svietidlo je zapnuté."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Svietidlo je vypnuté."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Svietidlo je zapnuté."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Zapnúť Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ak chcete klávesnicu pripojiť k tabletu, najprv musíte zapnúť Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Zapnúť"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Zobrazovať upozornenia bez zvukového signálu"</string>
+    <string name="block" msgid="2734508760962682611">"Blokovať všetky upozornenia"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Nestíšiť"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Nestíšiť ani neblokovať"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Zobraziť nastavenia vysokej dôležitosti"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Zablokované"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Minimálna dôležitosť"</string>
     <string name="low_importance" msgid="4109929986107147930">"Nízka dôležitosť"</string>
     <string name="default_importance" msgid="8192107689995742653">"Normálna dôležitosť"</string>
     <string name="high_importance" msgid="1527066195614050263">"Vysoká dôležitosť"</string>
     <string name="max_importance" msgid="5089005872719563894">"Neodkladná dôležitosť"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Tieto upozornenia nikdy nezobrazovať"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Zobrazovať v dolnej časti zoznamu upozornení bez zvukového signálu"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tieto upozornenia zobrazovať bez zvukového signálu"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Umožniť týmto upozorneniam vydávať zvukové signály"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Zobrazovať cez obrazovku a povoliť zvukový signál"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Zobrazovať v hornej časti zoznamu upozornení, zobrazovať cez obrazovku a povoliť zvukový signál"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
     <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Farba a vzhľad"</string>
     <string name="use_dark_theme" msgid="2900938704964299312">"Použiť tmavý motív pre systém Android OS"</string>
     <string name="adjust_tint" msgid="3398569573231409878">"Upraviť tónovanie"</string>
     <string name="adjust_brightness" msgid="980039329808178246">"Upraviť jas"</string>
-    <string name="night_mode_disclaimer" msgid="598914896926759578">"V hlavných oblastiach systému Android OS (ako sú Nastavenia), ktoré sú obyčajne zobrazené v svetlom motíve, je použitý tmavý motív."</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"V hlavných oblastiach systému Android OS (ako sú Nastavenia), ktoré sú obyčajne zobrazené vsvetlom motíve, je použitý tmavý motív."</string>
     <string name="color_apply" msgid="9212602012641034283">"Použiť"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Potvrdenie nastavení"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Niektoré nastavenia farieb môžu toto zariadenie znefunkčniť. Tieto nastavenia farieb potvrdíte kliknutím na tlačidlo OK, ináč sa tieto nastavenia o 10 sekúnd obnovia."</string>
     <item msgid="2139628951880142927">"Zobrazovať percentá počas nabíjania (predvolené)"</item>
     <item msgid="3327323682209964956">"Nezobrazovať túto ikonu"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Ďalšie"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Rozdeľovač obrazovky"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Posunúť nadol"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Posunúť nahor"</string>
index 327e553..991e9e2 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Више времена."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Мање времена."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Батеријска лампа је искључена."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Лампа није доступна."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Батеријска лампа је укључена."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Батеријска лампа је искључена."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Батеријска лампа је укључена."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Желите ли да укључите Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Да бисте повезали тастатуру са таблетом, прво морате да укључите Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Укључи"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Приказуј обавештења без звука"</string>
+    <string name="block" msgid="2734508760962682611">"Блокирај сва обавештења"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Не искључуј звук"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Не искључују звук нити блокирај"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Прикажи комплетна подешавања важности"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Блокирана"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Веома мала важност"</string>
     <string name="low_importance" msgid="4109929986107147930">"Мала важност"</string>
     <string name="default_importance" msgid="8192107689995742653">"Уобичајена важност"</string>
     <string name="high_importance" msgid="1527066195614050263">"Велика важност"</string>
     <string name="max_importance" msgid="5089005872719563894">"Важност: хитно"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ова обавештења се никада не приказују"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Приказују се у дну листе обавештења без звука"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Ова обавештења се приказују без звука"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Дозволите да ова обавештења емитују звук"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Накратко се приказују на екрану и емитују звук"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Приказују се у врху листе обавештења, накратко се приказују на екрану и емитују звук"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Боја и изглед"</string>
     <item msgid="2139628951880142927">"Прикажи проценат током пуњења (подразумевано)"</item>
     <item msgid="3327323682209964956">"Не приказуј ову икону"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Друго"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Разделник подељеног екрана"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Помери надоле"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Помери нагоре"</string>
index a23aba9..d35fad5 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Längre tid."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kortare tid."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ficklampa av."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Ficklampan är inte tillgänglig."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ficklampa på."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ficklampan har inaktiverats."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ficklampan har aktiverats."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vill du aktivera Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Om du vill ansluta tangentbordet till surfplattan måste du först aktivera Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aktivera"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Visa aviseringar utan ljud"</string>
+    <string name="block" msgid="2734508760962682611">"Blockera alla aviseringar"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Stäng inte av ljudet"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Stäng inte av ljudet och blockera inte"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Visa alla relevansinställningarna"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Blockerad"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Oviktig avisering"</string>
     <string name="low_importance" msgid="4109929986107147930">"Oviktig avisering"</string>
     <string name="default_importance" msgid="8192107689995742653">"Vanlig avisering"</string>
     <string name="high_importance" msgid="1527066195614050263">"Viktig avisering"</string>
     <string name="max_importance" msgid="5089005872719563894">"Brådskande avisering"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Visa aldrig de här aviseringarna"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Visa längst ned i listan, utan ljud"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Visa aviseringarna utan ljud"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Tillåt ljud för de här aviseringarna"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Visa med snabbtitt på skärmen och tillåt ljud"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Visa högst upp i aviseringslistan och med snabbtitt på skärmen samt tillåt ljud"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Klar"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Färg och utseende"</string>
     <item msgid="2139628951880142927">"Visa procent under laddning (standard)"</item>
     <item msgid="3327323682209964956">"Visa inte den här ikonen"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Annat"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Avdelare för delad skärm"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Flytta nedåt"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Flytta uppåt"</string>
index 02a193a..66a1496 100644 (file)
@@ -73,8 +73,8 @@
     <string name="screenshot_saved_title" msgid="6461865960961414961">"ஸ்கிரீன் ஷாட் எடுக்கப்பட்டது."</string>
     <string name="screenshot_saved_text" msgid="1152839647677558815">"உங்கள் ஸ்க்ரீன் ஷாட்டைப் பார்க்க தொடவும்."</string>
     <string name="screenshot_failed_title" msgid="705781116746922771">"ஸ்க்ரீன் ஷாட்டை எடுக்க முடியவில்லை."</string>
-    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"போதுமான சேமிப்பிடம் இல்லாததால் ஸ்கிரீன் ஷாட்டைச் சேமிக்க முடியவில்லை."</string>
-    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"பயன்பாடு அல்லது உங்கள் நிறுவனம் ஸ்கிரீன் ஷாட்டுகளை எடுக்க அனுமதிக்கவில்லை."</string>
+    <string name="screenshot_failed_to_save_text" msgid="2592658083866306296">"போதுமான சேமிப்பிடம் இல்லாததால் ஸ்கிரீன்ஷாட்டைச் சேமிக்க முடியவில்லை."</string>
+    <string name="screenshot_failed_to_capture_text" msgid="7602391003979898374">"பயன்பாடு அல்லது உங்கள் நிறுவனம் ஸ்கிரீன்ஷாட்டுகளை எடுக்க அனுமதிக்கவில்லை."</string>
     <string name="usb_preference_title" msgid="6551050377388882787">"USB கோப்பு இடமாற்ற விருப்பங்கள்"</string>
     <string name="use_mtp_button_title" msgid="4333504413563023626">"(MTP) மீடியா பிளேயராக ஏற்று"</string>
     <string name="use_ptp_button_title" msgid="7517127540301625751">"(PTP) கேமராவாக ஏற்று"</string>
     <string name="recents_launch_disabled_message" msgid="1624523193008871793">"பாதுகாப்புப் பயன்முறையில் <xliff:g id="APP">%s</xliff:g> முடக்கப்பட்டது."</string>
     <string name="recents_history_button_label" msgid="5153358867807604821">"வரலாறு"</string>
     <string name="recents_history_clear_all_button_label" msgid="5905258334958006953">"அழி"</string>
-    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"பயனà¯\8dபாà®\9fà¯\81 à®ªà®² à®\9aாளர à®\85à®®à¯\8dà®\9aதà¯\8dதà¯\88 à®\86தரிà®\95à¯\8dà®\95ாதà¯\81"</string>
+    <string name="recents_drag_non_dockable_task_message" msgid="2935843902795166158">"à®\87நà¯\8dதபà¯\8d à®ªà®¯à®©à¯\8dபாà®\9fà¯\81 à®ªà®² à®\9aாளர à®\85à®®à¯\8dà®\9aதà¯\8dதà¯\88 à®\86தரிà®\95à¯\8dà®\95விலà¯\8dலà¯\88"</string>
     <string name="recents_launch_non_dockable_task_label" msgid="7862379814938391888">"பயன்பாடு பல சாளர அம்சத்தை ஆதரிக்காது"</string>
     <string name="recents_multistack_add_stack_dialog_split_horizontal" msgid="8848514474543427332">"கிடைமட்டமாகப் பிரி"</string>
     <string name="recents_multistack_add_stack_dialog_split_vertical" msgid="9075292233696180813">"செங்குத்தாகப் பிரி"</string>
index 33a07ec..9b1ea74 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"เวลามากขึ้น"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"เวลาน้อยลง"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"ไฟฉายปิดอยู่"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"ไฟฉายไม่พร้อมใช้งาน"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"ไฟฉายเปิดอยู่"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"ปิดไฟฉายแล้ว"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"เปิดไฟฉายแล้ว"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"เปิดบลูทูธไหม"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"หากต้องการเชื่อมต่อแป้นพิมพ์กับแท็บเล็ต คุณต้องเปิดบลูทูธก่อน"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"เปิด"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"แสดงการแจ้งเตือนโดยไม่ส่งเสียง"</string>
+    <string name="block" msgid="2734508760962682611">"บล็อกการแจ้งเตือนทั้งหมด"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"ไม่ปิดเสียง"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"ไม่ปิดเสียงหรือบล็อก"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"แสดงการตั้งค่าความสำคัญแบบเต็ม"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"บล็อกแล้ว"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"ความสำคัญน้อย"</string>
     <string name="low_importance" msgid="4109929986107147930">"ความสำคัญต่ำ"</string>
     <string name="default_importance" msgid="8192107689995742653">"ความสำคัญปกติ"</string>
     <string name="high_importance" msgid="1527066195614050263">"ความสำคัญสูง"</string>
     <string name="max_importance" msgid="5089005872719563894">"ความสำคัญเร่งด่วน"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"ไม่ต้องแสดงการแจ้งเตือนเหล่านี้"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"แสดงที่ด้านล่างของรายการแจ้งเตือนโดยไม่ส่งเสียง"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"แสดงการแจ้งเตือนเหล่านี้โดยไม่ส่งเสียง"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ให้การแจ้งเตือนเหล่านี้ส่งเสียงได้"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"แสดงบนหน้าจอและให้ส่งเสียงได้"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"แสดงที่ด้านบนของรายการการแจ้งเตือน แสดงบนหน้าจอและให้ส่งเสียงได้"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"การตั้งค่าเพิ่มเติม"</string>
     <string name="notification_done" msgid="5279426047273930175">"เสร็จสิ้น"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"สีและลักษณะที่ปรากฏ"</string>
     <item msgid="2139628951880142927">"แสดงเปอร์เซ็นต์เมื่อชาร์จ (ค่าเริ่มต้น)"</item>
     <item msgid="3327323682209964956">"อย่าแสดงไอคอนนี้"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"อื่นๆ"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"เส้นแบ่งหน้าจอ"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"เลื่อนลง"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"เลื่อนขึ้น"</string>
index 99fa7a2..d131c84 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Higit pang oras."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Mas kaunting oras."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Naka-off ang flashlight."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Hindi available ang flashlight."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Naka-on ang flashlight."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Na-off ang flashlight."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Na-on ang flashlight."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"I-on ang Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Upang ikonekta ang iyong keyboard sa iyong tablet, kailangan mo munang i-on ang Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"I-on"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Tahimik na ipakita ang mga notification"</string>
+    <string name="block" msgid="2734508760962682611">"I-block ang lahat ng notification"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Huwag i-silent"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Huwag i-silent o i-block"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Ipakita ang kumpletong mga setting ng kahalagahan"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Na-block"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Hindi masyadong mahalaga"</string>
     <string name="low_importance" msgid="4109929986107147930">"Hindi masyadong mahalaga"</string>
     <string name="default_importance" msgid="8192107689995742653">"Mahalaga"</string>
     <string name="high_importance" msgid="1527066195614050263">"Napakahalaga"</string>
     <string name="max_importance" msgid="5089005872719563894">"Mahalagang-mahalaga"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Huwag kailanman ipakita ang mga notification na ito"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Tahimik na ipakita sa ibaba ng listahan ng notification"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Tahimik na ipakita ang mga notification na ito"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Payagan ang mga notification na ito na tumunog"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Palitawin sa screen at payagang tumunog"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Ipakita sa itaas ng listahan ng mga notification, palitawin sa screen at payagang tumunog"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Higit pang mga setting"</string>
     <string name="notification_done" msgid="5279426047273930175">"Tapos Na"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Kulay at hitsura"</string>
     <item msgid="2139628951880142927">"Ipakita ang porsyento kapag nagcha-charge (default)"</item>
     <item msgid="3327323682209964956">"Huwag ipakita ang icon na ito"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Iba pa"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Divider ng split-screen"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Ilipat pababa"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Ilipat pataas"</string>
index 050f1f7..fd9e14c 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Daha uzun süre."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Daha kısa süre."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"El feneri kapalı."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"El feneri kullanılamıyor."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"El feneri açık."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"El feneri kapatıldı."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"El feneri açıldı."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth açılsın mı?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klavyenizi tabletinize bağlamak için önce Bluetooth\'u açmanız gerekir."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Aç"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Bildirimleri sessizce göster"</string>
+    <string name="block" msgid="2734508760962682611">"Tüm bildirimleri engelle"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Sessiz moda alma"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Sessiz moda alma veya engelleme"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Tüm önem ayarlarını göster"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Engellendi"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Önemi en düşük"</string>
     <string name="low_importance" msgid="4109929986107147930">"Önem düzeyi düşük"</string>
     <string name="default_importance" msgid="8192107689995742653">"Önem düzeyi normal"</string>
     <string name="high_importance" msgid="1527066195614050263">"Önem düzeyi yüksek"</string>
     <string name="max_importance" msgid="5089005872719563894">"Önem düzeyi acil"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirimleri hiçbir zaman gösterme"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Bildirim listesinin en altında sessizce göster"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Bu bildirimleri sessizce göster"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Bu bildirimlerin ses çıkarmasına izin ver"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Ekrana getir ve sesli bildirime izin ver"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Bildirim listesinin üstünde göster, ekrana getir ve sesli bildirime izin ver"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Renk ve görünüm"</string>
     <item msgid="2139628951880142927">"Şarj olurken yüzdeyi göster (varsayılan)"</item>
     <item msgid="3327323682209964956">"Bu simgeyi gösterme"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Diğer"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Bölünmüş ekran ayırıcı"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Aşağı taşı"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Yukarı taşı"</string>
index 485e2b2..e5bf06d 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Більше часу."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Менше часу."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Ліхтарик вимк."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Ліхтарик недоступний."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Ліхтарик увімк."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Ліхтарик вимкнено."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Ліхтарик увімкнено."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Увімкнути Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Щоб під’єднати клавіатуру до планшета, спершу потрібно ввімкнути Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Увімкнути"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Показувати сповіщення без звукового сигналу"</string>
+    <string name="block" msgid="2734508760962682611">"Блокувати всі сповіщення"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Не вимикати звуковий сигнал"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Не вимикати звуковий сигнал і не блокувати"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Показати налаштування пріоритетності"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Заблоковано"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Низький пріоритет"</string>
     <string name="low_importance" msgid="4109929986107147930">"Низький пріоритет"</string>
     <string name="default_importance" msgid="8192107689995742653">"Стандартний пріоритет"</string>
     <string name="high_importance" msgid="1527066195614050263">"Високий пріоритет"</string>
     <string name="max_importance" msgid="5089005872719563894">"Терміново"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ніколи не показувати ці сповіщення"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Показувати сповіщення внизу списку без звукового сигналу"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Показувати ці сповіщення без звукового сигналу"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Увімкнути звуковий сигнал для цих сповіщень"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Показувати сповіщення на екрані зі звуковим сигналом"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Показувати сповіщення вгорі списку, на екрані та зі звуковим сигналом"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Більше налаштувань"</string>
     <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Колір і вигляд"</string>
     <item msgid="2139628951880142927">"Показувати відсотки під час заряджання (за умовчанням)"</item>
     <item msgid="3327323682209964956">"Не показувати цей значок"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Інше"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Розділювач екрана"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Перемістити вниз"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Перемістити вгору"</string>
index 20a2a6f..7a10732 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"مزید وقت۔"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"کم وقت۔"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"فلیش لائٹ آف ہے۔"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"فلیش لائٹ دستیاب نہیں ہے"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"فلیش لائٹ آن ہے۔"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"فلیش لائٹ کو آف کر دیا گیا۔"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"فلیش لائٹ کو آن کر دیا گیا۔"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"بلوٹوتھ آن کریں؟"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"اپنے کی بورڈ کو اپنے ٹیبلٹ کے ساتھ منسلک کرنے کیلئے پہلے آپ کو اپنا بلو ٹوتھ آن کرنا ہو گا۔"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"آن کریں"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"اطلاعات خاموشی سے دکھائیں"</string>
+    <string name="block" msgid="2734508760962682611">"تمام اطلاعات کو مسدود کریں"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"خاموش نہ کریں"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"خاموش یا مسدود نہ کریں"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"اہمیت کی پوری ترتیبات دکھائیں"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"مسدود کردہ"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"کم سے کم اہمیت"</string>
     <string name="low_importance" msgid="4109929986107147930">"کم اہمیت"</string>
     <string name="default_importance" msgid="8192107689995742653">"عمومی اہمیت"</string>
     <string name="high_importance" msgid="1527066195614050263">"زیادہ اہمیت"</string>
     <string name="max_importance" msgid="5089005872719563894">"فوری اہمیت"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"یہ اطلاعات کبھی مت دکھائیں"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"اطلاعات کی فہرست کے سب سے نیچے خاموشی سے دکھائیں"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"خاموشی سے یہ اطلاعات دکھائیں"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"ان اطلاعات کو آواز نکالنے کی اجازت دیں"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"اسکرین پر دکھائیں اور آواز کی اجازت دیں"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"اطلاعات کی فہرست پر سب سے اوپر دکھائیں، اسکرین پر دکھائیں اور آواز کی اجازت دیں"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
     <string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"رنگ اور ظہور"</string>
     <item msgid="2139628951880142927">"چارج ہوتے وقت فیصد دکھائیں (ڈیفالٹ)"</item>
     <item msgid="3327323682209964956">"یہ آئیکن نہ دکھائیں"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"دیگر"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"سپلٹ اسکرین تقسیم کار"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"نیچے منتقل کریں"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"اوپر منتقل کریں"</string>
index 3fc7aad..79729dc 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Ko‘proq vaqt."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Kamroq vaqt."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"Fonar o‘chirilgan."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"Bu yerda fonar yo‘q."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"Fonar yoqilgan."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"Fonar o‘chirildi."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"Fonar yoqildi."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Bluetooth yoqilsinmi?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Klaviaturani planshetingizga ulash uchun Bluetooth xizmatini yoqishingiz kerak."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Yoqish"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Bildirishnomalar ovozsiz ko‘rsatilsin"</string>
+    <string name="block" msgid="2734508760962682611">"Barcha bildirishnomalar bloklansin"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ovozi o‘chirilmasin"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ovozi o‘chirilmasin yoki bloklanmasin"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Barcha muhimlik sozlamalarini ko‘rsatish"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Bloklangan"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Kamroq muhim"</string>
     <string name="low_importance" msgid="4109929986107147930">"Kamroq muhim"</string>
     <string name="default_importance" msgid="8192107689995742653">"O‘rtacha muhim"</string>
     <string name="high_importance" msgid="1527066195614050263">"Juda muhim"</string>
     <string name="max_importance" msgid="5089005872719563894">"Favqulodda muhim"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Bu bildirishnomalar boshqa ko‘rsatilmasin"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Bildirishnomalar ro‘yxatining oxirida ovozsiz ko‘rsatilsin"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Bu bildirishnomalar ovozsiz ko‘rsatilsin"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Bu bildirishnomalar ovoz bilan ko‘rsatilsin"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Barcha oynalar ustida ovoz bilan ko‘rsatilsin"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Bildirishnomalar ro‘yxatining boshida va barcha oynalar ustida ovoz bilan ko‘rsatilsin"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
     <string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Rang va ko‘rinishi"</string>
     <string name="use_dark_theme" msgid="2900938704964299312">"Android uchun to‘q rangli mavzudan foydalanish"</string>
     <string name="adjust_tint" msgid="3398569573231409878">"Rang tusini o‘zgartirish"</string>
     <string name="adjust_brightness" msgid="980039329808178246">"Yorqinlikni o‘zgartirish"</string>
-    <string name="night_mode_disclaimer" msgid="598914896926759578">"To‘q rangli mavzu Android OS’ning o‘zak sahifalariga ham qo‘llaniladi va bu Sozlamalar kabi och rangli mavzularda odatdagiday ko‘rsatiladi."</string>
+    <string name="night_mode_disclaimer" msgid="598914896926759578">"To‘q rangli mavzu Android tizimining odatda och rangda ko‘rsatiladigan o‘zak sahifalariga (masalan, Sozlamalar) nisbatan qo‘llaniladi."</string>
     <string name="color_apply" msgid="9212602012641034283">"Qo‘llash"</string>
     <string name="color_revert_title" msgid="4746666545480534663">"Sozlamalarni tasdiqlang"</string>
     <string name="color_revert_message" msgid="9116001069397996691">"Ba’zi rang sozlamalari qurilmadan foydalanishni qiyinlashtirish mumkin. Tanlgan parametrlarni tasdiqlash uchun “OK” tugmasini bosing. Aks holda, ular 10 soniyadan so‘ng qayta tiklanadi."</string>
     <item msgid="2139628951880142927">"Quvvat olayotganda foizda ko‘rsatilsin (birlamchi)"</item>
     <item msgid="3327323682209964956">"Bu belgi boshqa ko‘rsatilmasin"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
-    <string name="accessibility_divider" msgid="5903423481953635044">"Ekranni ikkiga bo‘lgich"</string>
+    <string name="other" msgid="4060683095962566764">"Boshqa"</string>
+    <string name="accessibility_divider" msgid="5903423481953635044">"Ekranni ikkiga bo‘lish chizig‘i"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Pastga siljitish"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Tepaga siljitish"</string>
     <string name="accessibility_action_divider_move_left" msgid="9218189832115847253">"Chapga siljitish"</string>
index d48a9e6..f828306 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"延长时间。"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"缩短时间。"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"手电筒关闭。"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"无法使用手电筒。"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"手电筒打开。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"手电筒已关闭。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"手电筒已打开。"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要开启蓝牙吗?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"要将您的键盘连接到平板电脑,您必须先开启蓝牙。"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"开启"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"显示通知,但不发出提示音"</string>
+    <string name="block" msgid="2734508760962682611">"屏蔽所有通知"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"不静音"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"不静音或不屏蔽"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"显示完整的重要性设置"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"屏蔽"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"最低重要性"</string>
     <string name="low_importance" msgid="4109929986107147930">"重要性:低"</string>
     <string name="default_importance" msgid="8192107689995742653">"重要性:一般"</string>
     <string name="high_importance" msgid="1527066195614050263">"重要性:高"</string>
     <string name="max_importance" msgid="5089005872719563894">"重要性:紧急"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"一律不显示这些通知"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"在通知列表底部显示,但不发出提示音"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"显示这些通知,但不发出提示音"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"允许这些通知发出提示音"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"在屏幕上短暂显示,并发出提示音"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"在通知列表顶部显示,同时在屏幕上短暂显示,并发出提示音"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"更多设置"</string>
     <string name="notification_done" msgid="5279426047273930175">"完成"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"颜色和外观"</string>
     <item msgid="2139628951880142927">"充电时显示百分比(默认)"</item>
     <item msgid="3327323682209964956">"不显示此图标"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"其他"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"分屏分隔线"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"下移"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"上移"</string>
index 609f94d..bd379b7 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"增加時間。"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"減少時間。"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"閃光燈已關閉。"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"無法使用手電筒。"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"閃光燈已開啟。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"閃光燈已關閉。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"閃光燈已開啟。"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙嗎?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連接至平板電腦,請先開啟藍牙。"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"顯示通知,但不發出音效"</string>
+    <string name="block" msgid="2734508760962682611">"封鎖所有通知"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"不設為靜音"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"不設為靜音或封鎖"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"顯示所有重要性設定"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"已封鎖"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"最低重要性"</string>
     <string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
     <string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
     <string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
     <string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"永不顯示這些通知"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"在通知清單底部顯示但不發出音效"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"顯示這些通知但不發出音效"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"允許這些通知發出音效"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"不時於螢幕出現並發出音效"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"在通知清單頂部顯示,並不時於螢幕出現及發出音效"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
     <string name="notification_done" msgid="5279426047273930175">"完成"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"顏色和外觀"</string>
     <item msgid="2139628951880142927">"充電時顯示百分比 (預設)"</item>
     <item msgid="3327323682209964956">"不顯示這個圖示"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"其他"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"分割畫面分隔線"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"向下移"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"向上移"</string>
index 2188c3c..d580b28 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"增加時間。"</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"減少時間。"</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"閃光燈已關閉。"</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"無法使用手電筒。"</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"閃光燈已開啟。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"閃光燈已關閉。"</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"閃光燈已開啟。"</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"要開啟藍牙功能嗎?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"如要將鍵盤連線到平板電腦,您必須先開啟藍牙。"</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"開啟"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"顯示通知,但不發出任何音效"</string>
+    <string name="block" msgid="2734508760962682611">"封鎖所有通知"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"不設定靜音"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"不設定靜音或封鎖"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"顯示完整的重要性設定"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"封鎖"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"最低重要性"</string>
     <string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
     <string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
     <string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
     <string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"一律不顯示這些通知"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"顯示在通知清單底端,但不發出任何音效"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"顯示這些通知,但不發出任何音效"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"允許這些通知發出音效"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"短暫顯示在畫面上並發出音效"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"顯示在通知清單頂端,同時短暫顯示在畫面上並發出音效"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
     <string name="notification_done" msgid="5279426047273930175">"完成"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"顏色和外觀"</string>
     <item msgid="2139628951880142927">"充電時顯示百分比 (預設)"</item>
     <item msgid="3327323682209964956">"不顯示這個圖示"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"其他"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"分割畫面分隔線"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"向下移"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"向上移"</string>
index 69c85ab..9382b26 100644 (file)
     <string name="accessibility_quick_settings_more_time" msgid="3659274935356197708">"Isikhathi esiningi."</string>
     <string name="accessibility_quick_settings_less_time" msgid="2404728746293515623">"Isikhathi esincane."</string>
     <string name="accessibility_quick_settings_flashlight_off" msgid="4936432000069786988">"I-Flashlight ivaliwe."</string>
-    <!-- no translation found for accessibility_quick_settings_flashlight_unavailable (8012811023312280810) -->
-    <skip />
+    <string name="accessibility_quick_settings_flashlight_unavailable" msgid="8012811023312280810">"I-Flashlight ayitholakali."</string>
     <string name="accessibility_quick_settings_flashlight_on" msgid="2003479320007841077">"I-Flashlight ivuliwe."</string>
     <string name="accessibility_quick_settings_flashlight_changed_off" msgid="3303701786768224304">"I-Flashlight ivaliwe."</string>
     <string name="accessibility_quick_settings_flashlight_changed_on" msgid="6531793301533894686">"I-Flashlight ivuliwe."</string>
     <string name="enable_bluetooth_title" msgid="5027037706500635269">"Vula i-Bluetooth?"</string>
     <string name="enable_bluetooth_message" msgid="9106595990708985385">"Ukuze uxhume ikhibhodi yakho nethebhulethi yakho, kufanele uqale ngokuvula i-Bluetooth."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="6258074250948309715">"Vula"</string>
-    <!-- no translation found for show_silently (6841966539811264192) -->
-    <skip />
-    <!-- no translation found for block (2734508760962682611) -->
-    <skip />
-    <!-- no translation found for do_not_silence (6878060322594892441) -->
-    <skip />
-    <!-- no translation found for do_not_silence_block (4070647971382232311) -->
-    <skip />
-    <!-- no translation found for tuner_full_importance_settings (8103289238676424226) -->
-    <skip />
+    <string name="show_silently" msgid="6841966539811264192">"Bonisa izaziso ngokuthulile"</string>
+    <string name="block" msgid="2734508760962682611">"Vimbela zonke izaziso"</string>
+    <string name="do_not_silence" msgid="6878060322594892441">"Ungathulisi"</string>
+    <string name="do_not_silence_block" msgid="4070647971382232311">"Ungathulisi noma uvimbele"</string>
+    <string name="tuner_full_importance_settings" msgid="8103289238676424226">"Bonisa izilungiselelo ezibalulekile ezigcwele"</string>
     <string name="blocked_importance" msgid="5198578988978234161">"Kuvinjelwe"</string>
-    <!-- no translation found for min_importance (1901894910809414782) -->
-    <skip />
+    <string name="min_importance" msgid="1901894910809414782">"Okubaluleke kancane"</string>
     <string name="low_importance" msgid="4109929986107147930">"Ukubaluleka okuphansi"</string>
     <string name="default_importance" msgid="8192107689995742653">"Ukubaluleka okujwayelekile"</string>
     <string name="high_importance" msgid="1527066195614050263">"Ukubaluleka okuphezulu"</string>
     <string name="max_importance" msgid="5089005872719563894">"Ukubaluleka okusheshayo"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ungalokothi ubonise lezi zaziso"</string>
-    <!-- no translation found for notification_importance_min (1938190340516905748) -->
-    <skip />
-    <!-- no translation found for notification_importance_low (3657252049508213048) -->
-    <skip />
-    <!-- no translation found for notification_importance_default (4466466472622442175) -->
-    <skip />
-    <!-- no translation found for notification_importance_high (2135428926525093825) -->
-    <skip />
-    <!-- no translation found for notification_importance_max (5806278962376556491) -->
-    <skip />
+    <string name="notification_importance_min" msgid="1938190340516905748">"Bonisa ngokuthulile ngaphansi kohlu lwesaziso"</string>
+    <string name="notification_importance_low" msgid="3657252049508213048">"Bonisa ngokuthulile lezi zaziso"</string>
+    <string name="notification_importance_default" msgid="4466466472622442175">"Vumela lezi zaziso ukwenza umsindo"</string>
+    <string name="notification_importance_high" msgid="2135428926525093825">"Beka kusikrini futhi uvumele umsindo"</string>
+    <string name="notification_importance_max" msgid="5806278962376556491">"Bonisa phezulu kohlu lwezaziso, beka phezu kwesikrini futhi uvumele umsindo"</string>
     <string name="notification_more_settings" msgid="816306283396553571">"Izilungiselelo eziningi"</string>
     <string name="notification_done" msgid="5279426047273930175">"Kwenziwe"</string>
     <string name="color_and_appearance" msgid="1254323855964993144">"Umbala nokubonakala"</string>
     <item msgid="2139628951880142927">"Bonisa iphesentheji uma ishaja (okuzenzakalelayo)"</item>
     <item msgid="3327323682209964956">"Ungabonisi lesi sithonjana"</item>
   </string-array>
-    <!-- no translation found for other (4060683095962566764) -->
-    <skip />
+    <string name="other" msgid="4060683095962566764">"Okunye"</string>
     <string name="accessibility_divider" msgid="5903423481953635044">"Isihlukanisi sokuhlukanisa isikrini"</string>
     <string name="accessibility_action_divider_move_down" msgid="704893304141890042">"Iya phansi"</string>
     <string name="accessibility_action_divider_move_up" msgid="4580103171609248006">"Iya phezulu"</string>
index 189eb3b..e040ab2 100644 (file)
@@ -93,5 +93,9 @@
         <attr name="defValue" format="boolean" />
         <attr name="metricsAction" format="integer" />
     </declare-styleable>
+
+    <declare-styleable name="DensityContainer">
+        <attr name="android:layout" />
+    </declare-styleable>
 </resources>
 
index 8f69bbb..30acc72 100644 (file)
@@ -31,7 +31,7 @@
     <color name="batterymeter_bolt_color">#FFFFFFFF</color>
     <color name="qs_batterymeter_frame_color">#FF404040</color>
     <color name="system_primary_color">#ff263238</color><!-- blue grey 900 -->
-    <color name="system_secondary_color">#ff384248</color>
+    <color name="system_secondary_color">#ff37474F</color><!-- blue grey 800 -->
     <color name="system_accent_color">#ff80CBC4</color><!-- deep teal 200 -->
     <color name="system_warning_color">#fff4511e</color><!-- deep orange 600 -->
     <color name="qs_text">#FFFFFFFF</color>
index 6f4c983..af99aae 100644 (file)
@@ -18,7 +18,5 @@
 -->
 <resources>
     <color name="recents_tv_card_background_color">#FF37474F</color>
-    <color name="recents_tv_card_title_text_color">#FFEEEEEE</color>
-    <color name="recents_tv_card_content_text_color">#99EEEEEE</color>
-    <color name="recents_tv_card_source_text_color">#99EEEEEE</color>
+    <color name="recents_tv_card_title_text_color">#CCEEEEEE</color>
 </resources>
\ No newline at end of file
index fbe0207..12c3a5d 100644 (file)
     <!-- The amount to allow the stack to overscroll. -->
     <dimen name="recents_stack_overscroll">24dp</dimen>
 
+    <!-- The size of the initial peek area at the top of the stack (below the status bar). -->
+    <dimen name="recents_initial_top_peek_size">8dp</dimen>
+
     <!-- The size of the peek area at the top of the stack (below the status bar). -->
     <dimen name="recents_layout_focused_top_peek_size">@dimen/recents_history_button_height</dimen>
 
     <!-- The minimum amount of top overscroll to go to the quick settings. -->
     <dimen name="min_top_overscroll_to_qs">36dp</dimen>
 
-    <!-- The padding to the second card when the notifications collapse. -->
-    <dimen name="notification_collapse_second_card_padding">8dp</dimen>
-
     <!-- The height of the speed bump view. -->
     <dimen name="speed_bump_height">16dp</dimen>
 
index bf32cc7..b589110 100644 (file)
 -->
 <resources>
     <!-- Dimens for recents card in the recents view on tv -->
-    <dimen name="recents_tv_card_width">150dip</dimen>
-    <dimen name="recents_tv_card_height">85dip</dimen>
-    <dimen name="recents_tv_card_extra_badge_size">16dip</dimen>
+    <dimen name="recents_tv_card_width">268dip</dimen>
+    <dimen name="recents_tv_card_height">151dip</dimen>
+    <dimen name="recents_tv_card_extra_badge_size">20dip</dimen>
+    <dimen name="recents_tv_banner_width">114dip</dimen>
+    <dimen name="recents_tv_banner_height">64dip</dimen>
+    <dimen name="recents_tv_banner_margin_top">16dip</dimen>
+    <dimen name="recents_tv_icon_padding_bottom">8dip</dimen>
+    <dimen name="recents_tv_icon_padding_end">12dip</dimen>
+    <dimen name="recents_tv_text_padding_bottom">12dip</dimen>
 
     <!-- Padding for grid view in recents view on tv -->
     <dimen name="recents_tv_grid_row_padding">56dip</dimen>
     <dimen name="recents_tv_gird_row_top_padding">57dip</dimen>
-    <dimen name="recents_tv_grid_max_row_height">200dip</dimen>
-    <dimen name="recents_tv_gird_card_spacing">8dip</dimen>
+    <dimen name="recents_tv_grid_max_row_height">268dip</dimen>
+    <dimen name="recents_tv_gird_card_spacing">20dip</dimen>
 
     <!-- Values for focus animation -->
     <dimen name="recents_tv_unselected_item_z">6dp</dimen>
@@ -34,4 +40,7 @@
 
     <!-- Extra space around the PIP and its outline in PIP onboarding activity  -->
     <dimen name="tv_pip_bounds_space">3dp</dimen>
+
+    <!-- Values for text on recents cards on tv -->
+    <dimen name="recents_tv_title_text_size">12sp</dimen>
 </resources>
index 4f382ea..59cfb1e 100644 (file)
     <string name="pip_cancel" translatable="false">Cancel</string>
     <!-- Overlay text on PIP -->
     <string name="pip_hold_home" translatable="false">Hold HOME to control PIP</string>
-
     <!-- Picture-in-Picture onboarding screen -->
     <eat-comment />
     <!-- Description for onboarding screen. -->
     <string name="pip_onboarding_description" translatable="false">Press and hold the HOME\nbutton to close or control it</string>
     <!-- Button to close onboarding screen. -->
     <string name="pip_onboarding_button" translatable="false">Got it</string>
+    <!-- Font for Recents -->
+    <!-- DO NOT TRANSLATE -->
+    <string name="font_roboto_regular" translatable="false">sans-serif</string>
 </resources>
index a51b931..89890d6 100644 (file)
 
     <style name="QSBorderlessButton">
         <item name="android:padding">12dp</item>
-        <item name="android:background">@drawable/btn_borderless_rect</item>
+        <item name="android:background">@drawable/qs_btn_borderless_rect</item>
         <item name="android:gravity">center</item>
     </style>
 
         <item name="android:textSize">16sp</item>
     </style>
 
+    <style name="TextAppearance.NotificationGuts.Radio">
+        <item name="android:alpha">.87</item>
+    </style>
+
     <style name="TextAppearance.NotificationGuts.Button">
         <item name="android:textSize">14sp</item>
         <item name="android:textAllCaps">true</item>
index 3f0caab..263e1a4 100644 (file)
         <item name="android:windowBackground">@android:color/transparent</item>
         <item name="android:backgroundDimEnabled">false</item>
      </style>
+
+    <style name="RecentsTvTheme.Wallpaper" parent="@android:style/Theme.Material.NoActionBar.Overscan">
+        <item name="android:windowBackground">@android:color/transparent</item>
+        <item name="android:backgroundDimEnabled">false</item>
+        <item name="android:colorBackgroundCacheHint">@null</item>
+        <item name="android:windowIsTranslucent">true</item>
+    </style>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/DensityContainer.java b/packages/SystemUI/src/com/android/systemui/DensityContainer.java
new file mode 100644 (file)
index 0000000..2e3cb49
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.FrameLayout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class DensityContainer extends FrameLayout {
+
+    private final List<InflateListener> mInflateListeners = new ArrayList<>();
+    private final int mLayout;
+    private int mDensity;
+
+    public DensityContainer(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+
+        mDensity = context.getResources().getConfiguration().densityDpi;
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DensityContainer);
+        if (!a.hasValue(R.styleable.DensityContainer_android_layout)) {
+            throw new IllegalArgumentException("DensityContainer must contain a layout");
+        }
+        mLayout = a.getResourceId(R.styleable.DensityContainer_android_layout, 0);
+        inflateLayout();
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        int density = newConfig.densityDpi;
+        if (density != mDensity) {
+            mDensity = density;
+            inflateLayout();
+        }
+    }
+
+    private void inflateLayout() {
+        removeAllViews();
+        LayoutInflater.from(getContext()).inflate(mLayout, this);
+        final int N = mInflateListeners.size();
+        for (int i = 0; i < N; i++) {
+            mInflateListeners.get(i).onInflated(getChildAt(0));
+        }
+    }
+
+    public void addInflateListener(InflateListener listener) {
+        mInflateListeners.add(listener);
+        listener.onInflated(getChildAt(0));
+    }
+
+    public interface InflateListener {
+        /**
+         * Called whenever a new view is inflated.
+         */
+        void onInflated(View v);
+    }
+}
index 33f3c30..f6dcc11 100644 (file)
@@ -144,7 +144,9 @@ public class SwipeHelper implements Gefingerpoken {
     protected Animator getViewTranslationAnimator(View v, float target,
             AnimatorUpdateListener listener) {
         ObjectAnimator anim = createTranslationAnimation(v, target);
-        anim.addUpdateListener(listener);
+        if (listener != null) {
+            anim.addUpdateListener(listener);
+        }
         return anim;
     }
 
@@ -370,6 +372,9 @@ public class SwipeHelper implements Gefingerpoken {
         };
 
         Animator anim = getViewTranslationAnimator(animView, newPos, updateListener);
+        if (anim == null) {
+            return;
+        }
         if (useAccelerateInterpolator) {
             anim.setInterpolator(Interpolators.FAST_OUT_LINEAR_IN);
         } else {
@@ -411,6 +416,9 @@ public class SwipeHelper implements Gefingerpoken {
         };
 
         Animator anim = getViewTranslationAnimator(animView, targetLeft, updateListener);
+        if (anim == null) {
+            return;
+        }
         int duration = SNAP_ANIM_LEN;
         anim.setDuration(duration);
         anim.addListener(new AnimatorListenerAdapter() {
index ea7270d..4b775a5 100644 (file)
@@ -38,7 +38,9 @@ import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
 import android.text.TextUtils;
+import android.util.Pair;
 import android.util.Slog;
+import android.widget.Toast;
 
 import com.android.settingslib.bluetooth.BluetoothCallback;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -46,6 +48,7 @@ import com.android.settingslib.bluetooth.CachedBluetoothDeviceManager;
 import com.android.settingslib.bluetooth.LocalBluetoothAdapter;
 import com.android.settingslib.bluetooth.LocalBluetoothManager;
 import com.android.settingslib.bluetooth.LocalBluetoothProfileManager;
+import com.android.settingslib.bluetooth.Utils;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 
@@ -76,8 +79,9 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
     private static final int STATE_WAITING_FOR_BLUETOOTH = 4;
     private static final int STATE_PAIRING = 5;
     private static final int STATE_PAIRED = 6;
-    private static final int STATE_USER_CANCELLED = 7;
-    private static final int STATE_DEVICE_NOT_FOUND = 8;
+    private static final int STATE_PAIRING_FAILED = 7;
+    private static final int STATE_USER_CANCELLED = 8;
+    private static final int STATE_DEVICE_NOT_FOUND = 9;
 
     private static final int MSG_INIT = 0;
     private static final int MSG_ON_BOOT_COMPLETED = 1;
@@ -90,6 +94,7 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
     private static final int MSG_SHOW_BLUETOOTH_DIALOG = 8;
     private static final int MSG_DISMISS_BLUETOOTH_DIALOG = 9;
     private static final int MSG_BLE_ABORT_SCAN = 10;
+    private static final int MSG_SHOW_ERROR = 11;
 
     private volatile KeyboardHandler mHandler;
     private volatile KeyboardUIHandler mUIHandler;
@@ -178,6 +183,7 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
         mLocalBluetoothAdapter = bluetoothManager.getBluetoothAdapter();
         mProfileManager = bluetoothManager.getProfileManager();
         bluetoothManager.getEventManager().registerCallback(new BluetoothCallbackHandler());
+        Utils.setErrorListener(new BluetoothErrorListener());
 
         InputManager im = context.getSystemService(InputManager.class);
         im.registerOnTabletModeChangedListener(this, mHandler);
@@ -204,13 +210,15 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
         if (mInTabletMode != InputManager.SWITCH_STATE_OFF) {
             if (mState == STATE_WAITING_FOR_DEVICE_DISCOVERY) {
                 stopScanning();
+            } else if (mState == STATE_WAITING_FOR_BLUETOOTH) {
+                mUIHandler.sendEmptyMessage(MSG_DISMISS_BLUETOOTH_DIALOG);
             }
             mState = STATE_WAITING_FOR_TABLET_MODE_EXIT;
             return;
         }
 
         final int btState = mLocalBluetoothAdapter.getState();
-        if (btState == BluetoothAdapter.STATE_TURNING_ON || btState == BluetoothAdapter.STATE_ON
+        if ((btState == BluetoothAdapter.STATE_TURNING_ON || btState == BluetoothAdapter.STATE_ON)
                 && mState == STATE_WAITING_FOR_BLUETOOTH) {
             // If we're waiting for bluetooth but it has come on in the meantime, or is coming
             // on, just dismiss the dialog. This frequently happens during device startup.
@@ -334,7 +342,10 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
 
     private void stopScanning() {
         if (mScanCallback != null) {
-            mLocalBluetoothAdapter.getBluetoothLeScanner().stopScan(mScanCallback);
+            BluetoothLeScanner scanner = mLocalBluetoothAdapter.getBluetoothLeScanner();
+            if (scanner != null) {
+                scanner.stopScan(mScanCallback);
+            }
             mScanCallback = null;
         }
     }
@@ -370,10 +381,14 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
 
     // Should only be called on the handler thread
     private void onDeviceBondStateChangedInternal(CachedBluetoothDevice d, int bondState) {
-        if (d.getName().equals(mKeyboardName) && bondState == BluetoothDevice.BOND_BONDED) {
-            // We don't need to manually connect to the device here because it will automatically
-            // try to connect after it has been paired.
-            mState = STATE_PAIRED;
+        if (mState == STATE_PAIRING && d.getName().equals(mKeyboardName)) {
+            if (bondState == BluetoothDevice.BOND_BONDED) {
+                // We don't need to manually connect to the device here because it will
+                // automatically try to connect after it has been paired.
+                mState = STATE_PAIRED;
+            } else if (bondState == BluetoothDevice.BOND_NONE) {
+                mState = STATE_PAIRING_FAILED;
+            }
         }
     }
 
@@ -385,6 +400,17 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
         }
     }
 
+    // Should only be called on the handler thread. We want to be careful not to show errors for
+    // pairings not initiated by this UI, so we only pop up the toast when we're at an appropriate
+    // point in our pairing flow and it's the expected device.
+    private void onShowErrorInternal(Context context, String name, int messageResId) {
+        if ((mState == STATE_PAIRING || mState == STATE_PAIRING_FAILED)
+                && mKeyboardName.equals(name)) {
+            String message = context.getString(messageResId, name);
+            Toast.makeText(context, message, Toast.LENGTH_SHORT).show();
+        }
+    }
+
     private final class KeyboardUIHandler extends Handler {
         public KeyboardUIHandler() {
             super(Looper.getMainLooper(), null, true /*async*/);
@@ -393,19 +419,27 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
         public void handleMessage(Message msg) {
             switch(msg.what) {
                 case MSG_SHOW_BLUETOOTH_DIALOG: {
-                    DialogInterface.OnClickListener listener = new BluetoothDialogClickListener();
+                    if (mDialog != null) {
+                        // Don't show another dialog if one is already present
+                        break;
+                    }
+                    DialogInterface.OnClickListener clickListener =
+                            new BluetoothDialogClickListener();
+                    DialogInterface.OnDismissListener dismissListener =
+                            new BluetoothDialogDismissListener();
                     mDialog = new BluetoothDialog(mContext);
                     mDialog.setTitle(R.string.enable_bluetooth_title);
                     mDialog.setMessage(R.string.enable_bluetooth_message);
-                    mDialog.setPositiveButton(R.string.enable_bluetooth_confirmation_ok, listener);
-                    mDialog.setNegativeButton(android.R.string.cancel, listener);
+                    mDialog.setPositiveButton(
+                            R.string.enable_bluetooth_confirmation_ok, clickListener);
+                    mDialog.setNegativeButton(android.R.string.cancel, clickListener);
+                    mDialog.setOnDismissListener(dismissListener);
                     mDialog.show();
                     break;
                 }
                 case MSG_DISMISS_BLUETOOTH_DIALOG: {
                     if (mDialog != null) {
                         mDialog.dismiss();
-                        mDialog = null;
                     }
                     break;
                 }
@@ -469,6 +503,10 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
                     onBleScanFailedInternal();
                     break;
                 }
+                case MSG_SHOW_ERROR: {
+                    Pair<Context, String> p = (Pair<Context, String>) msg.obj;
+                    onShowErrorInternal(p.first, p.second, msg.arg1);
+                }
             }
         }
     }
@@ -482,6 +520,14 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
         }
     }
 
+    private final class BluetoothDialogDismissListener
+            implements DialogInterface.OnDismissListener {
+        @Override
+        public void onDismiss(DialogInterface dialog) {
+            mDialog = null;
+        }
+    }
+
     private final class KeyboardScanCallback extends ScanCallback {
 
         private boolean isDeviceDiscoverable(ScanResult result) {
@@ -564,6 +610,13 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
         public void onConnectionStateChanged(CachedBluetoothDevice cachedDevice, int state) { }
     }
 
+    private final class BluetoothErrorListener implements Utils.ErrorListener {
+        public void onShowError(Context context, String name, int messageResId) {
+            mHandler.obtainMessage(MSG_SHOW_ERROR, messageResId, 0 /*unused*/,
+                    new Pair<>(context, name)).sendToTarget();
+        }
+    }
+
     private static String stateToString(int state) {
         switch (state) {
             case STATE_NOT_ENABLED:
@@ -580,13 +633,15 @@ public class KeyboardUI extends SystemUI implements InputManager.OnTabletModeCha
                 return "STATE_PAIRING";
             case STATE_PAIRED:
                 return "STATE_PAIRED";
+            case STATE_PAIRING_FAILED:
+                return "STATE_PAIRING_FAILED";
             case STATE_USER_CANCELLED:
                 return "STATE_USER_CANCELLED";
             case STATE_DEVICE_NOT_FOUND:
                 return "STATE_DEVICE_NOT_FOUND";
             case STATE_UNKNOWN:
             default:
-                return "STATE_UNKNOWN";
+                return "STATE_UNKNOWN (" + state + ")";
         }
     }
 }
index 2c5cb89..24b45cc 100644 (file)
@@ -77,7 +77,9 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
 
     @Override
     public int getOffsetTop(TileRecord tile) {
-        return ((ViewGroup) tile.tileView.getParent()).getTop() + getTop();
+        final ViewGroup parent = (ViewGroup) tile.tileView.getParent();
+        if (parent == null) return 0;
+        return parent.getTop() + getTop();
     }
 
     @Override
@@ -165,6 +167,11 @@ public class PagedTileLayout extends ViewPager implements QSTileLayout {
         }
     };
 
+    public int getColumnCount() {
+        if (mPages.size() == 0) return 0;
+        return mPages.get(0).mColumns;
+    }
+
     public static class TilePage extends TileLayout {
         private int mMaxRows = 3;
 
index c643d67..6137349 100644 (file)
@@ -16,6 +16,7 @@ package com.android.systemui.qs;
 
 import android.util.Log;
 import android.view.View;
+import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnLayoutChangeListener;
 import android.view.animation.PathInterpolator;
 import android.widget.TextView;
@@ -25,14 +26,20 @@ import com.android.systemui.qs.QSTile.Host.Callback;
 import com.android.systemui.qs.TouchAnimator.Builder;
 import com.android.systemui.qs.TouchAnimator.Listener;
 import com.android.systemui.statusbar.phone.QSTileHost;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.util.ArrayList;
 import java.util.Collection;
 
-public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener {
+public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener,
+        OnAttachStateChangeListener, Tunable {
 
     private static final String TAG = "QSAnimator";
 
+    private static final String ALLOW_FANCY_ANIMATION = "sysui_qs_fancy_anim";
+    private static final String MOVE_FULL_ROWS = "sysui_qs_move_whole_rows";
+
     public static final PathInterpolator TRANSLATION_Y_INTERPOLATOR =
             new PathInterpolator(.1f, .3f, 1, 1);
 
@@ -44,34 +51,77 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
     private final QSPanel mQsPanel;
     private final QSContainer mQsContainer;
 
+    private PagedTileLayout mPagedLayout;
+
     private boolean mOnFirstPage = true;
     private TouchAnimator mFirstPageAnimator;
     private TouchAnimator mFirstPageDelayedAnimator;
     private TouchAnimator mTranslationYAnimator;
     private TouchAnimator mNonfirstPageAnimator;
 
+    private boolean mOnKeyguard;
+
+    private boolean mAllowFancy;
+    private boolean mFullRows;
+    private int mNumQuickTiles;
+
     public QSAnimator(QSContainer container, QuickQSPanel quickPanel, QSPanel panel) {
         mQsContainer = container;
         mQuickQsPanel = quickPanel;
         mQsPanel = panel;
+        mQsPanel.addOnAttachStateChangeListener(this);
         container.addOnLayoutChangeListener(this);
         QSTileLayout tileLayout = mQsPanel.getTileLayout();
         if (tileLayout instanceof PagedTileLayout) {
-            ((PagedTileLayout) tileLayout).setPageListener(this);
+            mPagedLayout = ((PagedTileLayout) tileLayout);
+            mPagedLayout.setPageListener(this);
         } else {
             Log.w(TAG, "QS Not using page layout");
         }
     }
 
+    public void setOnKeyguard(boolean onKeyguard) {
+        mOnKeyguard = onKeyguard;
+        if (mOnKeyguard) {
+            clearAnimationState();
+        }
+    }
+
     public void setHost(QSTileHost qsh) {
         qsh.addCallback(this);
     }
 
     @Override
+    public void onViewAttachedToWindow(View v) {
+        TunerService.get(mQsContainer.getContext()).addTunable(this, ALLOW_FANCY_ANIMATION,
+                MOVE_FULL_ROWS, QuickQSPanel.NUM_QUICK_TILES);
+    }
+
+    @Override
+    public void onViewDetachedFromWindow(View v) {
+        TunerService.get(mQsContainer.getContext()).removeTunable(this);
+    }
+
+    @Override
+    public void onTuningChanged(String key, String newValue) {
+        if (ALLOW_FANCY_ANIMATION.equals(key)) {
+            mAllowFancy = newValue == null || Integer.parseInt(newValue) != 0;
+            if (!mAllowFancy) {
+                clearAnimationState();
+            }
+        } else if (MOVE_FULL_ROWS.equals(key)) {
+            mFullRows = newValue != null && Integer.parseInt(newValue) != 0;
+        } else if (QuickQSPanel.NUM_QUICK_TILES.equals(key)) {
+            mNumQuickTiles = QuickQSPanel.getNumQuickTiles(mQsContainer.getContext());
+            clearAnimationState();
+        }
+        updateAnimators();
+    }
+
+    @Override
     public void onPageChanged(boolean isFirst) {
         if (mOnFirstPage == isFirst) return;
         if (!isFirst) {
-            setPosition(1);
             clearAnimationState();
         }
         mOnFirstPage = isFirst;
@@ -85,6 +135,7 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
         int count = 0;
         int[] loc1 = new int[2];
         int[] loc2 = new int[2];
+        int lastYDiff = 0;
         firstPageDelayedBuilder.setStartDelay(EXPANDED_TILE_DELAY);
         firstPageBuilder.setListener(this);
         translationYBuilder.setInterpolator(TRANSLATION_Y_INTERPOLATOR);
@@ -92,18 +143,20 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
         firstPageDelayedBuilder.addFloat(mQsPanel.getTileLayout(), "alpha", 0, 1);
         mAllViews.clear();
         mTopFiveQs.clear();
+        mAllViews.add((View) mQsPanel.getTileLayout());
         for (QSTile<?> tile : tiles) {
             QSTileBaseView tileView = mQsPanel.getTileView(tile);
             final TextView label = ((QSTileView) tileView).getLabel();
-            if (count++ < 5) {
+            final View tileIcon = tileView.getIcon();
+            if (count < mNumQuickTiles && mAllowFancy) {
                 // Quick tiles.
                 QSTileBaseView quickTileView = mQuickQsPanel.getTileView(tile);
-                final View tileIcon = tileView.getIcon();
 
                 getRelativePosition(loc1, quickTileView.getIcon(), mQsContainer);
                 getRelativePosition(loc2, tileIcon, mQsContainer);
                 final int xDiff = loc2[0] - loc1[0];
                 final int yDiff = loc2[1] - loc1[1];
+                lastYDiff = yDiff;
                 // Move the quick tile right from its location to the new one.
                 firstPageBuilder.addFloat(quickTileView, "translationX", 0, xDiff);
                 translationYBuilder.addFloat(quickTileView, "translationY", 0, yDiff);
@@ -119,20 +172,38 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
 
                 mTopFiveQs.add(tileIcon);
                 mAllViews.add(tileIcon);
+                mAllViews.add(label);
                 mAllViews.add(quickTileView);
+            } else if (mFullRows && isIconInAnimatedRow(count)) {
+                firstPageBuilder.addFloat(tileView, "translationY", mQsPanel.getHeight(), 0);
+                translationYBuilder.addFloat(label, "translationY", -lastYDiff, 0);
+                translationYBuilder.addFloat(tileIcon, "translationY", -lastYDiff, 0);
+                mAllViews.add(tileIcon);
+                mAllViews.add(label);
             }
             mAllViews.add(tileView);
             mAllViews.add(label);
+            count++;
+        }
+        if (mAllowFancy) {
+            mFirstPageAnimator = firstPageBuilder.build();
+            mFirstPageDelayedAnimator = firstPageDelayedBuilder.build();
+            mTranslationYAnimator = translationYBuilder.build();
         }
-        mFirstPageAnimator = firstPageBuilder.build();
-        mFirstPageDelayedAnimator = firstPageDelayedBuilder.build();
-        mTranslationYAnimator = translationYBuilder.build();
         mNonfirstPageAnimator = new TouchAnimator.Builder()
                 .addFloat(mQuickQsPanel, "alpha", 1, 0)
                 .setEndDelay(.5f)
                 .build();
     }
 
+    private boolean isIconInAnimatedRow(int count) {
+        if (mPagedLayout == null) {
+            return false;
+        }
+        final int columnCount = mPagedLayout.getColumnCount();
+        return count < ((mNumQuickTiles + columnCount - 1) / columnCount) * columnCount;
+    }
+
     private void getRelativePosition(int[] loc1, View view, View parent) {
         loc1[0] = 0 + view.getWidth() / 2;
         loc1[1] = 0;
@@ -148,7 +219,10 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
 
     public void setPosition(float position) {
         if (mFirstPageAnimator == null) return;
-        if (mOnFirstPage) {
+        if (mOnKeyguard) {
+            return;
+        }
+        if (mOnFirstPage && mAllowFancy) {
             mQuickQsPanel.setAlpha(1);
             mFirstPageAnimator.setPosition(position);
             mFirstPageDelayedAnimator.setPosition(position);
@@ -186,12 +260,17 @@ public class QSAnimator implements Callback, PageListener, Listener, OnLayoutCha
     private void clearAnimationState() {
         final int N = mAllViews.size();
         mQuickQsPanel.setAlpha(0);
+        mQuickQsPanel.setVisibility(View.VISIBLE);
         for (int i = 0; i < N; i++) {
             View v = mAllViews.get(i);
             v.setAlpha(1);
             v.setTranslationX(1);
             v.setTranslationY(1);
         }
+        final int N2 = mTopFiveQs.size();
+        for (int i = 0; i < N2; i++) {
+            mTopFiveQs.get(i).setVisibility(View.VISIBLE);
+        }
     }
 
     @Override
index c59da8d..c0c1e4d 100644 (file)
@@ -156,6 +156,7 @@ public class QSContainer extends FrameLayout {
     public void setKeyguardShowing(boolean keyguardShowing) {
         if (DEBUG) Log.d(TAG, "setKeyguardShowing " + keyguardShowing);
         mKeyguardShowing = keyguardShowing;
+        mQSAnimator.setOnKeyguard(keyguardShowing);
         updateQsState();
     }
 
index 267ed16..546f8c3 100644 (file)
@@ -23,7 +23,6 @@ import android.graphics.drawable.Drawable;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
-
 import android.widget.ImageView.ScaleType;
 import com.android.systemui.R;
 
@@ -34,6 +33,7 @@ public class QSIconView extends ViewGroup {
     private final View mIcon;
     private final int mIconSizePx;
     private final int mTilePaddingBelowIconPx;
+    private boolean mAnimationEnabled = true;
 
     public QSIconView(Context context) {
         super(context);
@@ -46,6 +46,10 @@ public class QSIconView extends ViewGroup {
         addView(mIcon);
     }
 
+    public void disableAnimation() {
+        mAnimationEnabled = false;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int w = MeasureSpec.getSize(widthMeasureSpec);
@@ -69,7 +73,9 @@ public class QSIconView extends ViewGroup {
 
     protected void setIcon(ImageView iv, QSTile.State state) {
         if (!Objects.equals(state.icon, iv.getTag(R.id.qs_icon_tag))) {
-            Drawable d = state.icon != null ? state.icon.getDrawable(mContext) : null;
+            Drawable d = state.icon != null
+                    ? iv.isShown() && mAnimationEnabled ? state.icon.getDrawable(mContext)
+                    : state.icon.getInvisibleDrawable(mContext) : null;
             int padding = state.icon != null ? state.icon.getPadding() : null;
             if (d != null && state.autoMirrorDrawable) {
                 d.setAutoMirrored(true);
@@ -77,7 +83,7 @@ public class QSIconView extends ViewGroup {
             iv.setImageDrawable(d);
             iv.setTag(R.id.qs_icon_tag, state.icon);
             iv.setPadding(0, padding, 0, padding);
-            if (d instanceof Animatable) {
+            if (d instanceof Animatable && iv.isShown()) {
                 Animatable a = (Animatable) d;
                 a.start();
                 if (!iv.isShown()) {
index 30a9850..71c1913 100644 (file)
@@ -31,6 +31,7 @@ import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile.DetailAdapter;
+import com.android.systemui.qs.QSTile.Host.Callback;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.settings.BrightnessController;
@@ -44,7 +45,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 
 /** View that represents the quick settings tile panel. **/
-public class QSPanel extends LinearLayout implements Tunable {
+public class QSPanel extends LinearLayout implements Tunable, Callback {
 
     public static final String QS_SHOW_BRIGHTNESS = "qs_show_brightness";
 
@@ -123,10 +124,16 @@ public class QSPanel extends LinearLayout implements Tunable {
     @Override
     protected void onDetachedFromWindow() {
         TunerService.get(mContext).removeTunable(this);
+        mHost.removeCallback(this);
         super.onDetachedFromWindow();
     }
 
     @Override
+    public void onTilesChanged() {
+        setTiles(mHost.getTiles());
+    }
+
+    @Override
     public void onTuningChanged(String key, String newValue) {
         if (QS_SHOW_BRIGHTNESS.equals(key)) {
             mBrightnessView.setVisibility(newValue == null || Integer.parseInt(newValue) != 0
@@ -168,6 +175,8 @@ public class QSPanel extends LinearLayout implements Tunable {
 
     public void setHost(QSTileHost host) {
         mHost = host;
+        mHost.addCallback(this);
+        setTiles(mHost.getTiles());
         mFooter.setHost(host);
         createCustomizePanel();
     }
@@ -272,7 +281,7 @@ public class QSPanel extends LinearLayout implements Tunable {
         }
     }
 
-    private void drawTile(TileRecord r, QSTile.State state) {
+    protected void drawTile(TileRecord r, QSTile.State state) {
         r.tileView.onStateChanged(state);
     }
 
index df622b8..42e98aa 100644 (file)
@@ -390,6 +390,7 @@ public abstract class QSTile<TState extends State> implements Listenable {
         Context getContext();
         Collection<QSTile<?>> getTiles();
         void addCallback(Callback callback);
+        void removeCallback(Callback callback);
         BluetoothController getBluetoothController();
         LocationController getLocationController();
         RotationLockController getRotationLockController();
@@ -416,6 +417,10 @@ public abstract class QSTile<TState extends State> implements Listenable {
     public static abstract class Icon {
         abstract public Drawable getDrawable(Context context);
 
+        public Drawable getInvisibleDrawable(Context context) {
+            return getDrawable(context);
+        }
+
         @Override
         public int hashCode() {
             return Icon.class.hashCode();
@@ -437,6 +442,11 @@ public abstract class QSTile<TState extends State> implements Listenable {
         public Drawable getDrawable(Context context) {
             return mDrawable;
         }
+
+        @Override
+        public Drawable getInvisibleDrawable(Context context) {
+            return mDrawable;
+        }
     }
 
     public static class ResourceIcon extends Icon {
@@ -463,6 +473,11 @@ public abstract class QSTile<TState extends State> implements Listenable {
         }
 
         @Override
+        public Drawable getInvisibleDrawable(Context context) {
+            return context.getDrawable(mResId);
+        }
+
+        @Override
         public boolean equals(Object o) {
             return o instanceof ResourceIcon && ((ResourceIcon) o).mResId == mResId;
         }
@@ -474,14 +489,17 @@ public abstract class QSTile<TState extends State> implements Listenable {
     }
 
     protected class AnimationIcon extends ResourceIcon {
-        public AnimationIcon(int resId) {
-            super(resId);
+        private final int mAnimatedResId;
+
+        public AnimationIcon(int resId, int staticResId) {
+            super(staticResId);
+            mAnimatedResId = resId;
         }
 
         @Override
         public Drawable getDrawable(Context context) {
             // workaround: get a clean state for every new AVD
-            return context.getDrawable(mResId).getConstantState().newDrawable();
+            return context.getDrawable(mAnimatedResId).getConstantState().newDrawable();
         }
     }
 
index f35aacf..9e40cfd 100644 (file)
@@ -48,7 +48,7 @@ public class QSTileBaseView extends LinearLayout {
 
         // Default to Quick Tile padding, and QSTileView will specify its own padding.
         int padding = context.getResources().getDimensionPixelSize(R.dimen.qs_quick_tile_padding);
-        setPadding(padding, padding, padding, padding);
+        setPadding(0, padding, 0, padding);
         setClipChildren(false);
         setClipToPadding(false);
     }
@@ -113,7 +113,7 @@ public class QSTileBaseView extends LinearLayout {
         setContentDescription(state.contentDescription);
     }
 
-    View getIcon() {
+    public QSIconView getIcon() {
         return mIcon;
     }
 
index 4408dbf..f8a57d0 100644 (file)
@@ -24,6 +24,10 @@ import android.view.View;
 import android.widget.LinearLayout;
 import android.widget.Space;
 import com.android.systemui.R;
+import com.android.systemui.qs.QSTile.SignalState;
+import com.android.systemui.qs.QSTile.State;
+import com.android.systemui.tuner.TunerService;
+import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -33,6 +37,8 @@ import java.util.Collection;
  */
 public class QuickQSPanel extends QSPanel {
 
+    public static final String NUM_QUICK_TILES = "sysui_qqs_count";
+
     private int mMaxTiles;
     private QSPanel mFullPanel;
     private View mHeader;
@@ -50,6 +56,18 @@ public class QuickQSPanel extends QSPanel {
     }
 
     @Override
+    protected void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        TunerService.get(mContext).addTunable(mNumTiles, NUM_QUICK_TILES);
+    }
+
+    @Override
+    protected void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        TunerService.get(mContext).removeTunable(mNumTiles);
+    }
+
+    @Override
     protected void createCustomizePanel() {
         // No customizing from the header.
     }
@@ -60,6 +78,19 @@ public class QuickQSPanel extends QSPanel {
     }
 
     @Override
+    protected void drawTile(TileRecord r, State state) {
+        if (state instanceof SignalState) {
+            State copy = r.tile.newTileState();
+            state.copyTo(copy);
+            // No activity shown in the quick panel.
+            ((SignalState) copy).activityIn = false;
+            ((SignalState) copy).activityOut = false;
+            state = copy;
+        }
+        super.drawTile(r, state);
+    }
+
+    @Override
     protected void showDetail(boolean show, Record r) {
         // Do nothing, will be handled by the QSPanel.
     }
@@ -71,6 +102,7 @@ public class QuickQSPanel extends QSPanel {
 
     public void setMaxTiles(int maxTiles) {
         mMaxTiles = maxTiles;
+        setTiles(mHost.getTiles());
     }
 
     @Override
@@ -99,6 +131,17 @@ public class QuickQSPanel extends QSPanel {
         super.setTiles(quickTiles);
     }
 
+    private final Tunable mNumTiles = new Tunable() {
+        @Override
+        public void onTuningChanged(String key, String newValue) {
+            setMaxTiles(getNumQuickTiles(mContext));
+        }
+    };
+
+    public static int getNumQuickTiles(Context context) {
+        return TunerService.get(context).getValue(NUM_QUICK_TILES, 5);
+    }
+
     private static class HeaderTileLayout extends LinearLayout implements QSTileLayout {
 
         private final Space mEndSpacer;
index 225c10f..5e02428 100644 (file)
@@ -87,6 +87,7 @@ public class QSCustomizer extends LinearLayout implements OnMenuItemClickListene
         mToolbar.setOnMenuItemClickListener(this);
         mToolbar.getMenu().add(Menu.NONE, MENU_RESET, 0,
                 mContext.getString(com.android.internal.R.string.reset));
+        mToolbar.setTitle(R.string.qs_edit);
 
         mRecyclerView = (RecyclerView) findViewById(android.R.id.list);
         mTileAdapter = new TileAdapter(getContext());
index d1953b1..d9b3b3f 100644 (file)
@@ -25,7 +25,6 @@ import android.support.v7.widget.RecyclerView.State;
 import android.support.v7.widget.RecyclerView.ViewHolder;
 import android.support.v7.widget.helper.ItemTouchHelper;
 import android.view.LayoutInflater;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.FrameLayout;
@@ -172,6 +171,7 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
             if (itemView instanceof FrameLayout) {
                 mTileView = (QSTileView) ((FrameLayout) itemView).getChildAt(0);
                 mTileView.setBackground(null);
+                mTileView.getIcon().disableAnimation();
             }
         }
 
@@ -276,9 +276,6 @@ public class TileAdapter extends RecyclerView.Adapter<Holder> implements TileSta
                     return false;
                 }
             }
-            if (target.getItemViewType() == TYPE_EDIT && from < mDividerIndex) {
-                to++;
-            }
             move(from, to, mTiles);
             mDividerIndex = mTiles.indexOf(null);
             notifyItemMoved(from, to);
index aa85f78..d95d3ef 100644 (file)
@@ -28,8 +28,6 @@ import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.Looper;
 import android.service.quicksettings.TileService;
-import com.android.systemui.Prefs;
-import com.android.systemui.Prefs.Key;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.DrawableIcon;
@@ -57,10 +55,8 @@ public class TileQueryHelper {
     }
 
     private void addSystemTiles(QSTileHost host) {
-        boolean hasColorMod = Prefs.getBoolean(host.getContext(), Key.QS_NIGHT_ADDED, false)
-                && TunerService.isTunerEnabled(host.getContext());
         String possible = mContext.getString(R.string.quick_settings_tiles_default)
-                + ",hotspot,inversion,saver,work,cast" + (hasColorMod ? ",night" : "");
+                + ",hotspot,inversion,saver,work,cast,night";
         String[] possibleTiles = possible.split(",");
         final Handler qsHandler = new Handler(host.getLooper());
         final Handler mainHandler = new Handler(Looper.getMainLooper());
index f0860fe..89f1985 100644 (file)
@@ -33,9 +33,11 @@ import com.android.systemui.qs.QSTile;
 /** Quick settings tile: Airplane mode **/
 public class AirplaneModeTile extends QSTile<QSTile.BooleanState> {
     private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_signal_airplane_enable_animation);
+            new AnimationIcon(R.drawable.ic_signal_airplane_enable_animation,
+                    R.drawable.ic_signal_airplane_disable);
     private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_signal_airplane_disable_animation);
+            new AnimationIcon(R.drawable.ic_signal_airplane_disable_animation,
+                    R.drawable.ic_signal_airplane_enable);
     private final GlobalSetting mSetting;
 
     private boolean mListening;
index 39d1447..2e87525 100644 (file)
@@ -172,6 +172,7 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
         }
 
         private void postBindView() {
+            if (mCurrentView == null) return;
             mCurrentView.post(new Runnable() {
                 @Override
                 public void run() {
@@ -181,6 +182,9 @@ public class BatteryTile extends QSTile<QSTile.State> implements BatteryControll
         }
 
         private void bindView() {
+            if (mCurrentView == null) {
+                return;
+            }
             mDrawable.onBatteryLevelChanged(100, false, false);
             mDrawable.onPowerSaveChanged(true);
             mDrawable.disableShowPercent();
index 42ce69c..a608316 100644 (file)
@@ -30,9 +30,11 @@ import com.android.systemui.qs.SecureSetting;
 public class ColorInversionTile extends QSTile<QSTile.BooleanState> {
 
     private final AnimationIcon mEnable
-            = new AnimationIcon(R.drawable.ic_invert_colors_enable_animation);
+            = new AnimationIcon(R.drawable.ic_invert_colors_enable_animation,
+            R.drawable.ic_invert_colors_disable);
     private final AnimationIcon mDisable
-            = new AnimationIcon(R.drawable.ic_invert_colors_disable_animation);
+            = new AnimationIcon(R.drawable.ic_invert_colors_disable_animation,
+            R.drawable.ic_invert_colors_enable);
     private final SecureSetting mSetting;
 
     private boolean mListening;
index 8982b3e..8b22868 100644 (file)
@@ -56,9 +56,11 @@ public class DndTile extends QSTile<QSTile.BooleanState> {
             ResourceIcon.get(R.drawable.ic_qs_dnd_on_total_silence);
 
     private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_dnd_disable_animation);
+            new AnimationIcon(R.drawable.ic_dnd_disable_animation,
+                    R.drawable.ic_qs_dnd_off);
     private final AnimationIcon mDisableTotalSilence =
-            new AnimationIcon(R.drawable.ic_dnd_total_silence_disable_animation);
+            new AnimationIcon(R.drawable.ic_dnd_total_silence_disable_animation,
+                    R.drawable.ic_qs_dnd_off);
 
     private final ZenModeController mController;
     private final DndDetailAdapter mDetailAdapter;
index 12c8c44..a01a9a5 100644 (file)
@@ -33,9 +33,11 @@ public class FlashlightTile extends QSTile<QSTile.BooleanState> implements
         FlashlightController.FlashlightListener {
 
     private final AnimationIcon mEnable
-            = new AnimationIcon(R.drawable.ic_signal_flashlight_enable_animation);
+            = new AnimationIcon(R.drawable.ic_signal_flashlight_enable_animation,
+            R.drawable.ic_signal_flashlight_disable);
     private final AnimationIcon mDisable
-            = new AnimationIcon(R.drawable.ic_signal_flashlight_disable_animation);
+            = new AnimationIcon(R.drawable.ic_signal_flashlight_disable_animation,
+            R.drawable.ic_signal_flashlight_enable);
     private final FlashlightController mFlashlightController;
 
     public FlashlightTile(Host host) {
index ad1c7a0..da93120 100644 (file)
@@ -29,9 +29,11 @@ import com.android.systemui.statusbar.policy.HotspotController;
 /** Quick settings tile: Hotspot **/
 public class HotspotTile extends QSTile<QSTile.BooleanState> {
     private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_hotspot_enable_animation);
+            new AnimationIcon(R.drawable.ic_hotspot_enable_animation,
+                    R.drawable.ic_hotspot_disable);
     private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_hotspot_disable_animation);
+            new AnimationIcon(R.drawable.ic_hotspot_disable_animation,
+                    R.drawable.ic_hotspot_enable);
     private final HotspotController mController;
     private final Callback mCallback = new Callback();
 
index 6533252..b1d1c77 100644 (file)
@@ -32,9 +32,11 @@ import com.android.systemui.statusbar.policy.LocationController.LocationSettings
 public class LocationTile extends QSTile<QSTile.BooleanState> {
 
     private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_signal_location_enable_animation);
+            new AnimationIcon(R.drawable.ic_signal_location_enable_animation,
+                    R.drawable.ic_signal_location_disable);
     private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_signal_location_disable_animation);
+            new AnimationIcon(R.drawable.ic_signal_location_disable_animation,
+                    R.drawable.ic_signal_location_enable);
 
     private final LocationController mController;
     private final KeyguardMonitor mKeyguard;
index b267ccd..d80ca10 100644 (file)
@@ -31,14 +31,18 @@ import com.android.systemui.statusbar.policy.RotationLockController.RotationLock
 /** Quick settings tile: Rotation **/
 public class RotationLockTile extends QSTile<QSTile.BooleanState> {
     private final AnimationIcon mPortraitToAuto
-            = new AnimationIcon(R.drawable.ic_portrait_to_auto_rotate_animation);
+            = new AnimationIcon(R.drawable.ic_portrait_to_auto_rotate_animation,
+            R.drawable.ic_portrait_from_auto_rotate);
     private final AnimationIcon mAutoToPortrait
-            = new AnimationIcon(R.drawable.ic_portrait_from_auto_rotate_animation);
+            = new AnimationIcon(R.drawable.ic_portrait_from_auto_rotate_animation,
+            R.drawable.ic_portrait_to_auto_rotate);
 
     private final AnimationIcon mLandscapeToAuto
-            = new AnimationIcon(R.drawable.ic_landscape_to_auto_rotate_animation);
+            = new AnimationIcon(R.drawable.ic_landscape_to_auto_rotate_animation,
+            R.drawable.ic_landscape_from_auto_rotate);
     private final AnimationIcon mAutoToLandscape
-            = new AnimationIcon(R.drawable.ic_landscape_from_auto_rotate_animation);
+            = new AnimationIcon(R.drawable.ic_landscape_from_auto_rotate_animation,
+            R.drawable.ic_landscape_to_auto_rotate);
 
     private final RotationLockController mController;
 
index 003e9c1..421a2cf 100644 (file)
@@ -28,9 +28,11 @@ import com.android.systemui.statusbar.phone.ManagedProfileController;
 public class WorkModeTile extends QSTile<QSTile.BooleanState> implements
         ManagedProfileController.Callback {
     private final AnimationIcon mEnable =
-            new AnimationIcon(R.drawable.ic_signal_workmode_enable_animation);
+            new AnimationIcon(R.drawable.ic_signal_workmode_enable_animation,
+                    R.drawable.ic_signal_workmode_disable);
     private final AnimationIcon mDisable =
-            new AnimationIcon(R.drawable.ic_signal_workmode_disable_animation);
+            new AnimationIcon(R.drawable.ic_signal_workmode_disable_animation,
+                    R.drawable.ic_signal_workmode_enable);
 
     private final ManagedProfileController mProfileController;
 
index f5ae351..54bf68b 100644 (file)
@@ -513,8 +513,9 @@ public class Recents extends SystemUI
      * Handle Recents activity visibility changed.
      */
     public final void onBusEvent(final RecentsVisibilityChangedEvent event) {
-        int processUser = event.systemServicesProxy.getProcessUser();
-        if (event.systemServicesProxy.isSystemUser(processUser)) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        int processUser = ssp.getProcessUser();
+        if (ssp.isSystemUser(processUser)) {
             mImpl.onVisibilityChanged(event.applicationContext, event.visible);
         } else {
             postToSystemUser(new Runnable() {
index c41098f..cd1a27f 100644 (file)
@@ -43,6 +43,7 @@ import com.android.systemui.R;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.AppWidgetProviderChangedEvent;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.DebugFlagsChangedEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
@@ -54,7 +55,7 @@ import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent;
 import com.android.systemui.recents.events.activity.ShowHistoryEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.component.ScreenPinningRequestEvent;
@@ -96,6 +97,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
     private long mLastTabKeyEventTime;
     private boolean mFinishedOnStartup;
     private boolean mIgnoreAltTabRelease;
+    private boolean mIsVisible;
 
     // Top level views
     private RecentsView mRecentsView;
@@ -107,7 +109,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
     private RecentsAppWidgetHostView mSearchWidgetHostView;
 
     // Runnables to finish the Recents activity
-    private FinishRecentsRunnable mFinishLaunchHomeRunnable;
+    private Intent mHomeIntent;
 
     // The trigger to automatically launch the current task
     private int mFocusTimerDuration;
@@ -119,7 +121,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
      * last activity launch state. Generally we always launch home when we exit Recents rather than
      * just finishing the activity since we don't know what is behind Recents in the task stack.
      */
-    class FinishRecentsRunnable implements Runnable {
+    class LaunchHomeRunnable implements Runnable {
 
         Intent mLaunchIntent;
         ActivityOptions mOpts;
@@ -127,7 +129,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
         /**
          * Creates a finish runnable that starts the specified intent.
          */
-        public FinishRecentsRunnable(Intent launchIntent, ActivityOptions opts) {
+        public LaunchHomeRunnable(Intent launchIntent, ActivityOptions opts) {
             mLaunchIntent = launchIntent;
             mOpts = opts;
         }
@@ -173,59 +175,6 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
         }
     };
 
-    /** Updates the set of recent tasks */
-    void updateRecentsTasks() {
-        // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
-        // reconstructing the task stack
-        RecentsTaskLoader loader = Recents.getTaskLoader();
-        RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
-        if (plan == null) {
-            plan = loader.createLoadPlan(this);
-        }
-
-        // Start loading tasks according to the load plan
-        RecentsConfiguration config = Recents.getConfiguration();
-        RecentsActivityLaunchState launchState = config.getLaunchState();
-        if (!plan.hasTasks()) {
-            loader.preloadTasks(plan, -1, launchState.launchedFromHome);
-        }
-        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
-        loadOpts.runningTaskId = launchState.launchedToTaskId;
-        loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
-        loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
-        loader.loadTasks(this, plan, loadOpts);
-
-        TaskStack stack = plan.getTaskStack();
-        mRecentsView.setTaskStack(stack);
-
-        // Animate the SystemUI scrims into view
-        Task launchTarget = stack.getLaunchTarget();
-        int taskCount = stack.getTaskCount();
-        int launchTaskIndexInStack = launchTarget != null
-                ? stack.indexOfStackTask(launchTarget)
-                : 0;
-        boolean hasNavBarScrim = (taskCount > 0) && !config.hasTransposedNavBar;
-        boolean animateNavBarScrim = !launchState.launchedWhileDocking;
-        mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
-
-        // Keep track of whether we launched from the nav bar button or via alt-tab
-        if (launchState.launchedWithAltTab) {
-            MetricsLogger.count(this, "overview_trigger_alttab", 1);
-        } else {
-            MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
-        }
-        // Keep track of whether we launched from an app or from home
-        if (launchState.launchedFromAppWithThumbnail) {
-            MetricsLogger.count(this, "overview_source_app", 1);
-            // If from an app, track the stack index of the app in the stack (for affiliated tasks)
-            MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
-        } else {
-            MetricsLogger.count(this, "overview_source_home", 1);
-        }
-        // Keep track of the total stack task count
-        MetricsLogger.histogram(this, "overview_task_count", taskCount);
-    }
-
     /**
      * Dismisses the history view back into the stack view.
      */
@@ -294,12 +243,8 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
     void dismissRecentsToHome(boolean animateTaskViews, ActivityOptions overrideAnimation) {
         DismissRecentsToHomeAnimationStarted dismissEvent =
                 new DismissRecentsToHomeAnimationStarted(animateTaskViews);
-        if (overrideAnimation != null) {
-            dismissEvent.addPostAnimationCallback(new FinishRecentsRunnable(
-                    mFinishLaunchHomeRunnable.mLaunchIntent, overrideAnimation));
-        } else {
-            dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
-        }
+        dismissEvent.addPostAnimationCallback(new LaunchHomeRunnable(mHomeIntent,
+                overrideAnimation));
         dismissEvent.addPostAnimationCallback(new Runnable() {
             @Override
             public void run() {
@@ -348,6 +293,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
 
         // Set the Recents layout
         setContentView(R.layout.recents);
+        takeKeyEvents(true);
         mRecentsView = (RecentsView) findViewById(R.id.recents_view);
         mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE |
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
@@ -365,11 +311,10 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
         });
 
         // Create the home intent runnable
-        Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
-        homeIntent.addCategory(Intent.CATEGORY_HOME);
-        homeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
+        mHomeIntent = new Intent(Intent.ACTION_MAIN, null);
+        mHomeIntent.addCategory(Intent.CATEGORY_HOME);
+        mHomeIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
                 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
-        mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent, null);
 
         // Bind the search app widget when we first start up
         if (RecentsDebugFlags.Static.EnableSearchBar) {
@@ -386,82 +331,127 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
     }
 
     @Override
-    protected void onNewIntent(Intent intent) {
-        super.onNewIntent(intent);
-        setIntent(intent);
+    protected void onStart() {
+        super.onStart();
+
+        // Notify that recents is now visible
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
+        MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
     }
 
     @Override
-    protected void onStart() {
-        super.onStart();
+    public void onEnterAnimationComplete() {
+        super.onEnterAnimationComplete();
+        EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+    }
 
-        // Update the recent tasks
-        updateRecentsTasks();
+    @Override
+    protected void onResume() {
+        super.onResume();
+
+        // If the Recents component has preloaded a load plan, then use that to prevent
+        // reconstructing the task stack
+        RecentsTaskLoader loader = Recents.getTaskLoader();
+        RecentsTaskLoadPlan loadPlan = RecentsImpl.consumeInstanceLoadPlan();
+        if (loadPlan == null) {
+            loadPlan = loader.createLoadPlan(this);
+        }
+
+        // Start loading tasks according to the load plan
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        if (!loadPlan.hasTasks()) {
+            loader.preloadTasks(loadPlan, -1, launchState.launchedFromHome);
+        }
+
+        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+        loadOpts.runningTaskId = launchState.launchedToTaskId;
+        loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+        loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+        loader.loadTasks(this, loadPlan, loadOpts);
+        TaskStack stack = loadPlan.getTaskStack();
+        mRecentsView.onResume(mIsVisible, stack);
+
+        // Animate the SystemUI scrims into view
+        Task launchTarget = stack.getLaunchTarget();
+        int taskCount = stack.getTaskCount();
+        int launchTaskIndexInStack = launchTarget != null
+                ? stack.indexOfStackTask(launchTarget)
+                : 0;
+        boolean hasNavBarScrim = (taskCount > 0) && !config.hasTransposedNavBar;
+        boolean animateNavBarScrim = !launchState.launchedWhileDocking;
+        mScrimViews.prepareEnterRecentsAnimation(hasNavBarScrim, animateNavBarScrim);
 
         // If this is a new instance from a configuration change, then we have to manually trigger
         // the enter animation state, or if recents was relaunched by AM, without going through
         // the normal mechanisms
-        RecentsConfiguration config = Recents.getConfiguration();
-        RecentsActivityLaunchState launchState = config.getLaunchState();
         boolean wasLaunchedByAm = !launchState.launchedFromHome &&
-                !launchState.launchedFromAppWithThumbnail;
+                !launchState.launchedFromApp;
         if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
             EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
         }
 
-        // Notify that recents is now visible
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
-
-        MetricsLogger.visible(this, MetricsEvent.OVERVIEW_ACTIVITY);
-
         mRecentsView.getViewTreeObserver().addOnPreDrawListener(
                 new ViewTreeObserver.OnPreDrawListener() {
 
-            @Override
-            public boolean onPreDraw() {
-                mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
-                EventBus.getDefault().post(new RecentsDrawnEvent());
-                return true;
-            }
-        });
-    }
+                    @Override
+                    public boolean onPreDraw() {
+                        mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
+                        EventBus.getDefault().post(new RecentsDrawnEvent());
+                        return true;
+                    }
+                });
 
-    @Override
-    public void onEnterAnimationComplete() {
-        super.onEnterAnimationComplete();
-        EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
+        // Keep track of whether we launched from the nav bar button or via alt-tab
+        if (launchState.launchedWithAltTab) {
+            MetricsLogger.count(this, "overview_trigger_alttab", 1);
+        } else {
+            MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
+        }
+
+        // Keep track of whether we launched from an app or from home
+        if (launchState.launchedFromApp) {
+            MetricsLogger.count(this, "overview_source_app", 1);
+            // If from an app, track the stack index of the app in the stack (for affiliated tasks)
+            MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
+        } else {
+            MetricsLogger.count(this, "overview_source_home", 1);
+        }
+
+        // Keep track of the total stack task count
+        MetricsLogger.histogram(this, "overview_task_count", taskCount);
+
+        // After we have resumed, set the visible state until the next onStop() call
+        mIsVisible = true;
     }
 
     @Override
     protected void onPause() {
         super.onPause();
 
-        // Stop the fast-toggle dozer
+        mIgnoreAltTabRelease = false;
         mIterateTrigger.stopDozing();
+
+        // Workaround for b/22542869, if the RecentsActivity is started again, but without going
+        // through SystemUI, we need to reset the config launch flags to ensure that we do not
+        // wait on the system to send a signal that was never queued.
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
+        launchState.reset();
     }
 
     @Override
     protected void onStop() {
         super.onStop();
 
-        // Reset some states
-        mIgnoreAltTabRelease = false;
+        // Only hide the history if Recents is completely hidden
         if (RecentsDebugFlags.Static.EnableHistory && mRecentsView.isHistoryVisible()) {
             EventBus.getDefault().send(new HideHistoryEvent(false /* animate */));
         }
 
         // Notify that recents is now hidden
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
-
-        // Workaround for b/22542869, if the RecentsActivity is started again, but without going
-        // through SystemUI, we need to reset the config launch flags to ensure that we do not
-        // wait on the system to send a signal that was never queued.
-        RecentsConfiguration config = Recents.getConfiguration();
-        RecentsActivityLaunchState launchState = config.getLaunchState();
-        launchState.reset();
-
+        mIsVisible = false;
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
         MetricsLogger.hidden(this, MetricsEvent.OVERVIEW_ACTIVITY);
     }
 
@@ -528,16 +518,23 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
     @Override
     public void onMultiWindowChanged(boolean inMultiWindow) {
         super.onMultiWindowChanged(inMultiWindow);
+        EventBus.getDefault().send(new ConfigurationChangedEvent());
+
+        // Reload the task stack completely
+        RecentsConfiguration config = Recents.getConfiguration();
+        RecentsActivityLaunchState launchState = config.getLaunchState();
         RecentsTaskLoader loader = Recents.getTaskLoader();
-        RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
-        launchOpts.loadIcons = false;
-        launchOpts.loadThumbnails = false;
-        launchOpts.onlyLoadForCache = true;
         RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
-        loader.preloadTasks(loadPlan, -1, false);
-        loader.loadTasks(this, loadPlan, launchOpts);
-        EventBus.getDefault().send(new TaskStackUpdatedEvent(loadPlan.getTaskStack(),
-                inMultiWindow));
+        loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
+
+        RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
+        loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+        loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
+        loader.loadTasks(this, loadPlan, loadOpts);
+
+        mRecentsView.onResume(mIsVisible, loadPlan.getTaskStack());
+
+        EventBus.getDefault().send(new MultiWindowStateChangedEvent(inMultiWindow));
     }
 
     @Override
@@ -636,7 +633,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD
             // Focus the next task
             EventBus.getDefault().send(new FocusNextTaskViewEvent(timerIndicatorDuration));
 
-            MetricsLogger.action(this, MetricsEvent.OVERVIEW_PAGE);
+            MetricsLogger.action(this, MetricsEvent.ACTION_OVERVIEW_PAGE);
         }
     }
 
index aa1437b..ec4820a 100644 (file)
@@ -28,7 +28,8 @@ package com.android.systemui.recents;
 public class RecentsActivityLaunchState {
 
     public boolean launchedWithAltTab;
-    public boolean launchedFromAppWithThumbnail;
+    public boolean launchedFromApp;
+    public boolean launchedFromAppDocked;
     public boolean launchedFromHome;
     public boolean launchedFromSearchHome;
     public boolean launchedReuseTaskStackViews;
@@ -42,7 +43,8 @@ public class RecentsActivityLaunchState {
     public void reset() {
         launchedFromHome = false;
         launchedFromSearchHome = false;
-        launchedFromAppWithThumbnail = false;
+        launchedFromApp = false;
+        launchedFromAppDocked = false;
         launchedToTaskId = -1;
         launchedWithAltTab = false;
         launchedHasConfigurationChanged = false;
@@ -67,7 +69,7 @@ public class RecentsActivityLaunchState {
     public int getInitialFocusTaskIndex(int numTasks) {
         RecentsDebugFlags debugFlags = Recents.getDebugFlags();
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
-        if (launchedFromAppWithThumbnail) {
+        if (launchedFromApp) {
             if (!launchState.launchedWithAltTab && debugFlags.isFastToggleRecentsEnabled()) {
                 // If fast toggling, focus the front most task so that the next tap will focus the
                 // N-1 task
index 9e43bb4..eec0411 100644 (file)
@@ -69,7 +69,6 @@ public class RecentsConfiguration {
     public final int smallestWidth;
 
     /** Misc **/
-    public boolean useHardwareLayers;
     public boolean fakeShadows;
     public int svelteLevel;
     public int searchBarSpaceHeightPx;
@@ -80,7 +79,6 @@ public class RecentsConfiguration {
         SystemServicesProxy ssp = Recents.getSystemServices();
         Context appContext = context.getApplicationContext();
         Resources res = appContext.getResources();
-        useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
         fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
         svelteLevel = res.getInteger(R.integer.recents_svelte_level);
 
index cd64323..6feda81 100644 (file)
@@ -39,8 +39,8 @@ public class RecentsDebugFlags implements TunerService.Tunable {
         public static final boolean EnableAffiliatedTaskGroups = true;
         // Enables the history
         public static final boolean EnableHistory = false;
-        // Overrides the Tuner flags and enables the fast toggle and timeout
-        public static final boolean EnableFastToggleTimeoutOverride = true;
+        // Overrides the Tuner flags and enables the timeout
+        private static final boolean EnableFastToggleTimeout = false;
 
         // Enables us to create mock recents tasks
         public static final boolean EnableMockTasks = false;
@@ -54,9 +54,9 @@ public class RecentsDebugFlags implements TunerService.Tunable {
         public static final int MockTaskGroupsTaskCount = 12;
     }
 
-    private static final String KEY_DISABLE_FAST_TOGGLE = "overview_disable_fast_toggle_via_button";
+    private static final String KEY_ENABLE_PAGING = "overview_enable_paging";
 
-    private boolean mDisableFastToggleRecents;
+    private boolean mEnablePaging;
 
     /**
      * We read the prefs once when we start the activity, then update them as the tuner changes
@@ -65,31 +65,32 @@ public class RecentsDebugFlags implements TunerService.Tunable {
     public RecentsDebugFlags(Context context) {
         // Register all our flags, this will also call onTuningChanged() for each key, which will
         // initialize the current state of each flag
-        TunerService.get(context).addTunable(this, KEY_DISABLE_FAST_TOGGLE);
+        TunerService.get(context).addTunable(this, KEY_ENABLE_PAGING);
     }
 
     /**
      * @return whether we are enabling fast toggling.
      */
     public boolean isFastToggleRecentsEnabled() {
-        // These checks EnableFastToggleTimeoutOverride
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (mDisableFastToggleRecents || ssp.hasFreeformWorkspaceSupport() || ssp.hasDockedTask()
-                || ssp.isTouchExplorationEnabled()) {
+        if (ssp.hasFreeformWorkspaceSupport() || ssp.isTouchExplorationEnabled()) {
             return false;
         }
-        if (Static.EnableFastToggleTimeoutOverride) {
-            return true;
-        }
-        return true;
+        return Static.EnableFastToggleTimeout;
+    }
+
+    /**
+     * @return whether we are enabling paging.
+     */
+    public boolean isPagingEnabled() {
+        return mEnablePaging;
     }
 
     @Override
     public void onTuningChanged(String key, String newValue) {
         switch (key) {
-            case KEY_DISABLE_FAST_TOGGLE:
-                mDisableFastToggleRecents = (newValue != null) &&
-                        (Integer.parseInt(newValue) != 0);
+            case KEY_ENABLE_PAGING:
+                mEnablePaging = (newValue != null) && (Integer.parseInt(newValue) != 0);
                 break;
         }
         EventBus.getDefault().send(new DebugFlagsChangedEvent());
index 28b2fae..ac23f44 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.systemui.recents;
 
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ITaskStackListener;
@@ -64,8 +66,10 @@ import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskGrouping;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.recents.tv.views.TaskStackHorizontalGridView;
 import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
 import com.android.systemui.recents.views.TaskStackView;
+import com.android.systemui.recents.views.TaskStackViewScroller;
 import com.android.systemui.recents.views.TaskViewHeader;
 import com.android.systemui.recents.views.TaskViewTransform;
 import com.android.systemui.statusbar.BaseStatusBar;
@@ -74,8 +78,6 @@ import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 import java.util.ArrayList;
 
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-
 /**
  * An implementation of the Recents component for the current user.  For secondary users, this can
  * be called remotely from the system user.
@@ -98,6 +100,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
 
     //Used to store tv or non-tv activty for use in creating intents.
     private final String mRecentsIntentActivityName;
+
     /**
      * An implementation of ITaskStackListener, that allows us to listen for changes to the system
      * task stacks and update recents accordingly.
@@ -276,28 +279,24 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
         mTriggeredFromAltTab = triggeredFromAltTab;
         mDraggingInRecents = draggingInRecents;
         mLaunchedWhileDocking = launchedWhileDockingTask;
-        if (mFastAltTabTrigger.hasTriggered()) {
-            // We are calling this from the doze trigger, so just fall through to show Recents
-            mFastAltTabTrigger.resetTrigger();
+        if (mFastAltTabTrigger.isAsleep()) {
+            // Fast alt-tab duration has elapsed, fall through to showing Recents and reset
+            mFastAltTabTrigger.stopDozing();
         } else if (mFastAltTabTrigger.isDozing()) {
-            // We are dozing but haven't yet triggered, ignore this if this is not another alt-tab,
-            // otherwise, this is an additional tab (alt-tab*), which means that we should trigger
-            // immediately (fall through and disable the pending trigger)
-            // TODO: This is tricky, we need to handle the tab key, but Recents has not yet started
-            //       so we may actually additional signal to handle multiple quick tab cases.  The
-            //       severity of this is inversely proportional to the FAST_ALT_TAB_DELAY_MS
-            //       duration though
+            // Fast alt-tab duration has not elapsed.  If this is triggered by a different
+            // showRecents() call, then ignore that call for now.
+            // TODO: We can not handle quick tabs that happen between the initial showRecents() call
+            //       that started the activity and the activity starting up.  The severity of this
+            //       is inversely proportional to the FAST_ALT_TAB_DELAY_MS duration though.
             if (!triggeredFromAltTab) {
                 return;
             }
             mFastAltTabTrigger.stopDozing();
-        } else {
-            // Otherwise, the doze trigger is not running, and if this is an alt tab, we should
-            // start the trigger and then wait for the hide (or for it to elapse)
-            if (triggeredFromAltTab) {
-                mFastAltTabTrigger.startDozing();
-                return;
-            }
+        } else if (triggeredFromAltTab) {
+            // The fast alt-tab detector is not yet running, so start the trigger and wait for the
+            // hideRecents() call, or for the fast alt-tab duration to elapse
+            mFastAltTabTrigger.startDozing();
+            return;
         }
 
         try {
@@ -321,7 +320,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
 
             // Cancel the fast alt-tab trigger
             mFastAltTabTrigger.stopDozing();
-            mFastAltTabTrigger.resetTrigger();
             return;
         }
 
@@ -348,12 +346,14 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
             long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
 
             if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
+                RecentsDebugFlags debugFlags = Recents.getDebugFlags();
                 RecentsConfiguration config = Recents.getConfiguration();
                 RecentsActivityLaunchState launchState = config.getLaunchState();
                 if (!launchState.launchedWithAltTab) {
                     // If the user taps quickly
-                    if (ViewConfiguration.getDoubleTapMinTime() < elapsedTime &&
-                            elapsedTime < ViewConfiguration.getDoubleTapTimeout()) {
+                    if (!debugFlags.isPagingEnabled() ||
+                            (ViewConfiguration.getDoubleTapMinTime() < elapsedTime &&
+                                    elapsedTime < ViewConfiguration.getDoubleTapTimeout())) {
                         // Launch the next focused task
                         EventBus.getDefault().post(new LaunchNextTaskRequestEvent());
                     } else {
@@ -568,11 +568,14 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
 
         // Make sure we inform DividerView before we actually start the activity so we can change
         // the resize mode already.
-        EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
-        ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds);
-        showRecents(false /* triggeredFromAltTab */,
-                dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS, false /* animate */,
-                true /* reloadTasks*/);
+        if (ssp.moveTaskToDockedStack(topTaskId, stackCreateMode, initialBounds)) {
+            EventBus.getDefault().send(new DockingTopTaskEvent(dragMode));
+            showRecents(
+                    false /* triggeredFromAltTab */,
+                    dragMode == NavigationBarGestureHelper.DRAG_MODE_RECENTS,
+                    false /* animate */,
+                    true /* launchedWhileDockingTask*/);
+        }
     }
 
     /**
@@ -599,7 +602,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
                 com.android.internal.R.dimen.navigation_bar_width);
         mTaskBarHeight = res.getDimensionPixelSize(
                 R.dimen.recents_task_bar_height);
-        mDummyStackView = new TaskStackView(mContext, new TaskStack());
+        mDummyStackView = new TaskStackView(mContext);
         mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
                 null, false);
     }
@@ -612,8 +615,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
      *                               is not already bound (can be expensive)
      * @param stack the stack to initialize the stack layout with
      */
-    private void updateHeaderBarLayout(boolean tryAndBindSearchWidget,
-            TaskStack stack) {
+    private void updateHeaderBarLayout(boolean tryAndBindSearchWidget, TaskStack stack) {
         RecentsConfiguration config = Recents.getConfiguration();
         SystemServicesProxy ssp = Recents.getSystemServices();
         Rect systemInsets = new Rect();
@@ -637,14 +639,15 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
                 mSearchBarBounds, mTaskStackBounds);
 
         // Rebind the header bar and draw it for the transition
-        TaskStackLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
+        TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm();
         Rect taskStackBounds = new Rect(mTaskStackBounds);
-        algo.setSystemInsets(systemInsets);
+        stackLayout.setSystemInsets(systemInsets);
         if (stack != null) {
-            algo.initialize(taskStackBounds,
+            stackLayout.initialize(taskStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
+            mDummyStackView.setTasks(stack, false /* notifyStackChanges */);
         }
-        Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
+        Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds();
         if (!taskViewBounds.equals(mLastTaskViewBounds)) {
             mLastTaskViewBounds.set(taskViewBounds);
 
@@ -702,10 +705,8 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
         updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
 
         // Update the destination rect
-        mDummyStackView.updateLayoutForStack(stack);
         final Task toTask = new Task();
-        final TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
-                toTask);
+        final TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask);
         ForegroundThread.getHandler().postAtFrontOfQueue(new Runnable() {
             @Override
             public void run() {
@@ -751,17 +752,20 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
      * Creates the activity options for an app->recents transition.
      */
     private ActivityOptions getThumbnailTransitionActivityOptions(
-            ActivityManager.RunningTaskInfo topTask, TaskStack stack, TaskStackView stackView) {
+            ActivityManager.RunningTaskInfo topTask, TaskStackView stackView) {
         if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
             ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
-            stackView.getScroller().setStackScrollToInitialState();
-            ArrayList<Task> tasks = stack.getStackTasks();
+            ArrayList<Task> tasks = stackView.getStack().getStackTasks();
+            TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm();
+            TaskStackViewScroller stackScroller = stackView.getScroller();
+
+            stackView.updateToInitialState();
+
             for (int i = tasks.size() - 1; i >= 0; i--) {
                 Task task = tasks.get(i);
                 if (task.isFreeformTask()) {
-                    mTmpTransform = stackView.getStackAlgorithm()
-                            .getStackTransformScreenCoordinates(task,
-                                    stackView.getScroller().getStackScroll(), mTmpTransform, null);
+                    mTmpTransform = stackLayout.getStackTransformScreenCoordinates(task,
+                                    stackScroller.getStackScroll(), mTmpTransform, null);
                     Rect toTaskRect = new Rect();
                     mTmpTransform.rect.round(toTaskRect);
                     Bitmap thumbnail = getThumbnailBitmap(topTask, task, mTmpTransform);
@@ -775,8 +779,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
         } else {
             // Update the destination rect
             Task toTask = new Task();
-            TaskViewTransform toTransform = getThumbnailTransitionTransform(stack, stackView,
-                    toTask);
+            TaskViewTransform toTransform = getThumbnailTransitionTransform(stackView, toTask);
             RectF toTaskRect = toTransform.rect;
             Bitmap thumbnail = getThumbnailBitmap(topTask, toTask, toTransform);
             if (thumbnail != null) {
@@ -808,9 +811,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
     /**
      * Returns the transition rect for the given task id.
      */
-    private TaskViewTransform getThumbnailTransitionTransform(TaskStack stack,
-            TaskStackView stackView, Task runningTaskOut) {
+    private TaskViewTransform getThumbnailTransitionTransform(TaskStackView stackView,
+            Task runningTaskOut) {
         // Find the running task in the TaskStack
+        TaskStack stack = stackView.getStack();
         Task launchTask = stack.getLaunchTarget();
         if (launchTask != null) {
             runningTaskOut.copyFrom(launchTask);
@@ -821,7 +825,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
         }
 
         // Get the transform for the running task
-        stackView.getScroller().setStackScrollToInitialState();
+        stackView.updateToInitialState();
         mTmpTransform = stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
                 stackView.getScroller().getStackScroll(), mTmpTransform, null);
         return mTmpTransform;
@@ -849,6 +853,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
                     c.scale(toTransform.scale, toTransform.scale);
                     mHeaderBar.rebindToTask(toTask, false /* touchExplorationEnabled */,
                             disabledInSafeMode);
+                    mHeaderBar.setDimAlpha(toTransform.dimAlpha);
                     mHeaderBar.draw(c);
                     c.setBitmap(null);
                 }
@@ -881,7 +886,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
         updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
 
         // Prepare the dummy stack for the transition
-        mDummyStackView.updateLayoutForStack(stack);
         TaskStackLayoutAlgorithm.VisibilityReport stackVr =
                 mDummyStackView.computeStackVisibilityReport();
 
@@ -897,8 +901,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
 
         if (useThumbnailTransition) {
             // Try starting with a thumbnail transition
-            ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
-                    mDummyStackView);
+            ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, mDummyStackView);
             if (opts != null) {
                 startRecentsActivity(topTask, opts, false /* fromHome */,
                         false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
@@ -945,14 +948,15 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
      * Starts the recents activity.
      */
     private void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
-              ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
-              TaskStackLayoutAlgorithm.VisibilityReport vr) {
+                ActivityOptions opts, boolean fromHome, boolean fromSearchHome,
+                boolean fromThumbnail, TaskStackLayoutAlgorithm.VisibilityReport vr) {
         // Update the configuration based on the launch options
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         launchState.launchedFromHome = fromSearchHome || fromHome;
         launchState.launchedFromSearchHome = fromSearchHome;
-        launchState.launchedFromAppWithThumbnail = fromThumbnail;
+        launchState.launchedFromApp = fromThumbnail || mLaunchedWhileDocking;
+        launchState.launchedFromAppDocked = mLaunchedWhileDocking;
         launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
         launchState.launchedWithAltTab = mTriggeredFromAltTab;
         launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.
  * limitations under the License.
  */
 
-package android.hardware;
+package com.android.systemui.recents.events.activity;
 
-/** @hide */
-interface ICamera
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/ICamera.h
-     */
-    void disconnect();
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent when the Recents activity configuration has changed.
+ */
+public class ConfigurationChangedEvent extends EventBus.AnimatedEvent {
+    // Simple event
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/LaunchTvTaskEvent.java
new file mode 100644 (file)
index 0000000..04ca68f
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.events.activity;
+
+
+import android.graphics.Rect;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.tv.views.TaskCardView;
+
+public class LaunchTvTaskEvent extends EventBus.Event {
+
+    public final TaskCardView taskView;
+    public final Task task;
+    public final Rect targetTaskBounds;
+    public final int targetTaskStack;
+
+    public LaunchTvTaskEvent(TaskCardView taskView, Task task, Rect targetTaskBounds,
+            int targetTaskStack) {
+        this.taskView = taskView;
+        this.task = task;
+        this.targetTaskBounds = targetTaskBounds;
+        this.targetTaskStack = targetTaskStack;
+    }
+
+}
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2015 The Android Open Source Project
+ * Copyright (C) 2016 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.
  * limitations under the License.
  */
 
-package android.hardware;
+package com.android.systemui.recents.events.activity;
+
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.tv.views.TaskCardView;
 
 /**
- * Binder interface for the camera service proxy running in system_server.
- *
- * Keep in sync with frameworks/av/include/camera/ICameraServiceProxy.h
- *
- * @hide
+ * This event is sent following {@link LaunchTvTaskEvent} after the call to the system is made to
+ * start the task, only used on TV.
  */
-interface ICameraServiceProxy
-{
-    /**
-     * Ping the service proxy to update the valid users for the camera service.
-     */
-    oneway void pingForUserUpdate();
+public class LaunchTvTaskStartedEvent extends EventBus.AnimatedEvent {
+
+    public final TaskCardView taskView;
+
+    public LaunchTvTaskStartedEvent(TaskCardView taskView) {
+        this.taskView = taskView;
+    }
 
-    /**
-     * Update the status of a camera device
-     */
-     oneway void notifyCameraState(String cameraId, int newCameraState);
 }
  * limitations under the License.
  */
 
-package android.hardware.camera2.params;
+package com.android.systemui.recents.events.activity;
 
-/** @hide */
-parcelable OutputConfiguration;
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * This is sent by the activity whenever the multi-window state has changed.
+ */
+public class MultiWindowStateChangedEvent extends EventBus.Event {
+
+    public final boolean inMultiWindow;
+
+    public MultiWindowStateChangedEvent(boolean inMultiWindow) {
+        this.inMultiWindow = inMultiWindow;
+    }
+}
index 4140bcd..8843eb4 100644 (file)
@@ -19,21 +19,18 @@ package com.android.systemui.recents.events.component;
 import android.content.Context;
 
 import com.android.systemui.recents.events.EventBus;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 
 /**
- * This is sent when the visibility of the RecentsActivity for the current user changes.
+ * This is sent when the visibility of the RecentsActivity for the current user changes.  Handlers
+ * of this event should not alter the UI, as the activity may still be visible.
  */
 public class RecentsVisibilityChangedEvent extends EventBus.Event {
 
     public final Context applicationContext;
-    public final SystemServicesProxy systemServicesProxy;
     public final boolean visible;
 
-    public RecentsVisibilityChangedEvent(Context context, SystemServicesProxy systemServicesProxy,
-            boolean visible) {
+    public RecentsVisibilityChangedEvent(Context context, boolean visible) {
         this.applicationContext = context.getApplicationContext();
-        this.systemServicesProxy = systemServicesProxy;
         this.visible = visible;
     }
 }
index d7b9b9e..5eeda72 100644 (file)
@@ -161,7 +161,7 @@ public class RecentsHistoryAdapter extends RecyclerView.Adapter<RecentsHistoryAd
             ssp.startActivityFromRecents(v.getContext(), task.key.id, task.title,
                     ActivityOptions.makeBasic());
 
-            MetricsLogger.action(v.getContext(), MetricsEvent.OVERVIEW_SELECT,
+            MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
                     task.key.getComponent().toString());
         }
 
index 95aa10f..574ea03 100644 (file)
@@ -30,7 +30,7 @@ public class DozeTrigger {
     @ViewDebug.ExportedProperty(category="recents")
     boolean mIsDozing;
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mHasTriggered;
+    boolean mIsAsleep;
     @ViewDebug.ExportedProperty(category="recents")
     int mDozeDurationMilliseconds;
     Runnable mOnSleepRunnable;
@@ -40,7 +40,7 @@ public class DozeTrigger {
         @Override
         public void run() {
             mIsDozing = false;
-            mHasTriggered = true;
+            mIsAsleep = true;
             mOnSleepRunnable.run();
         }
     };
@@ -56,7 +56,7 @@ public class DozeTrigger {
      */
     public void startDozing() {
         forcePoke();
-        mHasTriggered = false;
+        mIsAsleep = false;
     }
 
     /**
@@ -65,6 +65,7 @@ public class DozeTrigger {
     public void stopDozing() {
         mHandler.removeCallbacks(mDozeRunnable);
         mIsDozing = false;
+        mIsAsleep = false;
     }
 
     /**
@@ -99,12 +100,7 @@ public class DozeTrigger {
     }
 
     /** Returns whether the trigger has fired at least once. */
-    public boolean hasTriggered() {
-        return mHasTriggered;
-    }
-
-    /** Resets the doze trigger state. */
-    public void resetTrigger() {
-        mHasTriggered = false;
+    public boolean isAsleep() {
+        return mIsAsleep;
     }
 }
index 4b29c29..532e796 100644 (file)
@@ -338,15 +338,18 @@ public class SystemServicesProxy {
     }
 
     /** Docks an already resumed task to the side of the screen. */
-    public void moveTaskToDockedStack(int taskId, int createMode, Rect initialBounds) {
-        if (mIam == null) return;
+    public boolean moveTaskToDockedStack(int taskId, int createMode, Rect initialBounds) {
+        if (mIam == null) {
+            return false;
+        }
 
         try {
-            mIam.moveTaskToDockedStack(taskId, createMode, true /* onTop */, false /* animate */,
-                    initialBounds);
+            return mIam.moveTaskToDockedStack(
+                    taskId, createMode, true /* onTop */, false /* animate */, initialBounds);
         } catch (RemoteException e) {
             e.printStackTrace();
         }
+        return false;
     }
 
     /** Returns the focused stack id. */
@@ -692,6 +695,37 @@ public class SystemServicesProxy {
     }
 
     /**
+     * Returns a banner used on TV for the specified Activity.
+     */
+    public Drawable getActivityBanner(ActivityInfo info) {
+        if (mPm == null) return null;
+
+        // If we are mocking, then return a mock banner
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            return new ColorDrawable(0xFF666666);
+        }
+
+        Drawable banner = info.loadBanner(mPm);
+        return banner;
+    }
+
+    /**
+     * Returns a logo used on TV for the specified Activity.
+     */
+    public Drawable getActivityLogo(ActivityInfo info) {
+        if (mPm == null) return null;
+
+        // If we are mocking, then return a mock logo
+        if (RecentsDebugFlags.Static.EnableMockTasks) {
+            return new ColorDrawable(0xFF666666);
+        }
+
+        Drawable logo = info.loadLogo(mPm);
+        return logo;
+    }
+
+
+    /**
      * Returns the given label for a user, badging if necessary.
      */
     private String getBadgedLabel(String label, int userId) {
index 6fef8a2..6ae07fc 100644 (file)
@@ -133,7 +133,6 @@ public class RecentsTaskLoadPlan {
         SparseIntArray affiliatedTaskCounts = new SparseIntArray();
         String dismissDescFormat = mContext.getString(
                 R.string.accessibility_recents_item_will_be_dismissed);
-        Formatter dismissDescFormatter = new Formatter();
         long lastStackActiveTime = Prefs.getLong(mContext,
                 Prefs.Key.OVERVIEW_LAST_STACK_TASK_ACTIVE_TIME, 0);
         if (RecentsDebugFlags.Static.EnableMockTasks) {
@@ -184,8 +183,7 @@ public class RecentsTaskLoadPlan {
             ActivityInfo info = loader.getAndUpdateActivityInfo(taskKey);
             String title = loader.getAndUpdateActivityTitle(taskKey, t.taskDescription);
             String contentDescription = loader.getAndUpdateContentDescription(taskKey, res);
-            String dismissDescription = dismissDescFormatter.format(dismissDescFormat,
-                    contentDescription).toString();
+            String dismissDescription = String.format(dismissDescFormat, contentDescription);
             Drawable icon = isStackTask
                     ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
                     : null;
@@ -214,8 +212,7 @@ public class RecentsTaskLoadPlan {
 
         // Initialize the stacks
         mStack = new TaskStack();
-        mStack.setTasks(allTasks, false /* notifyStackChanges */);
-        mStack.createAffiliatedGroupings(mContext);
+        mStack.setTasks(mContext, allTasks, false /* notifyStackChanges */);
     }
 
     /**
index e5d4f1b..b5a5949 100644 (file)
@@ -100,11 +100,7 @@ public class Task {
 
         @Override
         public String toString() {
-            return "Task.Key: " + id + ", "
-                    + "s: " + stackId + ", "
-                    + "u: " + userId + ", "
-                    + "lat: " + lastActiveTime + ", "
-                    + getComponent().getPackageName();
+            return "t" + id + ", s" + stackId + ", u" + userId;
         }
 
         private void updateHashCode() {
@@ -204,7 +200,9 @@ public class Task {
         this.isDockable = isDockable;
     }
 
-    /** Copies the other task. */
+    /**
+     * Copies the metadata from another task, but retains the current callbacks.
+     */
     public void copyFrom(Task o) {
         this.key = o.key;
         this.group = o.group;
@@ -300,11 +298,6 @@ public class Task {
 
     @Override
     public String toString() {
-        String groupAffiliation = "no group";
-        if (group != null) {
-            groupAffiliation = Integer.toString(group.affiliation);
-        }
-        return "Task (" + groupAffiliation + "): " + key +
-                " [" + super.toString() + "]";
+        return "[" + key.toString() + "] " + title;
     }
 }
index 1f91dce..4d1c552 100644 (file)
@@ -92,15 +92,6 @@ class FilteredTaskList {
         }
     }
 
-    /**
-     * Resets the task list, but does not remove the filter.
-     */
-    void reset() {
-        mTasks.clear();
-        mFilteredTasks.clear();
-        mTaskIndices.clear();
-    }
-
     /** Removes the task filter and returns the previous touch state */
     void removeFilter() {
         mFilter = null;
@@ -481,15 +472,6 @@ public class TaskStack {
         mCb = cb;
     }
 
-    /** Resets this TaskStack. */
-    public void reset() {
-        mCb = null;
-        mStackTaskList.reset();
-        mHistoryTaskList.reset();
-        mGroups.clear();
-        mAffinitiesGroups.clear();
-    }
-
     /**
      * Moves the given task to either the front of the freeform workspace or the stack.
      */
@@ -556,12 +538,12 @@ public class TaskStack {
      * @param tasks the new set of tasks to replace the current set.
      * @param notifyStackChanges whether or not to callback on specific changes to the list of tasks.
      */
-    public void setTasks(List<Task> tasks, boolean notifyStackChanges) {
+    public void setTasks(Context context, List<Task> tasks, boolean notifyStackChanges) {
         // Compute a has set for each of the tasks
         ArrayMap<Task.TaskKey, Task> currentTasksMap = createTaskKeyMapFromList(mRawTaskList);
         ArrayMap<Task.TaskKey, Task> newTasksMap = createTaskKeyMapFromList(tasks);
-
-        ArrayList<Task> newTasks = new ArrayList<>();
+        ArrayList<Task> addedTasks = new ArrayList<>();
+        ArrayList<Task> allTasks = new ArrayList<>();
 
         // Disable notifications if there are no callbacks
         if (mCb == null) {
@@ -570,10 +552,13 @@ public class TaskStack {
 
         // Remove any tasks that no longer exist
         int taskCount = mRawTaskList.size();
-        for (int i = 0; i < taskCount; i++) {
+        for (int i = taskCount - 1; i >= 0; i--) {
             Task task = mRawTaskList.get(i);
             if (!newTasksMap.containsKey(task.key)) {
                 if (notifyStackChanges) {
+                    // If we are notifying, then remove the task now, otherwise the raw task list
+                    // will be reset at the end of this method
+                    removeTask(task, AnimationProps.IMMEDIATE);
                     mCb.onStackTaskRemoved(this, task, i == (taskCount - 1), null,
                             AnimationProps.IMMEDIATE);
                 }
@@ -584,26 +569,28 @@ public class TaskStack {
         // Add any new tasks
         taskCount = tasks.size();
         for (int i = 0; i < taskCount; i++) {
-            Task task = tasks.get(i);
-            if (!currentTasksMap.containsKey(task.key)) {
-                if (notifyStackChanges) {
-                    mCb.onStackTaskAdded(this, task);
-                }
-                newTasks.add(task);
-            } else {
-                newTasks.add(currentTasksMap.get(task.key));
+            Task newTask = tasks.get(i);
+            Task currentTask = currentTasksMap.get(newTask.key);
+            if (currentTask == null && notifyStackChanges) {
+                addedTasks.add(newTask);
+            } else if (currentTask != null) {
+                // The current task has bound callbacks, so just copy the data from the new task
+                // state and add it back into the list
+                currentTask.copyFrom(newTask);
+                newTask = currentTask;
             }
+            allTasks.add(newTask);
         }
 
         // Sort all the tasks to ensure they are ordered correctly
-        Collections.sort(newTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
+        Collections.sort(allTasks, FREEFORM_LAST_ACTIVE_TIME_COMPARATOR);
 
         // Filter out the historical tasks from this new list
         ArrayList<Task> stackTasks = new ArrayList<>();
         ArrayList<Task> historyTasks = new ArrayList<>();
-        int newTaskCount = newTasks.size();
+        int newTaskCount = allTasks.size();
         for (int i = 0; i < newTaskCount; i++) {
-            Task task = newTasks.get(i);
+            Task task = allTasks.get(i);
             if (task.isHistorical) {
                 historyTasks.add(task);
             } else {
@@ -613,10 +600,16 @@ public class TaskStack {
 
         mStackTaskList.set(stackTasks);
         mHistoryTaskList.set(historyTasks);
-        mRawTaskList.clear();
-        mRawTaskList.addAll(newTasks);
-        mGroups.clear();
-        mAffinitiesGroups.clear();
+        mRawTaskList = allTasks;
+
+        // Only callback for the newly added tasks after this stack has been updated
+        int addedTaskCount = addedTasks.size();
+        for (int i = 0; i < addedTaskCount; i++) {
+            mCb.onStackTaskAdded(this, addedTasks.get(i));
+        }
+
+        // Update the affiliated groupings
+        createAffiliatedGroupings(context);
     }
 
     /**
@@ -779,9 +772,12 @@ public class TaskStack {
     }
 
     /**
-     * Temporary: This method will simulate affiliation groups by
+     * Temporary: This method will simulate affiliation groups
      */
-    public void createAffiliatedGroupings(Context context) {
+    void createAffiliatedGroupings(Context context) {
+        mGroups.clear();
+        mAffinitiesGroups.clear();
+
         if (RecentsDebugFlags.Static.EnableMockTaskGroups) {
             ArrayMap<Task.TaskKey, Task> taskMap = new ArrayMap<>();
             // Sort all tasks by increasing firstActiveTime of the task
@@ -926,13 +922,13 @@ public class TaskStack {
 
     @Override
     public String toString() {
-        String str = "Stack Tasks:\n";
+        String str = "Stack Tasks (" + mStackTaskList.size() + "):\n";
         for (Task t : mStackTaskList.getTasks()) {
-            str += "  " + t.toString() + "\n";
+            str += "    " + t.toString() + "\n";
         }
-        str += "Historical Tasks:\n";
+        str += "Historical Tasks(" + mHistoryTaskList.size() + "):\n";
         for (Task t : mHistoryTaskList.getTasks()) {
-            str += "  " + t.toString() + "\n";
+            str += "    " + t.toString() + "\n";
         }
         return str;
     }
index 0c48cf7..dae522f 100644 (file)
@@ -40,7 +40,6 @@ import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationC
 import com.android.systemui.recents.events.activity.EnterRecentsWindowLastAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.HideRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
 import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
@@ -60,6 +59,8 @@ import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.tv.pip.PipManager;
 
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
 
 /**
  * The main TV recents activity started by the RecentsImpl.
@@ -157,11 +158,13 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
 
 
         mRecentsView.setTaskStack(stack);
+        List stackTasks = stack.getStackTasks();
+        Collections.reverse(stackTasks);
         if (mTaskStackViewAdapter == null) {
-            mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stack.getStackTasks());
+            mTaskStackViewAdapter = new TaskStackHorizontalViewAdapter(stackTasks);
             mRecentsView.setTaskStackViewAdapter(mTaskStackViewAdapter);
         } else {
-            mTaskStackViewAdapter.setNewStackTasks(stack.getStackTasks());
+            mTaskStackViewAdapter.setNewStackTasks(stackTasks);
         }
 
         if (launchState.launchedToTaskId != -1) {
@@ -284,14 +287,14 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         boolean wasLaunchedByAm = !launchState.launchedFromHome &&
-                !launchState.launchedFromAppWithThumbnail;
+                !launchState.launchedFromApp;
         if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
             EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
         }
 
         // Notify that recents is now visible
         SystemServicesProxy ssp = Recents.getSystemServices();
-        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, true));
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
 
         if (mPipManager.isPipShown()) {
             // Place mPipView at the PIP bounds for fine tuned focus handling.
@@ -340,8 +343,7 @@ public class RecentsTvActivity extends Activity implements OnPreDrawListener {
         mPipManager.removeListener(mPipListener);
         mIgnoreAltTabRelease = false;
         // Notify that recents is now hidden
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, ssp, false));
+        EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
 
         // Workaround for b/22542869, if the RecentsActivity is started again, but without going
         // through SystemUI, we need to reset the config launch flags to ensure that we do not
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
new file mode 100644 (file)
index 0000000..ef8d48e
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.recents.tv.views;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager;
+import android.app.ActivityOptions;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IRemoteCallback;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.WindowManagerGlobal;
+import com.android.internal.annotations.GuardedBy;
+import com.android.systemui.recents.Recents;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.*;
+import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.model.Task;
+import com.android.systemui.recents.model.TaskStack;
+
+
+public class RecentsTvTransitionHelper {
+    private static final String TAG = "RecentsTvTransitionHelper";
+
+    private Context mContext;
+    private Handler mHandler;
+
+    public RecentsTvTransitionHelper(Context context, Handler handler) {
+        mContext = context;
+        mHandler = handler;
+    }
+
+    public void launchTaskFromRecents(final TaskStack stack, @Nullable final Task task,
+            final TaskStackHorizontalGridView stackView, final TaskCardView taskView,
+            final Rect bounds, int destinationStack) {
+        final ActivityOptions opts = ActivityOptions.makeBasic();
+        if (bounds != null) {
+            opts.setLaunchBounds(bounds.isEmpty() ? null : bounds);
+        }
+
+        final ActivityOptions.OnAnimationStartedListener animStartedListener;
+        if (task.thumbnail != null && task.thumbnail.getWidth() > 0 &&
+                task.thumbnail.getHeight() > 0) {
+            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
+                @Override
+                public void onAnimationStarted() {
+                    // If we are launching into another task, cancel the previous task's
+                    // window transition
+                    EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
+                    EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+                }
+            };
+        } else {
+            // This is only the case if the task is not on screen (scrolled offscreen for example)
+            animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
+                @Override
+                public void onAnimationStarted() {
+                    EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+                }
+            };
+        }
+
+        if (taskView == null) {
+            // If there is no task view, then we do not need to worry about animating out occluding
+            // task views, and we can launch immediately
+            startTaskActivity(stack, task, taskView, opts, animStartedListener);
+        } else {
+            LaunchTvTaskStartedEvent launchStartedEvent = new LaunchTvTaskStartedEvent(taskView);
+            EventBus.getDefault().send(launchStartedEvent);
+            startTaskActivity(stack, task, taskView, opts, animStartedListener);
+        }
+    }
+
+    private void startTaskActivity(TaskStack stack, Task task, @Nullable TaskCardView taskView,
+            ActivityOptions opts,final ActivityOptions.OnAnimationStartedListener animStartedListener) {
+        SystemServicesProxy ssp = Recents.getSystemServices();
+        if (ssp.startActivityFromRecents(mContext, task.key.id, task.title, opts)) {
+            // Keep track of the index of the task launch
+            int taskIndexFromFront = 0;
+            int taskIndex = stack.indexOfStackTask(task);
+            if (taskIndex > -1) {
+                taskIndexFromFront = stack.getTaskCount() - taskIndex - 1;
+            }
+            EventBus.getDefault().send(new LaunchTaskSucceededEvent(taskIndexFromFront));
+        } else {
+            // Keep track of failed launches
+            EventBus.getDefault().send(new LaunchTaskFailedEvent());
+        }
+
+        IRemoteCallback.Stub callback = null;
+        if (animStartedListener != null) {
+            callback = new IRemoteCallback.Stub() {
+                @Override
+                public void sendResult(Bundle data) throws RemoteException {
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            if (animStartedListener != null) {
+                                animStartedListener.onAnimationStarted();
+                            }
+                        }
+                    });
+                }
+            };
+        }
+        try {
+            Rect taskRect = taskView.getGlobalRect();
+            WindowManagerGlobal.getWindowManagerService()
+                    .overridePendingAppTransitionThumb(task.thumbnail, taskRect.left,
+                            taskRect.top, callback, true);
+        } catch (RemoteException e) {
+            Log.w(TAG, "Failed to override transition: " + e);
+        }
+    }
+}
index 8e768a2..bf6229c 100644 (file)
@@ -17,6 +17,7 @@ package com.android.systemui.recents.tv.views;
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.Handler;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -31,7 +32,7 @@ import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
+import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.Task;
@@ -53,7 +54,8 @@ public class RecentsTvView extends FrameLayout {
     private View mEmptyView;
     private boolean mAwaitingFirstLayout = true;
     private Rect mSystemInsets = new Rect();
-
+    private RecentsTvTransitionHelper mTransitionHelper;
+    private Handler mHandler;
 
     public RecentsTvView(Context context) {
         this(context, null);
@@ -75,6 +77,8 @@ public class RecentsTvView extends FrameLayout {
         LayoutInflater inflater = LayoutInflater.from(context);
         mEmptyView = inflater.inflate(R.layout.recents_empty, this, false);
         addView(mEmptyView);
+        mHandler = new Handler();
+        mTransitionHelper = new RecentsTvTransitionHelper(mContext, mHandler);
     }
 
     public void setTaskStack(TaskStack stack) {
@@ -209,6 +213,11 @@ public class RecentsTvView extends FrameLayout {
 
     /**** EventBus Events ****/
 
+    public final void onBusEvent(LaunchTvTaskEvent event) {
+        mTransitionHelper.launchTaskFromRecents(mStack, event.task, mTaskStackHorizontalView,
+                event.taskView, event.targetTaskBounds, event.targetTaskStack);
+    }
+
     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
         // If we are going home, cancel the previous task's window transition
         EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(null));
index e275f22..7d8a3ce 100644 (file)
 package com.android.systemui.recents.tv.views;
 
 import android.content.Context;
+import android.graphics.Rect;
 import android.util.AttributeSet;
 import android.widget.ImageView;
-import android.widget.RelativeLayout;
+import android.widget.LinearLayout;
 import android.widget.TextView;
 
 import com.android.systemui.R;
-import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.tv.animations.ViewFocusAnimator;
+import com.android.systemui.recents.model.Task;
 
-public class TaskCardView extends RelativeLayout {
+public class TaskCardView extends LinearLayout {
 
     private ImageView mThumbnailView;
     private TextView mTitleTextView;
-    private TextView mContentTextView;
     private ImageView mBadgeView;
     private Task mTask;
 
@@ -52,7 +52,6 @@ public class TaskCardView extends RelativeLayout {
     protected void onFinishInflate() {
         mThumbnailView = (ImageView) findViewById(R.id.card_view_thumbnail);
         mTitleTextView = (TextView) findViewById(R.id.card_title_text);
-        mContentTextView = (TextView) findViewById(R.id.card_content_text);
         mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
     }
 
@@ -60,11 +59,27 @@ public class TaskCardView extends RelativeLayout {
         mTask = task;
         mThumbnailView.setImageBitmap(task.thumbnail);
         mTitleTextView.setText(task.title);
-        mContentTextView.setText(task.contentDescription);
         mBadgeView.setImageDrawable(task.icon);
     }
 
     public Task getTask() {
         return mTask;
     }
+
+    @Override
+    public void getFocusedRect(Rect r) {
+        mThumbnailView.getFocusedRect(r);
+    }
+
+    public Rect getFocusedRect() {
+        Rect r = new Rect();
+        getFocusedRect(r);
+        return r;
+    }
+
+    public Rect getGlobalRect() {
+        Rect r = new Rect();
+        getGlobalVisibleRect(r);
+        return r;
+    }
 }
index 58ec852..4458639 100644 (file)
@@ -15,7 +15,6 @@
  */
 package com.android.systemui.recents.tv.views;
 
-
 import android.content.Context;
 import android.support.v17.leanback.widget.HorizontalGridView;
 import android.util.AttributeSet;
@@ -36,13 +35,17 @@ import java.util.List;
 /**
  * Horizontal Grid View Implementation to show the Task Stack for TV.
  */
-public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks{
+public class TaskStackHorizontalGridView extends HorizontalGridView implements TaskStackCallbacks {
 
     private TaskStack mStack;
     private ArrayList<TaskCardView> mTaskViews = new ArrayList<>();
     private Task mFocusedTask;
 
 
+    public TaskStackHorizontalGridView(Context context) {
+        this(context, null);
+    }
+
     public TaskStackHorizontalGridView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -64,8 +67,6 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
      * Resets this view for reuse.
      */
     public void reset() {
-        // Reset the focused task
-        resetFocusedTask(getFocusedTask());
         requestLayout();
     }
 
@@ -73,12 +74,6 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
      * @param task - Task to reset
      */
     private void resetFocusedTask(Task task) {
-        if (task != null) {
-            TaskCardView tv = getChildViewForTask(task);
-            if (tv != null) {
-                tv.requestFocus();
-            }
-        }
         mFocusedTask = null;
     }
 
@@ -107,6 +102,9 @@ public class TaskStackHorizontalGridView extends HorizontalGridView implements T
      * @return - The focused task.
      */
     public Task getFocusedTask() {
+        if (findFocus() != null) {
+            mFocusedTask = ((TaskCardView)findFocus()).getTask();
+        }
         return mFocusedTask;
     }
 
index f154331..fba424e 100644 (file)
@@ -16,7 +16,6 @@
 package com.android.systemui.recents.tv.views;
 
 import android.app.Activity;
-import android.app.ActivityManagerNative;
 import android.support.v7.widget.RecyclerView;
 import android.util.Log;
 import android.view.LayoutInflater;
@@ -24,15 +23,20 @@ import android.view.View;
 import android.view.ViewGroup;
 
 import com.android.systemui.R;
+import com.android.systemui.recents.events.EventBus;
+import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
 import com.android.systemui.recents.model.Task;
 
 import java.util.ArrayList;
 import java.util.List;
 
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+
 public class TaskStackHorizontalViewAdapter extends
         RecyclerView.Adapter<TaskStackHorizontalViewAdapter.ViewHolder> {
 
-    private static final String TAG = "TaskStackHorizontalViewAdapter";
+    //Full class name is 30 characters
+    private static final String TAG = "TaskStackViewAdapter";
     private List<Task> mTaskList;
 
     static class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
@@ -54,7 +58,8 @@ public class TaskStackHorizontalViewAdapter extends
         @Override
         public void onClick(View v) {
             try {
-                ActivityManagerNative.getDefault().startActivityFromRecents(mTask.key.id, null);
+                EventBus.getDefault().send(new LaunchTvTaskEvent(mTaskCardView, mTask,
+                        null, INVALID_STACK_ID));
                 ((Activity)(v.getContext())).finish();
             } catch (Exception e) {
                 Log.e(TAG, v.getContext()
@@ -73,11 +78,12 @@ public class TaskStackHorizontalViewAdapter extends
         mTaskList.addAll(tasks);
         notifyDataSetChanged();
     }
+
     @Override
     public TaskStackHorizontalViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
             int viewType) {
         View view = LayoutInflater.from(parent.getContext())
-                .inflate(R.layout.recents_task_card_view, parent, false);
+                .inflate(R.layout.recents_tv_task_card_view, parent, false);
         ViewHolder viewHolder = new ViewHolder(view);
         return viewHolder;
     }
index 4359101..72b914c 100644 (file)
@@ -37,6 +37,13 @@ public class FreeformWorkspaceLayoutAlgorithm {
     private int mTaskPadding;
 
     public FreeformWorkspaceLayoutAlgorithm(Context context) {
+        reloadOnConfigurationChange(context);
+    }
+
+    /**
+     * Reloads the layout for the current configuration.
+     */
+    public void reloadOnConfigurationChange(Context context) {
         // This is applied to the edges of each task
         mTaskPadding = context.getResources().getDimensionPixelSize(
                 R.dimen.recents_freeform_workspace_task_padding) / 2;
@@ -72,8 +79,7 @@ public class FreeformWorkspaceLayoutAlgorithm {
                 }
                 // Bound the task width to the workspace width so that at the worst case, it will
                 // fit its own row
-                normalizedTaskWidths[i] = Math.min(rowTaskWidth,
-                        normalizedWorkspaceWidth);
+                normalizedTaskWidths[i] = Math.min(rowTaskWidth, normalizedWorkspaceWidth);
             }
 
             // Determine the scale to best fit each of the tasks in the workspace
index 37b2859..dd825cb 100644 (file)
@@ -105,9 +105,6 @@ public class RecentsTransitionHelper {
             animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
                 @Override
                 public void onAnimationStarted() {
-                    // If we are launching into another task, cancel the previous task's
-                    // window transition
-                    EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
                     EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
 
                     if (screenPinningRequested) {
@@ -149,6 +146,10 @@ public class RecentsTransitionHelper {
                         animStartedListener);
             }
         }
+
+        // If we are launching into another task, cancel the previous task's
+        // window transition
+        EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
     }
 
     /**
@@ -176,6 +177,7 @@ public class RecentsTransitionHelper {
             // Keep track of failed launches
             EventBus.getDefault().send(new LaunchTaskFailedEvent());
         }
+
         if (transitionFuture != null) {
             IRemoteCallback.Stub callback = null;
             if (animStartedListener != null) {
index 5dde926..1af5a55 100644 (file)
@@ -60,9 +60,7 @@ import com.android.systemui.recents.events.activity.HideHistoryEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
 import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
 import com.android.systemui.recents.events.activity.ShowHistoryEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
 import com.android.systemui.recents.events.activity.ToggleHistoryEvent;
-import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEndedEvent;
 import com.android.systemui.recents.events.ui.DraggingInRecentsEvent;
 import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent;
@@ -168,35 +166,39 @@ public class RecentsView extends FrameLayout {
     }
 
     /** Set/get the bsp root node */
-    public void setTaskStack(TaskStack stack) {
+    public void onResume(boolean isResumingFromVisible, TaskStack stack) {
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
-        mStack = stack;
-        if (launchState.launchedReuseTaskStackViews) {
-            if (mTaskStackView != null) {
-                // If onRecentsHidden is not triggered, we need to the stack view again here
-                mTaskStackView.reset();
-                mTaskStackView.setStack(stack);
-            } else {
-                mTaskStackView = new TaskStackView(getContext(), stack);
-                addView(mTaskStackView);
-            }
-        } else {
-            if (mTaskStackView != null) {
-                removeView(mTaskStackView);
-            }
-            mTaskStackView = new TaskStackView(getContext(), stack);
+
+        if (mTaskStackView == null || !launchState.launchedReuseTaskStackViews) {
+            isResumingFromVisible = false;
+            removeView(mTaskStackView);
+            mTaskStackView = new TaskStackView(getContext());
+            mStack = mTaskStackView.getStack();
             addView(mTaskStackView);
         }
 
-        // If we are already occluded by the app, then just set the default background scrim now.
-        // Otherwise, defer until the enter animation completes to animate the scrim with the
-        // tasks for the home animation.
-        if (launchState.launchedWhileDocking || launchState.launchedFromAppWithThumbnail
-                || mStack.getTaskCount() == 0) {
-            mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255));
+        // Reset the state
+        mAwaitingFirstLayout = !isResumingFromVisible;
+        mLastTaskLaunchedWasFreeform = false;
+
+        // Update the stack
+        mTaskStackView.onResume(isResumingFromVisible);
+        mTaskStackView.setTasks(stack, isResumingFromVisible /* notifyStackChanges */);
+
+        if (isResumingFromVisible) {
+            // If we are already visible, then restore the background scrim
+            animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION);
         } else {
-            mBackgroundScrim.setAlpha(0);
+            // If we are already occluded by the app, then set the final background scrim alpha now.
+            // Otherwise, defer until the enter animation completes to animate the scrim alpha with
+            // the tasks for the home animation.
+            if (launchState.launchedWhileDocking || launchState.launchedFromApp
+                    || mStack.getTaskCount() == 0) {
+                mBackgroundScrim.setAlpha((int) (DEFAULT_SCRIM_ALPHA * 255));
+            } else {
+                mBackgroundScrim.setAlpha(0);
+            }
         }
 
         // Update the top level view's visibilities
@@ -205,9 +207,6 @@ public class RecentsView extends FrameLayout {
         } else {
             showEmptyView();
         }
-
-        // Trigger a new layout
-        requestLayout();
     }
 
     /**
@@ -662,16 +661,9 @@ public class RecentsView extends FrameLayout {
         animator.start();
     }
 
-    public final void onBusEvent(TaskStackUpdatedEvent event) {
-        if (!event.inMultiWindow) {
-            mStack.setTasks(event.stack.computeAllTasksList(), true /* notifyStackChanges */);
-            mStack.createAffiliatedGroupings(getContext());
-        }
-    }
-
     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
-        if (!launchState.launchedWhileDocking && !launchState.launchedFromAppWithThumbnail
+        if (!launchState.launchedWhileDocking && !launchState.launchedFromApp
                 && mStack.getTaskCount() > 0) {
             animateBackgroundScrim(DEFAULT_SCRIM_ALPHA,
                     TaskStackAnimationHelper.ENTER_FROM_HOME_TRANSLATION_DURATION);
@@ -686,17 +678,6 @@ public class RecentsView extends FrameLayout {
         animateBackgroundScrim(DEFAULT_SCRIM_ALPHA, DEFAULT_UPDATE_SCRIM_DURATION);
     }
 
-    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
-        if (!event.visible) {
-            // Reset the view state
-            mAwaitingFirstLayout = true;
-            mLastTaskLaunchedWasFreeform = false;
-            if (RecentsDebugFlags.Static.EnableHistory) {
-                hideHistoryButton(0, false /* translate */);
-            }
-        }
-    }
-
     public final void onBusEvent(ToggleHistoryEvent event) {
         if (!RecentsDebugFlags.Static.EnableHistory) {
             return;
index 1cd0850..19b219a 100644 (file)
 
 package com.android.systemui.recents.views;
 
+import android.animation.AnimatorListenerAdapter;
 import android.app.Activity;
 import android.content.Context;
 import android.view.View;
+import android.view.ViewPropertyAnimator;
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -56,25 +58,41 @@ public class SystemBarScrimViews {
                 View.VISIBLE : View.INVISIBLE);
     }
 
+    /**
+     * Animates the nav bar scrim visibility.
+     */
+    public void animateNavBarScrimVisibility(boolean visible, AnimationProps animation) {
+        int toY = 0;
+        if (visible) {
+            mNavBarScrimView.setVisibility(View.VISIBLE);
+            mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
+        } else {
+            toY = mNavBarScrimView.getMeasuredHeight();
+        }
+        if (animation != AnimationProps.IMMEDIATE) {
+            mNavBarScrimView.animate()
+                    .translationY(toY)
+                    .setDuration(animation.getDuration(AnimationProps.BOUNDS))
+                    .setInterpolator(animation.getInterpolator(AnimationProps.BOUNDS))
+                    .start();
+        } else {
+            mNavBarScrimView.setTranslationY(toY);
+        }
+    }
+
     /**** EventBus events ****/
 
     /**
      * Starts animating the scrim views when entering Recents.
      */
     public final void onBusEvent(EnterRecentsWindowAnimationCompletedEvent event) {
-        if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
-            mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
-            mNavBarScrimView.animate()
-                    .translationY(0)
-                    .setDuration(mNavBarScrimEnterDuration)
-                    .setInterpolator(Interpolators.DECELERATE_QUINT)
-                    .withStartAction(new Runnable() {
-                        @Override
-                        public void run() {
-                            mNavBarScrimView.setVisibility(View.VISIBLE);
-                        }
-                    })
-                    .start();
+        if (mHasNavBarScrim) {
+            AnimationProps animation = mShouldAnimateNavBarScrim
+                    ? new AnimationProps()
+                            .setDuration(AnimationProps.BOUNDS, mNavBarScrimEnterDuration)
+                            .setInterpolator(AnimationProps.BOUNDS, Interpolators.DECELERATE_QUINT)
+                    : AnimationProps.IMMEDIATE;
+            animateNavBarScrimVisibility(true, animation);
         }
     }
 
@@ -83,13 +101,12 @@ public class SystemBarScrimViews {
      * going home).
      */
     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
-        if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
-            mNavBarScrimView.animate()
-                    .translationY(mNavBarScrimView.getMeasuredHeight())
-                    .setStartDelay(0)
-                    .setDuration(TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
-                    .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                    .start();
+        if (mHasNavBarScrim) {
+            AnimationProps animation = new AnimationProps()
+                    .setDuration(AnimationProps.BOUNDS,
+                            TaskStackAnimationHelper.EXIT_TO_HOME_TRANSLATION_DURATION)
+                    .setInterpolator(AnimationProps.BOUNDS, Interpolators.FAST_OUT_SLOW_IN);
+            animateNavBarScrimVisibility(false, animation);
         }
     }
 }
index 2cd0c19..758f4d8 100644 (file)
@@ -20,8 +20,8 @@ import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
 import android.content.res.Resources;
-import android.graphics.Path;
 import android.graphics.RectF;
+import android.util.Log;
 import android.view.View;
 import android.view.animation.Interpolator;
 import android.view.animation.PathInterpolator;
@@ -56,8 +56,8 @@ public class TaskStackAnimationHelper {
         /**
          * Callback to start the animation for the launch target {@link TaskView}.
          */
-        void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
-                ReferenceCountedTrigger postAnimationTrigger);
+        void onStartLaunchTargetEnterAnimation(TaskViewTransform transform, int duration,
+                boolean screenPinningEnabled, ReferenceCountedTrigger postAnimationTrigger);
 
         /**
          * Callback to start the animation for the launch target {@link TaskView} when it is
@@ -141,7 +141,7 @@ public class TaskStackAnimationHelper {
                 tv.setVisibility(View.INVISIBLE);
             } else if (launchState.launchedHasConfigurationChanged) {
                 // Just load the views as-is
-            } else if (launchState.launchedFromAppWithThumbnail) {
+            } else if (launchState.launchedFromApp) {
                 if (task.isLaunchTarget) {
                     tv.onPrepareLaunchTargetForEnterAnimation();
                 } else if (currentTaskOccludesLaunchTarget) {
@@ -205,10 +205,11 @@ public class TaskStackAnimationHelper {
             stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform,
                     null);
 
-            if (launchState.launchedFromAppWithThumbnail) {
+            if (launchState.launchedFromApp) {
                 if (task.isLaunchTarget) {
-                    tv.onStartLaunchTargetEnterAnimation(taskViewEnterFromAppDuration,
-                            mStackView.mScreenPinningEnabled, postAnimationTrigger);
+                    tv.onStartLaunchTargetEnterAnimation(mTmpTransform,
+                            taskViewEnterFromAppDuration, mStackView.mScreenPinningEnabled,
+                            postAnimationTrigger);
                 } else {
                     // Animate the task up if it was occluding the launch target
                     if (currentTaskOccludesLaunchTarget) {
@@ -441,11 +442,13 @@ public class TaskStackAnimationHelper {
         TaskStackViewScroller stackScroller = mStackView.getScroller();
         TaskStack stack = mStackView.getStack();
 
+        final float curScroll = stackScroller.getStackScroll();
         final float newScroll = stackLayout.getStackScrollForTask(newFocusedTask);
-        boolean willScrollToFront = newScroll > stackScroller.getStackScroll();
-        boolean willScroll = Float.compare(newScroll, stackScroller.getStackScroll()) != 0;
+        boolean willScrollToFront = newScroll > curScroll;
+        boolean willScroll = Float.compare(newScroll, curScroll) != 0;
 
         // Get the current set of task transforms
+        int taskViewCount = mStackView.getTaskViews().size();
         ArrayList<Task> stackTasks = stack.getStackTasks();
         mStackView.getCurrentTaskTransforms(stackTasks, mTmpCurrentTaskTransforms);
 
@@ -463,6 +466,13 @@ public class TaskStackAnimationHelper {
 
         // Focus the task view
         TaskView newFocusedTaskView = mStackView.getChildViewForTask(newFocusedTask);
+        if (newFocusedTaskView == null) {
+            // Log the error if we have no task view, and skip the animation
+            Log.e("TaskStackAnimationHelper", "b/27389156 null-task-view prebind:" + taskViewCount +
+                    " postbind:" + mStackView.getTaskViews().size() + " prescroll:" + curScroll +
+                    " postscroll: " + newScroll);
+            return false;
+        }
         newFocusedTaskView.setFocusedState(true, requestViewFocus);
 
         // Setup the end listener to return all the hidden views to the view pool after the
@@ -476,7 +486,7 @@ public class TaskStackAnimationHelper {
         });
 
         List<TaskView> taskViews = mStackView.getTaskViews();
-        int taskViewCount = taskViews.size();
+        taskViewCount = taskViews.size();
         int newFocusTaskViewIndex = taskViews.indexOf(newFocusedTaskView);
         for (int i = 0; i < taskViewCount; i++) {
             TaskView tv = taskViews.get(i);
index 261b6f6..699b85e 100644 (file)
@@ -29,6 +29,7 @@ import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.misc.FreePathInterpolator;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.misc.Utilities;
@@ -36,6 +37,7 @@ import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 
 import java.util.ArrayList;
+import java.util.List;
 
 /**
  * Used to describe a visible range that can be normalized to [0, 1].
@@ -220,6 +222,10 @@ public class TaskStackLayoutAlgorithm {
     private Range mUnfocusedRange;
     private Range mFocusedRange;
 
+    // The initial offset from the top of the stack
+    @ViewDebug.ExportedProperty(category="recents")
+    private int mInitialTopPeekHeight;
+
     // The offset from the top when scrolled to the top of the stack
     @ViewDebug.ExportedProperty(category="recents")
     private int mFocusedTopPeekHeight;
@@ -231,6 +237,10 @@ public class TaskStackLayoutAlgorithm {
     @ViewDebug.ExportedProperty(category="recents")
     private int mStackTopOffset;
 
+    // The height of the header bar
+    @ViewDebug.ExportedProperty(category="recents")
+    private int mHeaderBarHeight;
+
     // The offset from the bottom of the stack to the bottom of the bounds when the stack is
     // scrolled to the front
     @ViewDebug.ExportedProperty(category="recents")
@@ -249,6 +259,9 @@ public class TaskStackLayoutAlgorithm {
     private FreePathInterpolator mUnfocusedDimCurveInterpolator;
     private FreePathInterpolator mFocusedDimCurveInterpolator;
 
+    // Indexed from the front of the stack, the normalized x in the unfocused range for each task
+    private float[] mInitialNormX;
+
     // The state of the stack focus (0..1), which controls the transition of the stack from the
     // focused to non-focused state
     @ViewDebug.ExportedProperty(category="recents")
@@ -292,23 +305,32 @@ public class TaskStackLayoutAlgorithm {
     TaskViewTransform mFrontOfStackTransform = new TaskViewTransform();
 
     public TaskStackLayoutAlgorithm(Context context, TaskStackLayoutAlgorithmCallbacks cb) {
-        Resources res = context.getResources();
         mContext = context;
         mCb = cb;
+        mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
+        reloadOnConfigurationChange(context);
+    }
 
+    /**
+     * Reloads the layout for the current configuration.
+     */
+    public void reloadOnConfigurationChange(Context context) {
+        Resources res = context.getResources();
         mFocusedRange = new Range(res.getFloat(R.integer.recents_layout_focused_range_min),
                 res.getFloat(R.integer.recents_layout_focused_range_max));
         mUnfocusedRange = new Range(res.getFloat(R.integer.recents_layout_unfocused_range_min),
                 res.getFloat(R.integer.recents_layout_unfocused_range_max));
-        mFocusState = getDefaultFocusState();
+        mFocusState = getInitialFocusState();
+        mInitialTopPeekHeight = res.getDimensionPixelSize(R.dimen.recents_initial_top_peek_size);
         mFocusedTopPeekHeight =
                 res.getDimensionPixelSize(R.dimen.recents_layout_focused_top_peek_size);
         mFocusedBottomTaskPeekHeight =
                 res.getDimensionPixelSize(R.dimen.recents_layout_focused_bottom_task_peek_size);
+        mHeaderBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
 
         mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
         mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
-        mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context);
+        mFreeformLayoutAlgorithm.reloadOnConfigurationChange(context);
     }
 
     /**
@@ -316,7 +338,7 @@ public class TaskStackLayoutAlgorithm {
      */
     public void reset() {
         mTaskIndexOverrideMap.clear();
-        setFocusState(getDefaultFocusState());
+        setFocusState(getInitialFocusState());
     }
 
     /**
@@ -439,46 +461,86 @@ public class TaskStackLayoutAlgorithm {
             mTaskIndexMap.put(task.key.id, i);
         }
 
-        // Calculate the min/max scroll
-        if (getDefaultFocusState() > 0f) {
+        // Update the freeform tasks
+        if (!freeformTasks.isEmpty()) {
+            mFreeformLayoutAlgorithm.update(freeformTasks, this);
+        }
+
+        // Calculate the min/max/initial scroll
+        Task launchTask = stack.getLaunchTarget();
+        int launchTaskIndex = launchTask != null
+                ? stack.indexOfStackTask(launchTask)
+                : mNumStackTasks - 1;
+        if (getInitialFocusState() == STATE_FOCUSED) {
             mMinScrollP = 0;
             mMaxScrollP = Math.max(mMinScrollP, mNumStackTasks - 1);
+            if (launchState.launchedFromHome) {
+                mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
+            } else {
+                mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
+            }
+        } else if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
+            // If there is one stack task, ignore the min/max/initial scroll positions
+            mMinScrollP = 0;
+            mMaxScrollP = 0;
+            mInitialScrollP = 0;
         } else {
-            if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
-                mMinScrollP = mMaxScrollP = 0;
+            // Set the max scroll to be the point where the front most task is visible with the
+            // stack bottom offset
+            int maxBottomOffset = mStackBottomOffset + mTaskRect.height();
+            float maxBottomOffsetPct = (float) maxBottomOffset / mStackRect.height();
+            float maxBottomNormX = mUnfocusedCurveInterpolator.getX(maxBottomOffsetPct);
+            mUnfocusedRange.offset(0f);
+            mMinScrollP = 0;
+            mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
+                    Math.max(0, mUnfocusedRange.getAbsoluteX(maxBottomNormX)));
+            boolean scrollToFront = launchState.launchedFromHome ||
+                    launchState.launchedFromAppDocked;
+            if (scrollToFront) {
+                mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
             } else {
-                float bottomOffsetPct = (float) (mStackBottomOffset + mTaskRect.height()) /
-                        mStackRect.height();
-                float normX = mUnfocusedCurveInterpolator.getX(bottomOffsetPct);
-                mMinScrollP = 0;
-                mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) -
-                        Math.max(0, mUnfocusedRange.getAbsoluteX(normX)));
+                mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
             }
+
+            // Set the initial scroll to the predefined state (which differs from the stack)
+            int initialPeekOffset = mStackRect.height() - mInitialTopPeekHeight;
+            float initialPeekOffsetPct = (float) initialPeekOffset / mStackRect.height();
+            float initialPeekOffsetNormX = mUnfocusedCurveInterpolator.getX(initialPeekOffsetPct);
+            float initialFocusedOffset = mStackRect.height() - mInitialTopPeekHeight -
+                    (mHeaderBarHeight * 1f) + 1;
+            float initialFocusedOffsetPct = (float) initialFocusedOffset / mStackRect.height();
+            float initialFocusedNormX = mUnfocusedCurveInterpolator.getX(initialFocusedOffsetPct);
+            int initialBottomOffset = mStackBottomOffset + mHeaderBarHeight;
+            float initialBottomOffsetPct = (float) initialBottomOffset / mStackRect.height();
+            float initialBottomNormX = mUnfocusedCurveInterpolator.getX(initialBottomOffsetPct);
+            /*
+            // If we want to offset the top card slightly
+            mInitialNormX = scrollToFront
+                    ? new float[] { initialFocusedNormX, initialPeekOffsetNormX, 0f }
+                    : new float[] { initialBottomNormX, initialFocusedNormX,
+                            initialPeekOffsetNormX, 0f };
+            */
+            mInitialNormX = scrollToFront
+                    ? new float[] { initialFocusedNormX, initialPeekOffsetNormX, 0f }
+                    : new float[] { initialBottomNormX, 0.5f, 0f };
         }
+    }
 
-        if (!freeformTasks.isEmpty()) {
-            mFreeformLayoutAlgorithm.update(freeformTasks, this);
-            mInitialScrollP = mMaxScrollP;
-        } else {
-            Task launchTask = stack.getLaunchTarget();
-            int launchTaskIndex = launchTask != null
-                    ? stack.indexOfStackTask(launchTask)
-                    : mNumStackTasks - 1;
-            if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
-                mInitialScrollP = mMinScrollP;
-            } else if (getDefaultFocusState() > 0f) {
-                if (launchState.launchedFromHome) {
-                    mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
-                } else {
-                    mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP,
-                            mMaxScrollP);
-                }
-            } else {
-                float offsetPct = (float) (mTaskRect.height() / 3) / mStackRect.height();
-                float normX = mUnfocusedCurveInterpolator.getX(offsetPct);
-                mInitialScrollP = Utilities.clamp(launchTaskIndex -
-                        mUnfocusedRange.getAbsoluteX(normX), mMinScrollP, mMaxScrollP);
+    public void updateToInitialState(List<Task> tasks) {
+        if (mInitialNormX == null) {
+            return;
+        }
+
+        mUnfocusedRange.offset(0f);
+        int taskCount = tasks.size();
+        for (int i = taskCount - 1; i >= 0; i--) {
+            int indexFromFront = taskCount - i - 1;
+            if (indexFromFront >= mInitialNormX.length) {
+                break;
             }
+            float newTaskProgress = mInitialScrollP +
+                    mUnfocusedRange.getAbsoluteX(mInitialNormX[indexFromFront]);
+            mTaskIndexOverrideMap.put(tasks.get(i).key.id, newTaskProgress);
         }
     }
 
@@ -500,10 +562,18 @@ public class TaskStackLayoutAlgorithm {
         }
     }
 
+    public void clearUnfocusedTaskOverrides() {
+        mTaskIndexOverrideMap.clear();
+    }
+
     /**
      * Updates this stack when a scroll happens.
      */
     public void updateFocusStateOnScroll(float stackScroll, float deltaScroll) {
+        if (deltaScroll == 0f) {
+            return;
+        }
+
         for (int i = mTaskIndexOverrideMap.size() - 1; i >= 0; i--) {
             int taskId = mTaskIndexOverrideMap.keyAt(i);
             float x = mTaskIndexMap.get(taskId);
@@ -523,7 +593,7 @@ public class TaskStackLayoutAlgorithm {
             } else {
                 // Scrolling override x away from x, we should still move the scroll towards x
                 float deltaX = overrideX - x;
-                newOverrideX = Math.signum(deltaX) * (Math.abs(deltaX) - deltaScroll);
+                newOverrideX = Math.signum(deltaX) * (Math.abs(deltaX) - Math.abs(deltaScroll));
                 mTaskIndexOverrideMap.put(taskId, x + newOverrideX);
             }
         }
@@ -532,8 +602,13 @@ public class TaskStackLayoutAlgorithm {
     /**
      * Returns the default focus state.
      */
-    public int getDefaultFocusState() {
-        return STATE_FOCUSED;
+    public int getInitialFocusState() {
+        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
+        if (debugFlags.isPagingEnabled()) {
+            return STATE_FOCUSED;
+        } else {
+            return STATE_UNFOCUSED;
+        }
     }
 
     /**
@@ -559,6 +634,13 @@ public class TaskStackLayoutAlgorithm {
     }
 
     /**
+     * Returns whether this stack layout has been initialized.
+     */
+    public boolean isInitialized() {
+        return !mStackRect.isEmpty();
+    }
+
+    /**
      * Computes the maximum number of visible tasks and thumbnails when the scroll is at the initial
      * stack scroll.  Requires that update() is called first.
      */
@@ -577,7 +659,7 @@ public class TaskStackLayoutAlgorithm {
         // Otherwise, walk backwards in the stack and count the number of tasks and visible
         // thumbnails and add that to the total freeform task count
         TaskViewTransform tmpTransform = new TaskViewTransform();
-        Range currentRange = getDefaultFocusState() > 0f ? mFocusedRange : mUnfocusedRange;
+        Range currentRange = getInitialFocusState() > 0f ? mFocusedRange : mUnfocusedRange;
         currentRange.offset(mInitialScrollP);
         int taskBarHeight = mContext.getResources().getDimensionPixelSize(
                 R.dimen.recents_task_bar_height);
@@ -600,8 +682,9 @@ public class TaskStackLayoutAlgorithm {
 
             boolean isFrontMostTaskInGroup = task.group == null || task.group.isFrontMostTask(task);
             if (isFrontMostTaskInGroup) {
-                getStackTransform(taskProgress, mInitialScrollP, mFocusState, tmpTransform, null,
-                        false /* ignoreSingleTaskCase */, false /* forceUpdate */);
+                getStackTransform(taskProgress, taskProgress, mInitialScrollP, mFocusState,
+                        tmpTransform, null, false /* ignoreSingleTaskCase */,
+                        false /* forceUpdate */);
                 float screenY = tmpTransform.rect.top;
                 boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
                 if (hasVisibleThumbnail) {
@@ -635,23 +718,34 @@ public class TaskStackLayoutAlgorithm {
     public TaskViewTransform getStackTransform(Task task, float stackScroll,
             TaskViewTransform transformOut, TaskViewTransform frontTransform) {
         return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform,
-                false /* forceUpdate */);
+                false /* forceUpdate */, false /* ignoreTaskOverrides */);
+    }
+
+    public TaskViewTransform getStackTransform(Task task, float stackScroll,
+            TaskViewTransform transformOut, TaskViewTransform frontTransform,
+            boolean ignoreTaskOverrides) {
+        return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform,
+                false /* forceUpdate */, ignoreTaskOverrides);
     }
 
     public TaskViewTransform getStackTransform(Task task, float stackScroll, int focusState,
-        TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate) {
+            TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate,
+            boolean ignoreTaskOverrides) {
         if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) {
             mFreeformLayoutAlgorithm.getTransform(task, transformOut, this);
             return transformOut;
         } else {
             // Return early if we have an invalid index
-            if (task == null || mTaskIndexMap.get(task.key.id, -1) == -1) {
+            int nonOverrideTaskProgress = mTaskIndexMap.get(task.key.id, -1);
+            if (task == null || nonOverrideTaskProgress == -1) {
                 transformOut.reset();
                 return transformOut;
             }
-            float taskProgress = getStackScrollForTask(task);
-            getStackTransform(taskProgress, stackScroll, focusState, transformOut,
-                    frontTransform, false /* ignoreSingleTaskCase */, forceUpdate);
+            float taskProgress = ignoreTaskOverrides
+                    ? nonOverrideTaskProgress
+                    : getStackScrollForTask(task);
+            getStackTransform(taskProgress, nonOverrideTaskProgress, stackScroll, focusState,
+                    transformOut, frontTransform, false /* ignoreSingleTaskCase */, forceUpdate);
             return transformOut;
         }
     }
@@ -676,9 +770,9 @@ public class TaskStackLayoutAlgorithm {
      *                             internally to ensure that we can calculate the transform for any
      *                             position in the stack.
      */
-    public void getStackTransform(float taskProgress, float stackScroll, int focusState,
-            TaskViewTransform transformOut, TaskViewTransform frontTransform,
-            boolean ignoreSingleTaskCase, boolean forceUpdate) {
+    public void getStackTransform(float taskProgress, float nonOverrideTaskProgress,
+            float stackScroll, int focusState, TaskViewTransform transformOut,
+            TaskViewTransform frontTransform, boolean ignoreSingleTaskCase, boolean forceUpdate) {
         SystemServicesProxy ssp = Recents.getSystemServices();
 
         // Compute the focused and unfocused offset
@@ -687,6 +781,8 @@ public class TaskStackLayoutAlgorithm {
         mFocusedRange.offset(boundedStackScroll);
         float boundedScrollUnfocusedRangeX = mUnfocusedRange.getNormalizedX(taskProgress);
         float boundedScrollFocusedRangeX = mFocusedRange.getNormalizedX(taskProgress);
+        float boundedScrollUnfocusedNonOverrideRangeX =
+                mUnfocusedRange.getNormalizedX(nonOverrideTaskProgress);
         mUnfocusedRange.offset(stackScroll);
         mFocusedRange.offset(stackScroll);
         boolean unfocusedVisible = mUnfocusedRange.isInRange(taskProgress);
@@ -730,7 +826,7 @@ public class TaskStackLayoutAlgorithm {
 
             y = (mStackRect.top - mTaskRect.top) +
                     (int) Utilities.mapRange(focusState, unfocusedY, focusedY);
-            z = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedRangeX),
+            z = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedNonOverrideRangeX),
                     mMinTranslationZ, mMaxTranslationZ);
             dimAlpha = Utilities.mapRange(focusState, unfocusedDim, focusedDim);
             viewOutlineAlpha = Utilities.mapRange(Utilities.clamp01(boundedScrollUnfocusedRangeX),
@@ -851,8 +947,8 @@ public class TaskStackLayoutAlgorithm {
         // The unfocused dim interpolator starts at max dim, reduces to zero at 0.5 (the focused
         // task), then goes back to max dim towards the front of the stack
         p.moveTo(0f, MAX_DIM);
-        p.cubicTo(0f, 0.1f, 0.4f, 0f, 0.5f, 0f);
-        p.cubicTo(0.6f, 0f, 0.9f, MAX_DIM - 0.1f, 1f, MAX_DIM / 2f);
+        p.cubicTo(0.1f, MAX_DIM, 0.4f, 0.0f, 0.5f, 0f);
+        p.cubicTo(0.6f, 0f, 0.9f, MAX_DIM / 2f, 1f, MAX_DIM / 2f);
         return p;
     }
 
@@ -870,9 +966,9 @@ public class TaskStackLayoutAlgorithm {
                 mFocusedRange.relativeMin);
         float max = Utilities.mapRange(mFocusState, mUnfocusedRange.relativeMax,
                 mFocusedRange.relativeMax);
-        getStackTransform(min, 0f, mFocusState, mBackOfStackTransform, null,
+        getStackTransform(min, min, 0f, mFocusState, mBackOfStackTransform, null,
                 true /* ignoreSingleTaskCase */, true /* forceUpdate */);
-        getStackTransform(max, 0f, mFocusState, mFrontOfStackTransform, null,
+        getStackTransform(max, max, 0f, mFocusState, mFrontOfStackTransform, null,
                 true /* ignoreSingleTaskCase */, true /* forceUpdate */);
         mBackOfStackTransform.visible = true;
         mFrontOfStackTransform.visible = true;
index e1a81c8..6abb826 100644 (file)
@@ -35,7 +35,6 @@ import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.MutableBoolean;
-import android.util.SparseBooleanArray;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -56,6 +55,7 @@ import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
+import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
 import com.android.systemui.recents.events.activity.EnterRecentsTaskStackAnimationCompletedEvent;
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
@@ -65,15 +65,13 @@ import com.android.systemui.recents.events.activity.IterateRecentsEvent;
 import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskEvent;
 import com.android.systemui.recents.events.activity.LaunchTaskStartedEvent;
+import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.events.activity.ShowHistoryButtonEvent;
 import com.android.systemui.recents.events.activity.ShowHistoryEvent;
-import com.android.systemui.recents.events.activity.TaskStackUpdatedEvent;
-import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
 import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
 import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
-import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
 import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
 import com.android.systemui.recents.events.ui.UserInteractionEvent;
@@ -118,7 +116,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
     private static final ArraySet<Task.TaskKey> EMPTY_TASK_SET = new ArraySet<>();
 
     LayoutInflater mInflater;
-    TaskStack mStack;
+    TaskStack mStack = new TaskStack();
     @ViewDebug.ExportedProperty(deepExport=true, prefix="layout_")
     TaskStackLayoutAlgorithm mLayoutAlgorithm;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="scroller_")
@@ -207,13 +205,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         }
     };
 
-    public TaskStackView(Context context, TaskStack stack) {
+    public TaskStackView(Context context) {
         super(context);
         SystemServicesProxy ssp = Recents.getSystemServices();
         Resources res = context.getResources();
 
         // Set the stack first
-        setStack(stack);
+        mStack.setCallbacks(this);
         mViewPool = new ViewPool<>(context, this);
         mInflater = LayoutInflater.from(context);
         mLayoutAlgorithm = new TaskStackLayoutAlgorithm(context, this);
@@ -249,6 +247,41 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         }
     }
 
+    /**
+     * Called only if we are resuming Recents.
+     */
+    void onResume(boolean isResumingFromVisible) {
+        if (!isResumingFromVisible) {
+            // Reset the focused task
+            resetFocusedTask(getFocusedTask());
+        }
+
+        // Reset the state of each of the task views
+        List<TaskView> taskViews = new ArrayList<>();
+        taskViews.addAll(getTaskViews());
+        taskViews.addAll(mViewPool.getViews());
+        for (int i = taskViews.size() - 1; i >= 0; i--) {
+            taskViews.get(i).onResume(isResumingFromVisible);
+        }
+
+        // Reset the stack state
+        readSystemFlags();
+        mTaskViewsClipDirty = true;
+        mEnterAnimationComplete = false;
+        mUIDozeTrigger.stopDozing();
+        if (isResumingFromVisible) {
+            // Animate in the freeform workspace
+            int ffBgAlpha = mLayoutAlgorithm.getStackState().freeformBackgroundAlpha;
+            animateFreeformWorkspaceBackgroundAlpha(ffBgAlpha, new AnimationProps(150,
+                    Interpolators.FAST_OUT_SLOW_IN));
+        } else {
+            mStackScroller.reset();
+            mLayoutAlgorithm.reset();
+            mAwaitingFirstLayout = true;
+            requestLayout();
+        }
+    }
+
     @Override
     protected void onAttachedToWindow() {
         EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
@@ -262,22 +295,35 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         EventBus.getDefault().unregister(this);
     }
 
-    /** Sets the task stack */
-    void setStack(TaskStack stack) {
-        // Set the new stack
-        mStack = stack;
-        if (mStack != null) {
-            mStack.setCallbacks(this);
+    /**
+     * Sets the stack tasks of this TaskStackView from the given TaskStack.
+     */
+    public void setTasks(TaskStack stack, boolean notifyStackChanges) {
+        boolean isInitialized = mLayoutAlgorithm.isInitialized();
+        mStack.setTasks(getContext(), stack.computeAllTasksList(),
+                notifyStackChanges && isInitialized);
+        if (isInitialized) {
+            // Only update the layout if we are notifying, otherwise, we will update it in the next
+            // measure/layout pass
+            updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
+            updateToInitialState();
+            relayoutTaskViewsOnNextFrame(AnimationProps.IMMEDIATE);
         }
-        // Layout again with the new stack
-        requestLayout();
     }
 
     /** Returns the task stack. */
-    TaskStack getStack() {
+    public TaskStack getStack() {
         return mStack;
     }
 
+    /**
+     * Updates this TaskStackView to the initial state.
+     */
+    public void updateToInitialState() {
+        mStackScroller.setStackScrollToInitialState();
+        mLayoutAlgorithm.updateToInitialState(mStack.getStackTasks());
+    }
+
     /** Updates the list of task views */
     void updateTaskViewsList() {
         mTaskViews.clear();
@@ -331,37 +377,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         return null;
     }
 
-    /** Resets this TaskStackView for reuse. */
-    void reset() {
-        // Reset the focused task
-        resetFocusedTask(getFocusedTask());
-
-        // Return all the views to the pool
-        List<TaskView> taskViews = getTaskViews();
-        int taskViewCount = taskViews.size();
-        for (int i = taskViewCount - 1; i >= 0; i--) {
-            mViewPool.returnViewToPool(taskViews.get(i));
-        }
-
-        // Mark each task view for relayout
-        List<TaskView> poolViews = mViewPool.getViews();
-        for (TaskView tv : poolViews) {
-            tv.reset();
-        }
-
-        // Reset the stack state
-        mStack.reset();
-        mTaskViewsClipDirty = true;
-        mAwaitingFirstLayout = true;
-        mEnterAnimationComplete = false;
-        mUIDozeTrigger.stopDozing();
-        mUIDozeTrigger.resetTrigger();
-        mStackScroller.reset();
-        mLayoutAlgorithm.reset();
-        readSystemFlags();
-        requestLayout();
-    }
-
     /** Returns the stack algorithm for this task stack. */
     public TaskStackLayoutAlgorithm getStackAlgorithm() {
         return mLayoutAlgorithm;
@@ -410,7 +425,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
      */
     int[] computeVisibleTaskTransforms(ArrayList<TaskViewTransform> taskTransforms,
             ArrayList<Task> tasks, float curStackScroll, float targetStackScroll,
-            ArraySet<Task.TaskKey> ignoreTasksSet) {
+            ArraySet<Task.TaskKey> ignoreTasksSet, boolean ignoreTaskOverrides) {
         int taskCount = tasks.size();
         int[] visibleTaskRange = mTmpIntPair;
         visibleTaskRange[0] = -1;
@@ -430,7 +445,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
 
             // Calculate the current and (if necessary) the target transform for the task
             transform = mLayoutAlgorithm.getStackTransform(task, curStackScroll,
-                    taskTransforms.get(i), frontTransform);
+                    taskTransforms.get(i), frontTransform, ignoreTaskOverrides);
             if (useTargetStackScroll && !transform.visible) {
                 // If we have a target stack scroll and the task is not currently visible, then we
                 // just update the transform at the new scroll
@@ -468,11 +483,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
 
     /**
      * Binds the visible {@link TaskView}s at the given target scroll.
-     *
-     * @see #bindVisibleTaskViews(float, ArraySet<Task.TaskKey>)
      */
     void bindVisibleTaskViews(float targetStackScroll) {
-        bindVisibleTaskViews(targetStackScroll, mIgnoreTasks);
+        bindVisibleTaskViews(targetStackScroll, mIgnoreTasks, false /* ignoreTaskOverrides */);
+    }
+
+    void bindVisibleTaskViews(float targetStackScroll, boolean ignoreTaskOverrides) {
+        bindVisibleTaskViews(targetStackScroll, mIgnoreTasks, ignoreTaskOverrides);
     }
 
     /**
@@ -487,12 +504,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
      *                          target stack scroll.
      * @param ignoreTasksSet The set of tasks to ignore in this rebinding of the visible
      *                       {@link TaskView}s
+     * @param ignoreTaskOverrides If set, the visible task computation will get the transforms for
+     *                            tasks at their non-overridden task progress
      */
-    void bindVisibleTaskViews(float targetStackScroll, ArraySet<Task.TaskKey> ignoreTasksSet) {
+    void bindVisibleTaskViews(float targetStackScroll, ArraySet<Task.TaskKey> ignoreTasksSet,
+            boolean ignoreTaskOverrides) {
         // Get all the task transforms
         ArrayList<Task> tasks = mStack.getStackTasks();
         int[] visibleTaskRange = computeVisibleTaskTransforms(mCurrentTaskTransforms, tasks,
-                mStackScroller.getStackScroll(), targetStackScroll, ignoreTasksSet);
+                mStackScroller.getStackScroll(), targetStackScroll, ignoreTasksSet,
+                ignoreTaskOverrides);
 
         // Return all the invisible children to the pool
         mTmpTaskViewMap.clear();
@@ -502,15 +523,22 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         for (int i = taskViewCount - 1; i >= 0; i--) {
             TaskView tv = taskViews.get(i);
             Task task = tv.getTask();
-            int taskIndex = mStack.indexOfStackTask(task);
-            TaskViewTransform transform = mCurrentTaskTransforms.get(taskIndex);
 
             // Skip ignored tasks
             if (ignoreTasksSet.contains(task.key)) {
                 continue;
             }
 
-            if (task.isFreeformTask() || transform.visible) {
+            // It is possible for the set of lingering TaskViews to differ from the stack if the
+            // stack was updated before the relayout.  If the task view is no longer in the stack,
+            // then just return it back to the view pool.
+            int taskIndex = mStack.indexOfStackTask(task);
+            TaskViewTransform transform = null;
+            if (taskIndex != -1) {
+                transform = mCurrentTaskTransforms.get(taskIndex);
+            }
+
+            if (task.isFreeformTask() || (transform != null && transform.visible)) {
                 mTmpTaskViewMap.put(task.key, tv);
             } else {
                 if (mTouchExplorationEnabled) {
@@ -605,7 +633,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         cancelAllTaskViewAnimations();
 
         // Synchronize the current set of TaskViews
-        bindVisibleTaskViews(mStackScroller.getStackScroll(), ignoreTasksSet);
+        bindVisibleTaskViews(mStackScroller.getStackScroll(), ignoreTasksSet,
+                false /* ignoreTaskOverrides */);
 
         // Animate them to their final transforms with the given animation
         List<TaskView> taskViews = getTaskViews();
@@ -657,7 +686,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                 transform.fillIn(tv);
             } else {
                 mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
-                        focusState, transform, null, true /* forceUpdate */);
+                        focusState, transform, null, true /* forceUpdate */,
+                        false /* ignoreTaskOverrides */);
             }
             transform.visible = true;
         }
@@ -674,7 +704,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
             Task task = tasks.get(i);
             TaskViewTransform transform = transformsOut.get(i);
             mLayoutAlgorithm.getStackTransform(task, stackScroll, focusState, transform, null,
-                    true /* forceUpdate */);
+                    true /* forceUpdate */, true /* ignoreTaskOverrides */);
             transform.visible = true;
         }
     }
@@ -759,9 +789,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                 }
             }
             tv.getViewBounds().setClipBottom(clipBottom);
-            if (!config.useHardwareLayers) {
-                tv.mThumbnailView.updateThumbnailVisibility(clipBottom - tv.getPaddingBottom());
-            }
+            tv.mThumbnailView.updateThumbnailVisibility(clipBottom - tv.getPaddingBottom());
             prevVisibleTv = tv;
         }
         mTaskViewsClipDirty = false;
@@ -860,6 +888,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
                     cancelAllTaskViewAnimations();
                 }
 
+                mLayoutAlgorithm.clearUnfocusedTaskOverrides();
                 willScroll = mAnimationHelper.startScrollToFocusedTaskAnimation(newFocusedTask,
                         requestViewFocus);
             } else {
@@ -1107,15 +1136,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
     }
 
     /**
-     * This is ONLY used from the Recents component to update the dummy stack view for purposes
-     * of getting the task rect to animate to.
-     */
-    public void updateLayoutForStack(TaskStack stack) {
-        mStack = stack;
-        updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET);
-    }
-
-    /**
      * Computes the maximum number of visible tasks and thumbnails. Requires that
      * updateLayoutForStack() is called first.
      */
@@ -1162,11 +1182,16 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
 
         // If this is the first layout, then scroll to the front of the stack, then update the
         // TaskViews with the stack so that we can lay them out
-        if (mAwaitingFirstLayout) {
-            mStackScroller.setStackScrollToInitialState();
+        // TODO: The second check is a workaround for wacky layouts that we get while docking via
+        //       long pressing the recents button
+        if (mAwaitingFirstLayout ||
+                (mStackScroller.getStackScroll() == mLayoutAlgorithm.mInitialScrollP)) {
+            updateToInitialState();
         }
+
         // Rebind all the views, including the ignore ones
-        bindVisibleTaskViews(mStackScroller.getStackScroll(), EMPTY_TASK_SET);
+        bindVisibleTaskViews(mStackScroller.getStackScroll(), EMPTY_TASK_SET,
+                false /* ignoreTaskOverrides */);
 
         // Measure each of the TaskViews
         mTmpTaskViews.clear();
@@ -1405,7 +1430,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
     public void onReturnViewToPool(TaskView tv) {
         final Task task = tv.getTask();
 
-        // Report that this tasks's data is no longer being used
+        // Report that this task's data is no longer being used
         Recents.getTaskLoader().unloadTaskData(task);
 
         // Reset the view properties and view state
@@ -1458,7 +1483,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         Recents.getTaskLoader().loadTaskData(task, true /* fetchAndInvalidateThumbnails */);
 
         // If the doze trigger has already fired, then update the state for this task view
-        if (mUIDozeTrigger.hasTriggered()) {
+        if (mUIDozeTrigger.isAsleep()) {
             tv.setNoUserInteractionState();
         }
 
@@ -1652,12 +1677,6 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         }
     }
 
-    public final void onBusEvent(RecentsVisibilityChangedEvent event) {
-        if (!event.visible) {
-            reset();
-        }
-    }
-
     public final void onBusEvent(DragStartEvent event) {
         // Ensure that the drag task is not animated
         addIgnoreTask(event.task);
@@ -1754,12 +1773,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         event.taskView.setLeftTopRightBottom(taskViewRect.left, taskViewRect.top,
                 taskViewRect.right, taskViewRect.bottom);
 
-        // Animate all the TaskViews back into position
+        // Animate the non-drag TaskViews back into position
         mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(),
                 mTmpTransform, null);
         event.getAnimationTrigger().increment();
         relayoutTaskViews(new AnimationProps(DEFAULT_SYNC_STACK_DURATION,
                 Interpolators.FAST_OUT_SLOW_IN));
+
+        // Animate the drag TaskView back into position
         updateTaskViewToTransform(event.taskView, mTmpTransform,
                 new AnimationProps(DEFAULT_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN,
                         event.getAnimationTrigger().decrementOnAnimationEnd()));
@@ -1832,31 +1853,28 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
         mAnimationHelper.startHideHistoryAnimation();
     }
 
-    public final void onBusEvent(TaskStackUpdatedEvent event) {
+    public final void onBusEvent(MultiWindowStateChangedEvent event) {
         if (!event.inMultiWindow) {
-            // Scroll the stack to the front after it has been updated
-            event.addPostAnimationCallback(new Runnable() {
+            // Scroll the stack to the front to see the undocked task
+            mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, new Runnable() {
                 @Override
                 public void run() {
-                    mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP,
-                            null /* postScrollRunnable */);
+                    List<TaskView> taskViews = getTaskViews();
+                    int taskViewCount = taskViews.size();
+                    for (int i = 0; i < taskViewCount; i++) {
+                        TaskView tv = taskViews.get(i);
+                        tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled,
+                                tv.mIsDisabledInSafeMode);
+                    }
                 }
             });
         }
-        // When the multi-window state changes, rebind all task view headers again to update their
-        // dockable state
-        event.addPostAnimationCallback(new Runnable() {
-            @Override
-            public void run() {
-                List<TaskView> taskViews = getTaskViews();
-                int taskViewCount = taskViews.size();
-                for (int i = 0; i < taskViewCount; i++) {
-                    TaskView tv = taskViews.get(i);
-                    tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled,
-                            tv.mIsDisabledInSafeMode);
-                }
-            }
-        });
+    }
+
+    public final void onBusEvent(ConfigurationChangedEvent event) {
+        mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+        mLayoutAlgorithm.initialize(mStackBounds,
+                TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
     }
 
     /**
index 333df9d..ad46abd 100644 (file)
@@ -115,13 +115,8 @@ public class TaskStackViewScroller {
      * @return whether the stack progress changed.
      */
     public boolean setStackScrollToInitialState() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
         float prevStackScrollP = mStackScrollP;
-        if (ssp.hasDockedTask()) {
-            setStackScroll(mLayoutAlgorithm.mMaxScrollP);
-        } else {
-            setStackScroll(mLayoutAlgorithm.mInitialScrollP);
-        }
+        setStackScroll(mLayoutAlgorithm.mInitialScrollP);
         return Float.compare(prevStackScrollP, mStackScrollP) != 0;
     }
 
index 20933ee..52f8fc8 100644 (file)
@@ -446,7 +446,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
             }
 
             // Pick up the newly visible views, not including the deleting tasks
-            mSv.bindVisibleTaskViews(newStackScroll);
+            mSv.bindVisibleTaskViews(newStackScroll, true /* ignoreTaskOverrides */);
 
             // Get the final set of task transforms (with task removed)
             mSv.getLayoutTaskTransforms(newStackScroll, TaskStackLayoutAlgorithm.STATE_UNFOCUSED,
@@ -486,6 +486,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback {
         mSv.getScroller().setStackScroll(mTargetStackScroll, null);
         // Update the focus state to the final focus state
         mSv.getStackAlgorithm().setFocusState(TaskStackLayoutAlgorithm.STATE_UNFOCUSED);
+        mSv.getStackAlgorithm().clearUnfocusedTaskOverrides();
         // Remove the task view from the stack
         EventBus.getDefault().send(new TaskViewDismissedEvent(tv.getTask(), tv));
         // Stop tracking this deletion animation
index 0c78e6a..0bc7f89 100644 (file)
@@ -77,6 +77,24 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
 
     /**
      * The dim overlay is generally calculated from the task progress, but occasionally (like when
+     * launching) needs to be animated independently of the task progress.  This call is only used
+     * when animating the task into Recents, when the header dim is already applied
+     */
+    public static final Property<TaskView, Float> DIM_ALPHA_WITHOUT_HEADER =
+            new FloatProperty<TaskView>("dimAlphaWithoutHeader") {
+                @Override
+                public void setValue(TaskView tv, float dimAlpha) {
+                    tv.setDimAlphaWithoutHeader(dimAlpha);
+                }
+
+                @Override
+                public Float get(TaskView tv) {
+                    return tv.getDimAlpha();
+                }
+            };
+
+    /**
+     * The dim overlay is generally calculated from the task progress, but occasionally (like when
      * launching) needs to be animated independently of the task progress.
      */
     public static final Property<TaskView, Float> DIM_ALPHA =
@@ -175,11 +193,13 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
     }
 
     /** Resets this TaskView for reuse. */
-    void reset() {
-        resetViewProperties();
+    void onResume(boolean isResumingFromVisible) {
         resetNoUserInteractionState();
         readSystemFlags();
-        setClipViewInStack(false);
+        if (!isResumingFromVisible) {
+            resetViewProperties();
+            setClipViewInStack(false);
+        }
         setCallbacks(null);
     }
 
@@ -388,47 +408,24 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
      * Sets the current dim.
      */
     public void setDimAlpha(float dimAlpha) {
-        RecentsConfiguration config = Recents.getConfiguration();
-
-        int dimAlphaInt = (int) (dimAlpha * 255);
         mDimAlpha = dimAlpha;
-        if (config.useHardwareLayers) {
-            // Defer setting hardware layers if we have not yet measured, or there is no dim to draw
-            if (getMeasuredWidth() > 0 && getMeasuredHeight() > 0) {
-                mDimColorFilter.setColor(Color.argb(dimAlphaInt, 0, 0, 0));
-                mDimLayerPaint.setColorFilter(mDimColorFilter);
-                mContent.setLayerType(LAYER_TYPE_HARDWARE, mDimLayerPaint);
-            }
-        } else {
-            mThumbnailView.setDimAlpha(dimAlpha);
-            mHeaderView.setDimAlpha(dimAlpha);
-        }
+        mThumbnailView.setDimAlpha(dimAlpha);
+        mHeaderView.setDimAlpha(dimAlpha);
     }
 
     /**
-     * Returns the current dim.
+     * Sets the current dim without updating the header's dim.
      */
-    public float getDimAlpha() {
-        return mDimAlpha;
+    public void setDimAlphaWithoutHeader(float dimAlpha) {
+        mDimAlpha = dimAlpha;
+        mThumbnailView.setDimAlpha(dimAlpha);
     }
 
     /**
-     * Animates the dim to the given value.
+     * Returns the current dim.
      */
-    void animateDimAlpha(float toDimAlpha, AnimationProps animation) {
-        // Animate the dim into view as well
-        if (Float.compare(toDimAlpha, getDimAlpha()) != 0) {
-            Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
-                    DIM_ALPHA, getDimAlpha(), toDimAlpha));
-            if (animation.getListener() != null) {
-                anim.addListener(animation.getListener());
-            }
-            anim.start();
-        } else {
-            if (animation.getListener() != null) {
-                animation.getListener().onAnimationEnd(null);
-            }
-        }
+    public float getDimAlpha() {
+        return mDimAlpha;
     }
 
     /**
@@ -517,18 +514,20 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
     @Override
     public void onPrepareLaunchTargetForEnterAnimation() {
         // These values will be animated in when onStartLaunchTargetEnterAnimation() is called
-        setDimAlpha(0);
+        setDimAlphaWithoutHeader(0);
         mActionButtonView.setAlpha(0f);
     }
 
     @Override
-    public void onStartLaunchTargetEnterAnimation(int duration, boolean screenPinningEnabled,
-            ReferenceCountedTrigger postAnimationTrigger) {
-        // Un-dim the view before/while launching the target
-        AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT)
-                .setListener(postAnimationTrigger.decrementOnAnimationEnd());
+    public void onStartLaunchTargetEnterAnimation(TaskViewTransform transform, int duration,
+            boolean screenPinningEnabled, ReferenceCountedTrigger postAnimationTrigger) {
+        // Dim the view after the app window transitions down into recents
         postAnimationTrigger.increment();
-        animateDimAlpha(0, animation);
+        AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT);
+        Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
+                DIM_ALPHA_WITHOUT_HEADER, getDimAlpha(), transform.dimAlpha));
+        anim.addListener(postAnimationTrigger.decrementOnAnimationEnd());
+        anim.start();
 
         if (screenPinningEnabled) {
             showActionButton(true /* fadeIn */, duration /* fadeInDuration */);
@@ -540,7 +539,9 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
             ReferenceCountedTrigger postAnimationTrigger) {
         // Un-dim the view before/while launching the target
         AnimationProps animation = new AnimationProps(duration, Interpolators.ALPHA_OUT);
-        animateDimAlpha(0, animation);
+        Animator anim = animation.apply(AnimationProps.DIM_ALPHA, ObjectAnimator.ofFloat(this,
+                DIM_ALPHA, getDimAlpha(), 0));
+        anim.start();
 
         postAnimationTrigger.increment();
         hideActionButton(true /* fadeOut */, duration,
@@ -603,7 +604,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
         EventBus.getDefault().send(new LaunchTaskEvent(this, mTask, null, INVALID_STACK_ID,
                 screenPinningRequested));
 
-        MetricsLogger.action(v.getContext(), MetricsEvent.OVERVIEW_SELECT,
+        MetricsLogger.action(v.getContext(), MetricsEvent.ACTION_OVERVIEW_SELECT,
                 mTask.key.getComponent().toString());
     }
 
index 05a8527..b2a7d90 100644 (file)
@@ -347,9 +347,11 @@ public class TaskViewHeader extends FrameLayout
      * Sets the dim alpha, only used when we are not using hardware layers.
      * (see RecentsConfiguration.useHardwareLayers)
      */
-    void setDimAlpha(float dimAlpha) {
-        mDimAlpha = dimAlpha;
-        updateBackgroundColor(mBackground.getColor(), dimAlpha);
+    public void setDimAlpha(float dimAlpha) {
+        if (Float.compare(mDimAlpha, dimAlpha) != 0) {
+            mDimAlpha = dimAlpha;
+            updateBackgroundColor(mBackground.getColor(), dimAlpha);
+        }
     }
 
     /**
@@ -377,7 +379,9 @@ public class TaskViewHeader extends FrameLayout
         int primaryColor = disabledInSafeMode
                 ? mDisabledTaskBarBackgroundColor
                 : t.colorPrimary;
-        updateBackgroundColor(primaryColor, mDimAlpha);
+        if (mBackground.getColor() != primaryColor) {
+            updateBackgroundColor(primaryColor, mDimAlpha);
+        }
         if (t.icon != null) {
             mIconView.setImageDrawable(t.icon);
         }
index 9bd645d..143f160 100644 (file)
@@ -194,6 +194,7 @@ public abstract class BaseStatusBar extends SystemUI implements
     // public mode, private notifications, etc
     private boolean mLockscreenPublicMode = false;
     private final SparseBooleanArray mUsersAllowingPrivateNotifications = new SparseBooleanArray();
+    private final SparseBooleanArray mUsersAllowingNotifications = new SparseBooleanArray();
 
     private UserManager mUserManager;
     private int mDensity;
@@ -959,7 +960,7 @@ public abstract class BaseStatusBar extends SystemUI implements
         }, false /* afterKeyguardGone */);
     }
 
-    private void bindGuts(ExpandableNotificationRow row) {
+    private void bindGuts(final ExpandableNotificationRow row) {
         row.inflateGuts();
         final StatusBarNotification sbn = row.getStatusBarNotification();
         PackageManager pmUser = getPackageManagerForUser(mContext, sbn.getUser().getIdentifier());
@@ -983,7 +984,7 @@ public abstract class BaseStatusBar extends SystemUI implements
             pkgicon = pmUser.getDefaultActivityIcon();
         }
 
-        ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
+        ((ImageView) row.findViewById(R.id.app_icon)).setImageDrawable(pkgicon);
         ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
 
         final View settingsButton = guts.findViewById(R.id.more_settings);
@@ -1003,7 +1004,17 @@ public abstract class BaseStatusBar extends SystemUI implements
             @Override
             public void onClick(View v) {
                 guts.saveImportance(sbn);
-                dismissPopups();
+
+                int[] rowLocation = new int[2];
+                int[] doneLocation = new int[2];
+                row.getLocationOnScreen(rowLocation);
+                v.getLocationOnScreen(doneLocation);
+
+                final int centerX = v.getWidth() / 2;
+                final int centerY = v.getHeight() / 2;
+                final int x = doneLocation[0] - rowLocation[0] + centerX;
+                final int y = doneLocation[1] - rowLocation[1] + centerY;
+                dismissPopups(x, y);
             }
         });
 
@@ -1049,7 +1060,7 @@ public abstract class BaseStatusBar extends SystemUI implements
                 // Post to ensure the the guts are properly laid out.
                 guts.post(new Runnable() {
                     public void run() {
-                        dismissPopups();
+                        dismissPopups(-1 /* x */, -1 /* y */, false /* resetGear */);
                         guts.setVisibility(View.VISIBLE);
                         final double horz = Math.max(guts.getWidth() - x, x);
                         final double vert = Math.max(guts.getHeight() - y, y);
@@ -1079,14 +1090,20 @@ public abstract class BaseStatusBar extends SystemUI implements
 
     @Override
     public void onGearDisplayed(ExpandableNotificationRow row) {
+        MetricsLogger.action(mContext, MetricsEvent.ACTION_REVEAL_GEAR,
+                row.getStatusBarNotification().getPackageName());
         mNotificationGearDisplayed = row;
     }
 
     public void dismissPopups() {
-        dismissPopups(-1, -1);
+        dismissPopups(-1 /* x */, -1 /* y */, true /* resetGear */);
     }
 
     private void dismissPopups(int x, int y) {
+        dismissPopups(x, y, true /* resetGear */);
+    }
+
+    public void dismissPopups(int x, int y, boolean resetGear) {
         if (mNotificationGutsExposed != null) {
             final NotificationGuts v = mNotificationGutsExposed;
             mNotificationGutsExposed = null;
@@ -1114,8 +1131,7 @@ public abstract class BaseStatusBar extends SystemUI implements
             v.setExposed(false);
             mStackScroller.onHeightChanged(null, true /* needsAnimation */);
         }
-
-        if (mNotificationGearDisplayed != null) {
+        if (resetGear && mNotificationGearDisplayed != null) {
             mNotificationGearDisplayed.resetTranslation();
             mNotificationGearDisplayed = null;
         }
@@ -1289,6 +1305,26 @@ public abstract class BaseStatusBar extends SystemUI implements
     }
 
     /**
+     * Has the given user chosen to allow notifications to be shown even when the lockscreen is in
+     * "public" (secure & locked) mode?
+     */
+    public boolean userAllowsNotificationsInPublic(int userHandle) {
+        if (userHandle == UserHandle.USER_ALL) {
+            return true;
+        }
+
+        if (mUsersAllowingNotifications.indexOfKey(userHandle) < 0) {
+            final boolean allowed = 0 != Settings.Secure.getIntForUser(
+                    mContext.getContentResolver(),
+                    Settings.Secure.LOCK_SCREEN_SHOW_NOTIFICATIONS, 0, userHandle);
+            mUsersAllowingNotifications.append(userHandle, allowed);
+            return allowed;
+        }
+
+        return mUsersAllowingNotifications.get(userHandle);
+    }
+
+    /**
      * Has the given user chosen to allow their private (full) notifications to be shown even
      * when the lockscreen is in "public" (secure & locked) mode?
      */
@@ -1320,13 +1356,30 @@ public abstract class BaseStatusBar extends SystemUI implements
     }
 
     /**
-     * Returns true if we're on a secure lockscreen and the user wants to hide "sensitive"
-     * notification data. If so, private notifications should show their (possibly
-     * auto-generated) publicVersion, and secret notifications should be totally invisible.
+     * Returns true if we're on a secure lockscreen and the user wants to hide notification data.
+     * If so, notifications should be hidden.
+     */
+    @Override  // NotificationData.Environment
+    public boolean shouldHideNotifications(int userid) {
+        return isLockscreenPublicMode() && !userAllowsNotificationsInPublic(userid);
+    }
+
+    /**
+     * Returns true if we're on a secure lockscreen and the user wants to hide notifications via
+     * package-specific override.
+     */
+    @Override // NotificationDate.Environment
+    public boolean shouldHideNotifications(String key) {
+        return isLockscreenPublicMode()
+                && mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_SECRET;
+    }
+
+    /**
+     * Returns true if we're on a secure lockscreen.
      */
     @Override  // NotificationData.Environment
-    public boolean shouldHideSensitiveContents(int userid) {
-        return isLockscreenPublicMode() && !userAllowsPrivateNotificationsInPublic(userid);
+    public boolean onSecureLockScreen() {
+        return isLockscreenPublicMode();
     }
 
     public void onNotificationClear(StatusBarNotification notification) {
@@ -1838,7 +1891,7 @@ public abstract class BaseStatusBar extends SystemUI implements
         }
     }
 
-    protected abstract boolean isPanelFullyCollapsed();
+    public abstract boolean isPanelFullyCollapsed();
 
     /**
      * Cancel this notification and tell the StatusBarManagerService / NotificationManagerService
index b326552..7f87c3c 100644 (file)
@@ -169,21 +169,23 @@ public class DragDownHelper implements Gefingerpoken {
                 ? RUBBERBAND_FACTOR_EXPANDABLE
                 : RUBBERBAND_FACTOR_STATIC;
         float rubberband = heightDelta * rubberbandFactor;
-        if (expandable && (rubberband + child.getMinHeight()) > child.getMaxContentHeight()) {
-            float overshoot = (rubberband + child.getMinHeight()) - child.getMaxContentHeight();
+        if (expandable
+                && (rubberband + child.getMinExpandHeight()) > child.getMaxContentHeight()) {
+            float overshoot =
+                    (rubberband + child.getMinExpandHeight()) - child.getMaxContentHeight();
             overshoot *= (1 - RUBBERBAND_FACTOR_STATIC);
             rubberband -= overshoot;
         }
-        child.setActualHeight((int) (child.getMinHeight() + rubberband));
+        child.setActualHeight((int) (child.getMinExpandHeight() + rubberband));
     }
 
     private void cancelExpansion(final ExpandableView child) {
-        if (child.getActualHeight() == child.getMinHeight()) {
+        if (child.getActualHeight() == child.getMinExpandHeight()) {
             mCallback.setUserLockedChild(child, false);
             return;
         }
         ObjectAnimator anim = ObjectAnimator.ofInt(child, "actualHeight",
-                child.getActualHeight(), child.getMinHeight());
+                child.getActualHeight(), child.getMinExpandHeight());
         anim.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
         anim.setDuration(SPRING_BACK_ANIMATION_LENGTH_MS);
         anim.addListener(new AnimatorListenerAdapter() {
index da125d8..12a83fd 100644 (file)
@@ -105,7 +105,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
     private boolean mClearable;
     private ExpansionLogger mLogger;
     private String mLoggingKey;
-    private boolean mWasReset;
     private NotificationSettingsIconRow mSettingsIconRow;
     private NotificationGuts mGuts;
     private NotificationData.Entry mEntry;
@@ -412,7 +411,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
     }
 
     public ExpandableNotificationRow getViewAtPosition(float y) {
-        if (!mIsSummaryWithChildren || !mChildrenExpanded) {
+        if (!mIsSummaryWithChildren || !mChildrenExpanded
+                || (getNotificationChildren().size() == 1 && isClearable())) {
             return this;
         } else {
             ExpandableNotificationRow view = mChildrenContainer.getViewAtPosition(y);
@@ -614,20 +614,16 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
         mShowingPublicInitialized = false;
         mIsSystemExpanded = false;
         mOnKeyguard = false;
-        mPublicLayout.reset(mIsHeadsUp);
-        mPrivateLayout.reset(mIsHeadsUp);
+        mPublicLayout.reset();
+        mPrivateLayout.reset();
         resetHeight();
         resetTranslation();
         logExpansionEvent(false, wasExpanded);
     }
 
     public void resetHeight() {
-        if (mIsHeadsUp) {
-            resetActualHeight();
-        }
         mMaxExpandHeight = 0;
         mHeadsUpHeight = 0;
-        mWasReset = true;
         onHeightReset();
         requestLayout();
     }
@@ -656,7 +652,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
                 mGuts = (NotificationGuts) inflated;
                 mGuts.setClipTopAmount(getClipTopAmount());
                 mGuts.setActualHeight(getActualHeight());
-                mTranslateableViews.add(mGuts);
                 mGutsStub = null;
             }
         });
@@ -684,7 +679,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
         mTranslateableViews.remove(mGutsStub);
     }
 
-    public void setTranslationForOutline(float translationX) {
+    private void setTranslationForOutline(float translationX) {
         setOutlineRect(false, translationX, getTop(), getRight() + translationX, getBottom());
     }
 
@@ -704,6 +699,46 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
         if (mTranslateAnim != null) {
             mTranslateAnim.cancel();
         }
+        mTranslateAnim = (AnimatorSet) getTranslateViewAnimator(leftTarget,
+                null /* updateListener */);
+        if (mTranslateAnim != null) {
+            mTranslateAnim.start();
+        }
+    }
+
+    @Override
+    public void setTranslation(float translationX) {
+        if (areGutsExposed()) {
+            // Don't translate if guts are showing.
+            return;
+        }
+        // Translate the group of views
+        for (int i = 0; i < mTranslateableViews.size(); i++) {
+            if (mTranslateableViews.get(i) != null) {
+                mTranslateableViews.get(i).setTranslationX(translationX);
+            }
+        }
+        setTranslationForOutline(translationX);
+        if (mSettingsIconRow != null) {
+            mSettingsIconRow.updateSettingsIcons(translationX, getMeasuredWidth());
+        }
+    }
+
+    @Override
+    public float getTranslation() {
+        if (mTranslateableViews != null && mTranslateableViews.size() > 0) {
+            // All of the views in the list should have same translation, just use first one.
+            return mTranslateableViews.get(0).getTranslationX();
+        }
+        return 0;
+    }
+
+    public Animator getTranslateViewAnimator(final float leftTarget,
+            AnimatorUpdateListener listener) {
+        if (areGutsExposed()) {
+            // No translation if guts are exposed.
+            return null;
+        }
         AnimatorSet set = new AnimatorSet();
         if (mTranslateableViews != null) {
             for (int i = 0; i < mTranslateableViews.size(); i++) {
@@ -715,8 +750,15 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
                         @Override
                         public void onAnimationUpdate(ValueAnimator animation) {
                             setTranslationForOutline((float) animation.getAnimatedValue());
+                            if (mSettingsIconRow != null) {
+                                mSettingsIconRow.updateSettingsIcons(
+                                        (float) animation.getAnimatedValue(), getMeasuredWidth());
+                            }
                         }
                     });
+                    if (listener != null) {
+                        translateAnim.addUpdateListener(listener);
+                    }
                 }
                 translateAnim.addListener(new AnimatorListenerAdapter() {
                     @Override
@@ -730,8 +772,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
                 set.play(translateAnim);
             }
         }
-        mTranslateAnim = set;
-        set.start();
+        return set;
     }
 
     public float getSpaceForGear() {
@@ -748,10 +789,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
         return mSettingsIconRow;
     }
 
-    public ArrayList<View> getContentViews() {
-        return mTranslateableViews;
-    }
-
     public void inflateGuts() {
         if (mGuts == null) {
             mGutsStub.inflate();
@@ -922,18 +959,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
         return mStatusBarNotification != null && mStatusBarNotification.isClearable();
     }
 
-    /**
-     * Apply an expansion state to the layout.
-     */
-    public void applyExpansionToLayout() {
-        boolean expand = isExpanded();
-        if (expand && mExpandable) {
-            setActualHeight(mMaxExpandHeight);
-        } else {
-            setActualHeight(getMinHeight());
-        }
-    }
-
     @Override
     public int getIntrinsicHeight() {
         if (isUserLocked()) {
@@ -1015,12 +1040,7 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        boolean updateExpandHeight = mMaxExpandHeight == 0 && !mWasReset;
         updateMaxHeights();
-        if (updateExpandHeight) {
-            applyExpansionToLayout();
-        }
-        mWasReset = false;
     }
 
     private void updateMaxHeights() {
@@ -1053,6 +1073,14 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
 
     public void setHideSensitiveForIntrinsicHeight(boolean hideSensitive) {
         mHideSensitiveForIntrinsicHeight = hideSensitive;
+        if (mIsSummaryWithChildren) {
+            List<ExpandableNotificationRow> notificationChildren =
+                    mChildrenContainer.getNotificationChildren();
+            for (int i = 0; i < notificationChildren.size(); i++) {
+                ExpandableNotificationRow child = notificationChildren.get(i);
+                child.setHideSensitiveForIntrinsicHeight(hideSensitive);
+            }
+        }
     }
 
     public void setHideSensitive(boolean hideSensitive, boolean animated, long delay,
@@ -1161,6 +1189,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
         return mMaxExpandHeight;
     }
 
+    public boolean areGutsExposed() {
+        return (mGuts != null && mGuts.areGutsExposed());
+    }
+
     @Override
     public boolean isContentExpandable() {
         NotificationContentView showingLayout = getShowingLayout();
@@ -1175,6 +1207,10 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
     @Override
     public void setActualHeight(int height, boolean notifyListeners) {
         super.setActualHeight(height, notifyListeners);
+        if (mGuts != null && mGuts.areGutsExposed()) {
+            mGuts.setActualHeight(height);
+            return;
+        }
         int contentHeight = Math.max(getMinHeight(), height);
         mPrivateLayout.setContentHeight(contentHeight);
         mPublicLayout.setContentHeight(contentHeight);
@@ -1184,7 +1220,6 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
         if (mGuts != null) {
             mGuts.setActualHeight(height);
         }
-        invalidate();
     }
 
     @Override
@@ -1211,8 +1246,8 @@ public class ExpandableNotificationRow extends ActivatableNotificationView {
 
     @Override
     public int getMinExpandHeight() {
-        if (mIsSummaryWithChildren && !mOnKeyguard) {
-            return mChildrenContainer.getMinExpandHeight();
+        if (mIsSummaryWithChildren && !mShowingPublic) {
+            return mChildrenContainer.getMinExpandHeight(mOnKeyguard);
         }
         return getMinHeight();
     }
index 1ff87f5..c0e4340 100644 (file)
@@ -36,7 +36,6 @@ public abstract class ExpandableView extends FrameLayout {
     protected OnHeightChangedListener mOnHeightChangedListener;
     private int mActualHeight;
     protected int mClipTopAmount;
-    private boolean mActualHeightInitialized;
     private boolean mDark;
     private ArrayList<View> mMatchParentViews = new ArrayList<View>();
     private int mClipTopOptimization;
@@ -99,28 +98,9 @@ public abstract class ExpandableView extends FrameLayout {
     @Override
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
-        if (!mActualHeightInitialized && mActualHeight == 0) {
-            int initialHeight = getInitialHeight();
-            if (initialHeight != 0) {
-                setActualHeight(initialHeight);
-            }
-        }
         updateClipping();
     }
 
-    /**
-     * Resets the height of the view on the next layout pass
-     */
-    protected void resetActualHeight() {
-        mActualHeight = 0;
-        mActualHeightInitialized = false;
-        requestLayout();
-    }
-
-    protected int getInitialHeight() {
-        return getHeight();
-    }
-
     @Override
     public boolean pointInView(float localX, float localY, float slop) {
         float top = mClipTopAmount;
@@ -137,7 +117,6 @@ public abstract class ExpandableView extends FrameLayout {
      * @param notifyListeners Whether the listener should be informed about the change.
      */
     public void setActualHeight(int actualHeight, boolean notifyListeners) {
-        mActualHeightInitialized = true;
         mActualHeight = actualHeight;
         updateClipping();
         if (notifyListeners) {
@@ -283,6 +262,20 @@ public abstract class ExpandableView extends FrameLayout {
     public void setBelowSpeedBump(boolean below) {
     }
 
+    /**
+     * Sets the translation of the view.
+     */
+    public void setTranslation(float translation) {
+        setTranslationX(translation);
+    }
+
+    /**
+     * Gets the translation of the view.
+     */
+    public float getTranslation() {
+        return getTranslationX();
+    }
+
     public void onHeightReset() {
         if (mOnHeightChangedListener != null) {
             mOnHeightChangedListener.onReset(this);
index 7c11161..b94c15b 100644 (file)
@@ -92,7 +92,14 @@ public class NotificationContentView extends FrameLayout {
             = new ViewTreeObserver.OnPreDrawListener() {
         @Override
         public boolean onPreDraw() {
-            mAnimate = true;
+            // We need to post since we don't want the notification to animate on the very first
+            // frame
+            post(new Runnable() {
+                @Override
+                public void run() {
+                    mAnimate = true;
+                }
+            });
             getViewTreeObserver().removeOnPreDrawListener(this);
             return true;
         }
@@ -113,7 +120,7 @@ public class NotificationContentView extends FrameLayout {
                 R.dimen.min_notification_layout_height);
         mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_content_margin_end);
-        reset(true);
+        reset();
     }
 
     public void setHeights(int smallHeight, int headsUpMaxHeight, int maxHeight) {
@@ -248,7 +255,7 @@ public class NotificationContentView extends FrameLayout {
         updateVisibility();
     }
 
-    public void reset(boolean resetActualHeight) {
+    public void reset() {
         if (mContractedChild != null) {
             mContractedChild.animate().cancel();
             removeView(mContractedChild);
@@ -264,10 +271,6 @@ public class NotificationContentView extends FrameLayout {
         mContractedChild = null;
         mExpandedChild = null;
         mHeadsUpChild = null;
-        mVisibleType = VISIBLE_TYPE_CONTRACTED;
-        if (resetActualHeight) {
-            mContentHeight = mSmallHeight;
-        }
     }
 
     public View getContractedChild() {
@@ -477,12 +480,18 @@ public class NotificationContentView extends FrameLayout {
     private void animateToVisibleType(int visibleType) {
         final TransformableView shownView = getTransformableViewForVisibleType(visibleType);
         final TransformableView hiddenView = getTransformableViewForVisibleType(mVisibleType);
+        if (shownView == hiddenView) {
+            shownView.setVisible(true);
+            return;
+        }
         shownView.transformFrom(hiddenView);
         getViewForVisibleType(visibleType).setVisibility(View.VISIBLE);
         hiddenView.transformTo(shownView, new Runnable() {
             @Override
             public void run() {
-                hiddenView.setVisible(false);
+                if (hiddenView != getTransformableViewForVisibleType(mVisibleType)) {
+                    hiddenView.setVisible(false);
+                }
             }
         });
     }
@@ -543,6 +552,9 @@ public class NotificationContentView extends FrameLayout {
                     || mContainingNotification.isExpanded()
                     ? mContainingNotification.getMaxContentHeight()
                     : mContainingNotification.getShowingLayout().getMinHeight();
+            if (height == 0) {
+                height = mContentHeight;
+            }
             int expandedVisualType = getVisualTypeForHeight(height);
             int collapsedVisualType = getVisualTypeForHeight(
                     mContainingNotification.getMinExpandHeight());
@@ -550,7 +562,12 @@ public class NotificationContentView extends FrameLayout {
                     ? expandedVisualType
                     : collapsedVisualType;
         }
-        int viewHeight = Math.min(mContentHeight, mContainingNotification.getIntrinsicHeight());
+        int intrinsicHeight = mContainingNotification.getIntrinsicHeight();
+        int viewHeight = mContentHeight;
+        if (intrinsicHeight != 0) {
+            // the intrinsicHeight might be 0 because it was just reset.
+            viewHeight = Math.min(mContentHeight, intrinsicHeight);
+        }
         return getVisualTypeForHeight(viewHeight);
     }
 
@@ -631,7 +648,6 @@ public class NotificationContentView extends FrameLayout {
         mBeforeN = entry.targetSdk < Build.VERSION_CODES.N;
         updateSingleLineView();
         applyRemoteInput(entry);
-        selectLayout(false /* animate */, true /* force */);
         if (mContractedChild != null) {
             mContractedWrapper.notifyContentUpdated(entry.notification);
         }
@@ -641,6 +657,7 @@ public class NotificationContentView extends FrameLayout {
         if (mHeadsUpChild != null) {
             mHeadsUpWrapper.notifyContentUpdated(entry.notification);
         }
+        selectLayout(false /* animate */, true /* force */);
         setDark(mDark, false /* animate */, 0 /* delay */);
     }
 
index 7cb9127..c9fe2bd 100644 (file)
@@ -353,8 +353,10 @@ public class NotificationData {
             return true;
         }
 
-        if (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET &&
-                mEnvironment.shouldHideSensitiveContents(sbn.getUserId())) {
+        if (mEnvironment.onSecureLockScreen() &&
+                (sbn.getNotification().visibility == Notification.VISIBILITY_SECRET
+                        || mEnvironment.shouldHideNotifications(sbn.getUserId())
+                        || mEnvironment.shouldHideNotifications(sbn.getKey()))) {
             return true;
         }
 
@@ -433,7 +435,9 @@ public class NotificationData {
      * Provides access to keyguard state and user settings dependent data.
      */
     public interface Environment {
-        public boolean shouldHideSensitiveContents(int userid);
+        public boolean onSecureLockScreen();
+        public boolean shouldHideNotifications(int userid);
+        public boolean shouldHideNotifications(String key);
         public boolean isDeviceProvisioned();
         public boolean isNotificationForCurrentProfiles(StatusBarNotification sbn);
         public String getCurrentMediaNotificationKey();
index 1c16bdc..45a24a0 100644 (file)
@@ -130,7 +130,12 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
             importanceSlider.setVisibility(View.VISIBLE);
             importanceButtons.setVisibility(View.GONE);
         } else {
-            bindToggles(importanceButtons, sbn, systemApp);
+            int userImportance = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
+            try {
+                userImportance =
+                        mINotificationManager.getImportance(sbn.getPackageName(), sbn.getUid());
+            } catch (RemoteException e) {}
+            bindToggles(importanceButtons, userImportance, systemApp);
             importanceButtons.setVisibility(View.VISIBLE);
             importanceSlider.setVisibility(View.GONE);
         }
@@ -144,7 +149,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
             if (mBlock.isChecked()) {
                 progress = NotificationListenerService.Ranking.IMPORTANCE_NONE;
             } else if (mSilent.isChecked()) {
-                progress = NotificationListenerService.Ranking.IMPORTANCE_DEFAULT;
+                progress = NotificationListenerService.Ranking.IMPORTANCE_LOW;
             } else {
                 progress = NotificationListenerService.Ranking.IMPORTANCE_UNSPECIFIED;
             }
@@ -158,7 +163,7 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
         }
     }
 
-    private void bindToggles(final View importanceButtons, final StatusBarNotification sbn,
+    private void bindToggles(final View importanceButtons, final int importance,
             final boolean systemApp) {
         mBlock = (RadioButton) importanceButtons.findViewById(R.id.block_importance);
         mSilent = (RadioButton) importanceButtons.findViewById(R.id.silent_importance);
@@ -169,7 +174,11 @@ public class NotificationGuts extends LinearLayout implements TunerService.Tunab
         } else {
             mReset.setText(mContext.getString(R.string.do_not_silence_block));
         }
-        mReset.setChecked(true);
+        if (importance == NotificationListenerService.Ranking.IMPORTANCE_LOW) {
+            mSilent.setChecked(true);
+        } else {
+            mReset.setChecked(true);
+        }
     }
 
     private void bindSlider(final View importanceSlider, final StatusBarNotification sbn,
index 4491ebd..375459f 100644 (file)
@@ -33,7 +33,7 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
         /**
          * Called when the gear behind a notification is touched.
          */
-        public void onGearTouched(ExpandableNotificationRow row);
+        public void onGearTouched(ExpandableNotificationRow row, int x, int y);
     }
 
     private ExpandableNotificationRow mParent;
@@ -45,6 +45,8 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
     private boolean mSettingsFadedIn = false;
     private boolean mAnimating = false;
     private boolean mOnLeft = true;
+    private int[] mGearLocation = new int[2];
+    private int[] mParentLocation = new int[2];
 
     public NotificationSettingsIconRow(Context context) {
         this(context, null);
@@ -74,6 +76,12 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
         resetState();
     }
 
+    public void resetState() {
+        setGearAlpha(0f);
+        mAnimating = false;
+        setIconLocation(true /* on left */);
+    }
+
     public void setGearListener(SettingsIconRowListener listener) {
         mListener = listener;
     }
@@ -86,21 +94,15 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
         return mParent;
     }
 
-    public void resetState() {
-        setGearAlpha(0f);
-        mAnimating = false;
-        setIconLocation(true /* on left */);
-    }
-
     private void setGearAlpha(float alpha) {
         if (alpha == 0) {
             mSettingsFadedIn = false; // Can fade in again once it's gone.
-            mGearIcon.setVisibility(View.INVISIBLE);
+            setVisibility(View.INVISIBLE);
         } else {
             if (alpha == 1) {
                 mSettingsFadedIn = true;
             }
-            mGearIcon.setVisibility(View.VISIBLE);
+            setVisibility(View.VISIBLE);
         }
         mGearIcon.setAlpha(alpha);
     }
@@ -200,7 +202,16 @@ public class NotificationSettingsIconRow extends FrameLayout implements View.OnC
     public void onClick(View v) {
         if (v.getId() == R.id.gear_icon) {
             if (mListener != null) {
-                mListener.onGearTouched(mParent);
+                mGearIcon.getLocationOnScreen(mGearLocation);
+                mParent.getLocationOnScreen(mParentLocation);
+
+                final int centerX = (int) (mHorizSpaceForGear / 2);
+                // Top / bottom padding are not equal, need to subtract them to get center of gear.
+                final int centerY = (int) (mGearIcon.getHeight() - mGearIcon.getPaddingTop()
+                        - mGearIcon.getPaddingBottom()) / 2 + mGearIcon.getPaddingTop();
+                final int x = mGearLocation[0] - mParentLocation[0] + centerX;
+                final int y = mGearLocation[1] - mParentLocation[1] + centerY;
+                mListener.onGearTouched(mParent, x, y);
             }
         } else {
             // Do nothing when the background is touched.
index c892b11..988d537 100644 (file)
@@ -221,12 +221,15 @@ public class SignalClusterView
 
         apply();
         applyIconTint();
+        mNC.addSignalCallback(this);
     }
 
     @Override
     protected void onDetachedFromWindow() {
         mMobileSignalGroup.removeAllViews();
         TunerService.get(mContext).removeTunable(this);
+        mSC.removeCallback(this);
+        mNC.removeSignalCallback(this);
 
         super.onDetachedFromWindow();
     }
index bf05d1d..66f945e 100644 (file)
@@ -76,26 +76,26 @@ public class ViewTransformationHelper implements TransformableView {
         });
         mViewTransformationAnimation.setInterpolator(Interpolators.LINEAR);
         mViewTransformationAnimation.setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
-        if (endRunnable != null) {
-            mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() {
-                public boolean mCancelled;
+        mViewTransformationAnimation.addListener(new AnimatorListenerAdapter() {
+            public boolean mCancelled;
 
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    endRunnable.run();
-                    if (!mCancelled) {
-                        setVisible(false);
-                    } else {
-                        abortTransformations();
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                if (!mCancelled) {
+                    if (endRunnable != null) {
+                        endRunnable.run();
                     }
+                    setVisible(false);
+                } else {
+                    abortTransformations();
                 }
+            }
 
-                @Override
-                public void onAnimationCancel(Animator animation) {
-                    mCancelled = true;
-                }
-            });
-        }
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+        });
         mViewTransformationAnimation.start();
     }
 
index 5ab441d..d3393b3 100644 (file)
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.notification;
 
+import android.text.Layout;
 import android.text.TextUtils;
 import android.util.Pools;
 import android.view.View;
@@ -28,14 +29,13 @@ public class TextViewTransformState extends TransformState {
 
     private static Pools.SimplePool<TextViewTransformState> sInstancePool
             = new Pools.SimplePool<>(40);
-    private CharSequence mText;
+    private TextView mText;
 
     @Override
     public void initFrom(View view) {
         super.initFrom(view);
         if (view instanceof TextView) {
-            TextView txt = (TextView) view;
-            mText = txt.getText();
+            mText = (TextView) view;
         }
     }
 
@@ -43,11 +43,27 @@ public class TextViewTransformState extends TransformState {
     protected boolean sameAs(TransformState otherState) {
         if (otherState instanceof TextViewTransformState) {
             TextViewTransformState otherTvs = (TextViewTransformState) otherState;
-            return TextUtils.equals(otherTvs.mText, mText);
+            if(TextUtils.equals(otherTvs.mText.getText(), mText.getText())) {
+                int ownEllipsized = getEllipsisCount();
+                int otherEllipsized = otherTvs.getEllipsisCount();
+                return ownEllipsized == otherEllipsized;
+            }
         }
         return super.sameAs(otherState);
     }
 
+    private int getEllipsisCount() {
+        Layout l = mText.getLayout();
+        if (l != null) {
+            int lines = l.getLineCount();
+            if (lines > 0) {
+                // we only care about the first line
+                return l.getEllipsisCount(0);
+            }
+        }
+        return 0;
+    }
+
     public static TextViewTransformState obtain() {
         TextViewTransformState instance = sInstancePool.acquire();
         if (instance != null) {
index 5796edb..ed71e57 100644 (file)
@@ -22,8 +22,12 @@ import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Color;
 import android.graphics.ColorFilter;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
 import android.graphics.drawable.Drawable;
 import android.os.SystemClock;
 import android.util.Log;
@@ -55,6 +59,7 @@ public class BarTransitions {
     private final BarBackgroundDrawable mBarBackground;
 
     private int mMode;
+    private boolean mAlwaysOpaque = false;
 
     public BarTransitions(View view, int gradientResourceId) {
         mTag = "BarTransitions." + view.getClass().getSimpleName();
@@ -69,13 +74,25 @@ public class BarTransitions {
         return mMode;
     }
 
+    /**
+     * @param alwaysOpaque if {@code true}, the bar's background will always be opaque, regardless
+     *         of what mode it is currently set to.
+     */
+    public void setAlwaysOpaque(boolean alwaysOpaque) {
+        mAlwaysOpaque = alwaysOpaque;
+    }
+
+    public boolean isAlwaysOpaque() {
+        // Low-end devices do not support translucent modes, fallback to opaque
+        return !HIGH_END || mAlwaysOpaque;
+    }
+
     public void transitionTo(int mode, boolean animate) {
-        // low-end devices do not support translucent modes, fallback to opaque
-        if (!HIGH_END && (mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
+        if (isAlwaysOpaque() && (mode == MODE_SEMI_TRANSPARENT || mode == MODE_TRANSLUCENT
                 || mode == MODE_TRANSPARENT)) {
             mode = MODE_OPAQUE;
         }
-        if (!HIGH_END && (mode == MODE_LIGHTS_OUT_TRANSPARENT)) {
+        if (isAlwaysOpaque() && (mode == MODE_LIGHTS_OUT_TRANSPARENT)) {
             mode = MODE_LIGHTS_OUT;
         }
         if (mMode == mode) return;
@@ -131,10 +148,13 @@ public class BarTransitions {
 
         private int mGradientAlpha;
         private int mColor;
+        private PorterDuffColorFilter mTintFilter;
+        private Paint mPaint = new Paint();
 
         private int mGradientAlphaStart;
         private int mColorStart;
 
+
         public BarBackgroundDrawable(Context context, int gradientResourceId) {
             final Resources res = context.getResources();
             if (DEBUG_COLORS) {
@@ -163,6 +183,26 @@ public class BarTransitions {
         }
 
         @Override
+        public void setTint(int color) {
+            if (mTintFilter == null) {
+                mTintFilter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN);
+            } else {
+                mTintFilter.setColor(color);
+            }
+            invalidateSelf();
+        }
+
+        @Override
+        public void setTintMode(Mode tintMode) {
+            if (mTintFilter == null) {
+                mTintFilter = new PorterDuffColorFilter(0, tintMode);
+            } else {
+                mTintFilter.setMode(tintMode);
+            }
+            invalidateSelf();
+        }
+
+        @Override
         protected void onBoundsChange(Rect bounds) {
             super.onBoundsChange(bounds);
             mGradient.setBounds(bounds);
@@ -208,6 +248,7 @@ public class BarTransitions {
             } else {
                 targetColor = mOpaque;
             }
+
             if (!mAnimating) {
                 mColor = targetColor;
                 mGradientAlpha = targetGradientAlpha;
@@ -234,7 +275,11 @@ public class BarTransitions {
                 mGradient.draw(canvas);
             }
             if (Color.alpha(mColor) > 0) {
-                canvas.drawColor(mColor);
+                mPaint.setColor(mColor);
+                if (mTintFilter != null) {
+                    mPaint.setColorFilter(mTintFilter);
+                }
+                canvas.drawPaint(mPaint);
             }
             if (mAnimating) {
                 invalidateSelf();  // keep going
index eade2a8..6e1c862 100644 (file)
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.phone;
 import android.content.Context;
 import android.util.AttributeSet;
 import android.widget.RelativeLayout;
-
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl;
index 05ae41b..88b8afa 100644 (file)
@@ -42,6 +42,8 @@ import android.widget.TextView;
 import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.DejankUtils;
+import com.android.systemui.DensityContainer;
+import com.android.systemui.DensityContainer.InflateListener;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
@@ -215,8 +217,14 @@ public class NotificationPanelView extends PanelView implements
         super.onFinishInflate();
         mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header);
         mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view);
-        mQsContainer = (QSContainer) findViewById(R.id.quick_settings_container);
-        mQsContainer.getHeader().setOnClickListener(this);
+        DensityContainer container = (DensityContainer) findViewById(R.id.qs_density_container);
+        container.addInflateListener(new InflateListener() {
+            @Override
+            public void onInflated(View v) {
+                mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
+                mQsContainer.getHeader().setOnClickListener(NotificationPanelView.this);
+            }
+        });
         mClockView = (TextView) findViewById(R.id.clock_view);
         mNotificationContainerParent = (NotificationsQuickSettingsContainer)
                 findViewById(R.id.notification_container_parent);
@@ -1389,7 +1397,7 @@ public class NotificationPanelView extends PanelView implements
                 // In Shade, interpolate linearly such that QS is closed whenever panel height is
                 // minimum QS expansion + minStackHeight
                 float panelHeightQsCollapsed = mNotificationStackScroller.getIntrinsicPadding()
-                        + mNotificationStackScroller.getMinStackHeight();
+                        + mNotificationStackScroller.getLayoutMinHeight();
                 float panelHeightQsExpanded = calculatePanelHeightQsExpanded();
                 t = (expandedHeight - panelHeightQsCollapsed)
                         / (panelHeightQsExpanded - panelHeightQsCollapsed);
@@ -1445,7 +1453,7 @@ public class NotificationPanelView extends PanelView implements
                 && mShadeEmpty) {
             notificationHeight = mNotificationStackScroller.getEmptyShadeViewHeight()
                     + mNotificationStackScroller.getBottomStackPeekSize()
-                    + mNotificationStackScroller.getCollapseSecondCardPadding();
+                    + mNotificationStackScroller.getBottomStackSlowDownHeight();
         }
         int maxQsHeight = mQsMaxExpansionHeight;
 
@@ -1460,7 +1468,7 @@ public class NotificationPanelView extends PanelView implements
                 + notificationHeight;
         if (totalHeight > mNotificationStackScroller.getHeight()) {
             float fullyCollapsedHeight = maxQsHeight
-                    + mNotificationStackScroller.getMinStackHeight();
+                    + mNotificationStackScroller.getLayoutMinHeight();
             totalHeight = Math.max(fullyCollapsedHeight, mNotificationStackScroller.getHeight());
         }
         return (int) totalHeight;
@@ -1477,7 +1485,7 @@ public class NotificationPanelView extends PanelView implements
     private float getFadeoutAlpha() {
         float alpha = (getNotificationsTopY() + mNotificationStackScroller.getFirstItemMinHeight())
                 / (mQsMinExpansionHeight + mNotificationStackScroller.getBottomStackPeekSize()
-                - mNotificationStackScroller.getCollapseSecondCardPadding());
+                - mNotificationStackScroller.getBottomStackSlowDownHeight());
         alpha = Math.max(0, Math.min(alpha, 1));
         alpha = (float) Math.pow(alpha, 0.75);
         return alpha;
index 7cc720d..6d90e5c 100644 (file)
@@ -47,7 +47,7 @@ public class NotificationsQuickSettingsContainer extends FrameLayout
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mQsContainer = findViewById(R.id.quick_settings_container);
+        mQsContainer = findViewById(R.id.qs_density_container);
         mStackScroller = findViewById(R.id.notification_stack_scroller);
         mKeyguardStatusBar = findViewById(R.id.keyguard_header);
         ViewStub userSwitcher = (ViewStub) findViewById(R.id.keyguard_user_switcher);
index 9b87a8a..073a848 100644 (file)
@@ -23,7 +23,6 @@ import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
-import android.app.IWallpaperManagerCallback;
 import android.app.Notification;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
@@ -104,6 +103,8 @@ import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DemoMode;
+import com.android.systemui.DensityContainer;
+import com.android.systemui.DensityContainer.InflateListener;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
@@ -778,8 +779,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
         mStatusBarView.setScrimController(mScrimController);
         mDozeScrimController = new DozeScrimController(mScrimController, context);
 
-        mHeader = (BaseStatusBarHeader) mStatusBarWindow.findViewById(R.id.header);
-        mHeader.setActivityStarter(this);
         mKeyguardStatusBar = (KeyguardStatusBarView) mStatusBarWindow.findViewById(R.id.keyguard_header);
         mKeyguardStatusView = mStatusBarWindow.findViewById(R.id.keyguard_status_view);
         mKeyguardBottomArea =
@@ -839,12 +838,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
 
         initSignalCluster(mStatusBarView);
         initSignalCluster(mKeyguardStatusBar);
-        initSignalCluster(mHeader);
-
-        final boolean isAPhone = mNetworkController.hasVoiceCallingFeature();
-        if (isAPhone) {
-            mNetworkController.addEmergencyListener(mHeader);
-        }
 
         mFlashlightController = new FlashlightController(mContext);
         mKeyguardBottomArea.setFlashlightController(mFlashlightController);
@@ -863,39 +856,40 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
         }
 
         // Set up the quick settings tile panel
-        mQSPanel = (QSPanel) mStatusBarWindow.findViewById(R.id.quick_settings_panel);
-        if (mQSPanel != null) {
+        DensityContainer container = (DensityContainer) mStatusBarWindow.findViewById(
+                R.id.qs_density_container);
+        if (container != null) {
             final QSTileHost qsh = new QSTileHost(mContext, this,
                     mBluetoothController, mLocationController, mRotationLockController,
                     mNetworkController, mZenModeController, mHotspotController,
                     mCastController, mFlashlightController,
                     mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
-                    mSecurityController, mBatteryController, mIconController);
-            mQSPanel.setTiles(qsh.getTiles());
+                    mSecurityController, mBatteryController, mIconController,
+                    mNextAlarmController);
             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
-            mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
-            QSContainer qsContainer = (QSContainer) mStatusBarWindow.findViewById(
-                    R.id.quick_settings_container);
-            qsContainer.setHost(qsh);
-            qsh.addCallback(new QSTileHost.Callback() {
+            container.addInflateListener(new InflateListener() {
                 @Override
-                public void onTilesChanged() {
-                    mQSPanel.setTiles(qsh.getTiles());
+                public void onInflated(View v) {
+                    QSContainer qsContainer = (QSContainer) v.findViewById(
+                            R.id.quick_settings_container);
+                    qsContainer.setHost(qsh);
+                    mQSPanel = qsContainer.getQsPanel();
+                    mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
+                    mHeader = qsContainer.getHeader();
+                    initSignalCluster(mHeader);
+                    mHeader.setActivityStarter(PhoneStatusBar.this);
                 }
             });
         }
 
         // User info. Trigger first load.
-        mHeader.setUserInfoController(mUserInfoController);
         mKeyguardStatusBar.setUserInfoController(mUserInfoController);
         mKeyguardStatusBar.setUserSwitcherController(mUserSwitcherController);
         mUserInfoController.reloadUserInfo();
 
-        mHeader.setBatteryController(mBatteryController);
         ((BatteryMeterView) mStatusBarView.findViewById(R.id.battery)).setBatteryController(
                 mBatteryController);
         mKeyguardStatusBar.setBatteryController(mBatteryController);
-        mHeader.setNextAlarmController(mNextAlarmController);
 
         PowerManager pm = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mBroadcastReceiver.onReceive(mContext,
@@ -1001,7 +995,6 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
         SignalClusterView signalCluster =
                 (SignalClusterView) containerView.findViewById(R.id.signal_cluster);
         if (signalCluster != null) {
-            mNetworkController.addSignalCallback(signalCluster);
             signalCluster.setSecurityController(mSecurityController);
             signalCluster.setNetworkController(mNetworkController);
         }
@@ -1603,8 +1596,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
     }
 
     private boolean packageHasVisibilityOverride(String key) {
-        return mNotificationData.getVisibilityOverride(key)
-                != NotificationListenerService.Ranking.VISIBILITY_NO_OVERRIDE;
+        return mNotificationData.getVisibilityOverride(key) == Notification.VISIBILITY_PRIVATE;
     }
 
     private void updateClearAll() {
@@ -3562,7 +3554,7 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
     }
 
     @Override
-    protected boolean isPanelFullyCollapsed() {
+    public boolean isPanelFullyCollapsed() {
         return mNotificationPanel.isFullyCollapsed();
     }
 
index 80afb9a..f894a22 100644 (file)
@@ -57,6 +57,7 @@ import com.android.systemui.qs.tiles.WorkModeTile;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.BluetoothController;
 import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.NightModeController;
 import com.android.systemui.statusbar.policy.FlashlightController;
 import com.android.systemui.statusbar.policy.HotspotController;
@@ -111,16 +112,18 @@ public final class QSTileHost implements QSTile.Host, Tunable {
     private final NightModeController mNightModeController;
     private final AutoTileManager mAutoTiles;
     private final ManagedProfileController mProfileController;
+    private final NextAlarmController mNextAlarmController;
     private View mHeader;
 
     public QSTileHost(Context context, PhoneStatusBar statusBar,
-                      BluetoothController bluetooth, LocationController location,
-                      RotationLockController rotation, NetworkController network,
-                      ZenModeController zen, HotspotController hotspot,
-                      CastController cast, FlashlightController flashlight,
-                      UserSwitcherController userSwitcher, UserInfoController userInfo,
-                      KeyguardMonitor keyguard, SecurityController security,
-                      BatteryController battery, StatusBarIconController iconController) {
+            BluetoothController bluetooth, LocationController location,
+            RotationLockController rotation, NetworkController network,
+            ZenModeController zen, HotspotController hotspot,
+            CastController cast, FlashlightController flashlight,
+            UserSwitcherController userSwitcher, UserInfoController userInfo,
+            KeyguardMonitor keyguard, SecurityController security,
+            BatteryController battery, StatusBarIconController iconController,
+            NextAlarmController nextAlarmController) {
         mContext = context;
         mStatusBar = statusBar;
         mBluetooth = bluetooth;
@@ -137,6 +140,7 @@ public final class QSTileHost implements QSTile.Host, Tunable {
         mSecurity = security;
         mBattery = battery;
         mIconController = iconController;
+        mNextAlarmController = nextAlarmController;
         mNightModeController = new NightModeController(mContext, true);
         mProfileController = new ManagedProfileController(this);
 
@@ -152,6 +156,10 @@ public final class QSTileHost implements QSTile.Host, Tunable {
         mAutoTiles = new AutoTileManager(context, this);
     }
 
+    public NextAlarmController getNextAlarmController() {
+        return mNextAlarmController;
+    }
+
     public void setHeaderView(View view) {
         mHeader = view;
     }
@@ -171,6 +179,11 @@ public final class QSTileHost implements QSTile.Host, Tunable {
     }
 
     @Override
+    public void removeCallback(Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
+    @Override
     public Collection<QSTile<?>> getTiles() {
         return mTiles.values();
     }
index b549d59..326ca2b 100644 (file)
@@ -35,13 +35,13 @@ import com.android.systemui.FontSizeUtils;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSAnimator;
 import com.android.systemui.qs.QSPanel;
-import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QuickQSPanel;
 import com.android.systemui.qs.TouchAnimator;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.NextAlarmController.NextAlarmChangeCallback;
 import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserInfoController.OnUserInfoChangedListener;
 import com.android.systemui.tuner.TunerService;
 
 public class QuickStatusBarHeader extends BaseStatusBarHeader implements
@@ -90,6 +90,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
     private TouchAnimator mAlarmTranslation;
     private TouchAnimator mSettingsAlpha;
     private float mExpansionAmount;
+    private QSTileHost mHost;
 
     public QuickStatusBarHeader(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -222,6 +223,14 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
         mExpandIndicator.setExpanded(headerExpansionFraction > EXPAND_INDICATOR_THRESHOLD);
     }
 
+    @Override
+    protected void onDetachedFromWindow() {
+        setListening(false);
+        mHost.getUserInfoController().remListener(mUserListener);
+        mHost.getNetworkController().removeEmergencyListener(this);
+        super.onDetachedFromWindow();
+    }
+
     private void updateAlarmVisibilities() {
         mAlarmStatus.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
         mAlarmStatusCollapsed.setVisibility(mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
@@ -284,17 +293,18 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
     }
 
     public void setupHost(final QSTileHost host) {
+        mHost = host;
         host.setHeaderView(this);
         mHeaderQsPanel.setQSPanelAndHeader(mQsPanel, this);
         mHeaderQsPanel.setHost(host);
-        mHeaderQsPanel.setMaxTiles(5);
-        mHeaderQsPanel.setTiles(host.getTiles());
-        host.addCallback(new QSTile.Host.Callback() {
-            @Override
-            public void onTilesChanged() {
-                mHeaderQsPanel.setTiles(host.getTiles());
-            }
-        });
+        setUserInfoController(host.getUserInfoController());
+        setBatteryController(host.getBatteryController());
+        setNextAlarmController(host.getNextAlarmController());
+
+        final boolean isAPhone = mHost.getNetworkController().hasVoiceCallingFeature();
+        if (isAPhone) {
+            mHost.getNetworkController().addEmergencyListener(this);
+        }
     }
 
     @Override
@@ -340,12 +350,7 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
 
     @Override
     public void setUserInfoController(UserInfoController userInfoController) {
-        userInfoController.addListener(new UserInfoController.OnUserInfoChangedListener() {
-            @Override
-            public void onUserInfoChanged(String name, Drawable picture) {
-                mMultiUserAvatar.setImageDrawable(picture);
-            }
-        });
+        userInfoController.addListener(mUserListener);
     }
 
     @Override
@@ -358,4 +363,11 @@ public class QuickStatusBarHeader extends BaseStatusBarHeader implements
             }
         }
     }
+
+    private final OnUserInfoChangedListener mUserListener = new OnUserInfoChangedListener() {
+        @Override
+        public void onUserInfoChanged(String name, Drawable picture) {
+            mMultiUserAvatar.setImageDrawable(picture);
+        }
+    };
 }
index 3e3b169..a051973 100644 (file)
@@ -39,7 +39,6 @@ import android.widget.RelativeLayout;
 import android.widget.Switch;
 import android.widget.TextView;
 import android.widget.Toast;
-
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.FontSizeUtils;
@@ -48,7 +47,7 @@ import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.DetailAdapter;
 import com.android.systemui.statusbar.policy.BatteryController;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
+import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.tuner.TunerService;
index e618cb8..3142ddf 100644 (file)
@@ -19,11 +19,10 @@ import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
 import android.telephony.SubscriptionInfo;
-
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
 
 import java.util.ArrayList;
 import java.util.List;
index bd36462..159bd41 100644 (file)
@@ -19,6 +19,7 @@ import android.content.Context;
 import android.net.NetworkCapabilities;
 
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import java.util.BitSet;
 
@@ -46,12 +47,12 @@ public class EthernetSignalController extends
     }
 
     @Override
-    public void notifyListeners() {
+    public void notifyListeners(SignalCallback callback) {
         boolean ethernetVisible = mCurrentState.connected;
         String contentDescription = getStringIfExists(getContentDescription());
 
         // TODO: wire up data transfer using WifiSignalPoller.
-        mCallbackHandler.setEthernetIndicators(new IconState(ethernetVisible, getCurrentIconId(),
+        callback.setEthernetIndicators(new IconState(ethernetVisible, getCurrentIconId(),
                 contentDescription));
     }
 
index 8fd4d9c..80dcfb6 100644 (file)
@@ -34,6 +34,7 @@ import com.android.internal.telephony.TelephonyIntents;
 import com.android.internal.telephony.cdma.EriInfo;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
 
@@ -198,7 +199,7 @@ public class MobileSignalController extends SignalController<
     }
 
     @Override
-    public void notifyListeners() {
+    public void notifyListeners(SignalCallback callback) {
         MobileIconGroup icons = getIcons();
 
         String contentDescription = getStringIfExists(getContentDescription());
@@ -231,7 +232,7 @@ public class MobileSignalController extends SignalController<
                 || mCurrentState.iconGroup == TelephonyIcons.ROAMING
                 || mCurrentState.iconGroup == TelephonyIcons.DATA_DISABLED;
         int typeIcon = showDataIcon ? icons.mDataType : 0;
-        mCallbackHandler.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
+        callback.setMobileDataIndicators(statusIcon, qsIcon, typeIcon, qsTypeIcon,
                 activityIn, activityOut, dataContentDescription, description, icons.mIsWide,
                 mSubscriptionInfo.getSubscriptionId());
     }
index 93c7322..348e0b0 100644 (file)
@@ -19,7 +19,6 @@ package com.android.systemui.statusbar.policy;
 import android.content.Context;
 import android.content.Intent;
 import android.telephony.SubscriptionInfo;
-
 import com.android.settingslib.net.DataUsageController;
 import com.android.settingslib.wifi.AccessPoint;
 
@@ -36,6 +35,11 @@ public interface NetworkController {
     DataUsageController getMobileDataController();
     DataSaverController getDataSaverController();
 
+    boolean hasVoiceCallingFeature();
+
+    void addEmergencyListener(EmergencyListener listener);
+    void removeEmergencyListener(EmergencyListener listener);
+
     public interface SignalCallback {
         void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
                 boolean activityIn, boolean activityOut, String description);
@@ -53,6 +57,10 @@ public interface NetworkController {
         void setMobileDataEnabled(boolean enabled);
     }
 
+    public interface EmergencyListener {
+        void setEmergencyCallsOnly(boolean emergencyOnly);
+    }
+
     public static class IconState {
         public final boolean visible;
         public final int icon;
index eecf8c2..40eb71d 100644 (file)
@@ -252,6 +252,10 @@ public class NetworkControllerImpl extends BroadcastReceiver
         mCallbackHandler.setEmergencyCallsOnly(isEmergencyOnly());
     }
 
+    public void removeEmergencyListener(EmergencyListener listener) {
+        mCallbackHandler.setListening(listener, false);
+    }
+
     public boolean hasMobileDataFeature() {
         return mHasMobileDataFeature;
     }
@@ -318,16 +322,16 @@ public class NetworkControllerImpl extends BroadcastReceiver
     }
 
     public void addSignalCallback(SignalCallback cb) {
-        mCallbackHandler.setListening(cb, true);
-        mCallbackHandler.setSubs(mCurrentSubscriptions);
-        mCallbackHandler.setIsAirplaneMode(new IconState(mAirplaneMode,
+        cb.setSubs(mCurrentSubscriptions);
+        cb.setIsAirplaneMode(new IconState(mAirplaneMode,
                 TelephonyIcons.FLIGHT_MODE_ICON, R.string.accessibility_airplane_mode, mContext));
-        mCallbackHandler.setNoSims(mHasNoSims);
-        mWifiSignalController.notifyListeners();
-        mEthernetSignalController.notifyListeners();
+        cb.setNoSims(mHasNoSims);
+        mWifiSignalController.notifyListeners(cb);
+        mEthernetSignalController.notifyListeners(cb);
         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
-            mobileSignalController.notifyListeners();
+            mobileSignalController.notifyListeners(cb);
         }
+        mCallbackHandler.setListening(cb, true);
     }
 
     @Override
@@ -812,10 +816,6 @@ public class NetworkControllerImpl extends BroadcastReceiver
         }
     };
 
-    public interface EmergencyListener {
-        void setEmergencyCallsOnly(boolean emergencyOnly);
-    }
-
     public static class SubscriptionDefaults {
         public int getDefaultVoiceSubId() {
             return SubscriptionManager.getDefaultVoiceSubscriptionId();
index 0b1911b..4611ef9 100644 (file)
 
 package com.android.systemui.statusbar.policy;
 
-import libcore.util.Objects;
-
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.opengl.Matrix;
-import android.provider.Settings;
 import android.provider.Settings.Secure;
 import android.util.MathUtils;
-
 import com.android.systemui.tuner.TunerService;
 
 import java.util.ArrayList;
@@ -189,8 +185,8 @@ public class NightModeController implements TunerService.Tunable {
     }
 
     private void updateNightMode(Intent intent) {
-        mIsNight = intent.getBooleanExtra(EXTRA_IS_NIGHT, false);
-        mAmount = intent.getFloatExtra(EXTRA_AMOUNT, 0);
+        mIsNight = intent != null && intent.getBooleanExtra(EXTRA_IS_NIGHT, false);
+        mAmount = intent != null ? intent.getFloatExtra(EXTRA_AMOUNT, 0) : 0;
     }
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
index c954d08..4cfd1c7 100644 (file)
@@ -18,6 +18,7 @@ package com.android.systemui.statusbar.policy;
 import android.content.Context;
 import android.text.format.DateFormat;
 import android.util.Log;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import java.io.PrintWriter;
 import java.util.BitSet;
@@ -48,7 +49,7 @@ public abstract class SignalController<T extends SignalController.State,
     // is aware of current state.
     protected final NetworkControllerImpl mNetworkController;
 
-    protected final CallbackHandler mCallbackHandler;
+    private final CallbackHandler mCallbackHandler;
 
     // Save the previous HISTORY_SIZE states for logging.
     private final State[] mHistory;
@@ -198,12 +199,16 @@ public abstract class SignalController<T extends SignalController.State,
         }
     }
 
+    public final void notifyListeners() {
+        notifyListeners(mCallbackHandler);
+    }
+
     /**
      * Trigger callbacks based on current state.  The callbacks should be completely
      * based on current state, and only need to be called in the scenario where
      * mCurrentState != mLastState.
      */
-    public abstract void notifyListeners();
+    public abstract void notifyListeners(SignalCallback callback);
 
     /**
      * Generate a blank T.
index 53fd446..cedc3c7 100644 (file)
@@ -37,6 +37,8 @@ import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
+import android.telephony.PhoneStateListener;
+import android.telephony.TelephonyManager;
 import android.util.Log;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -99,7 +101,6 @@ public class UserSwitcherController {
     private boolean mSimpleUserSwitcher;
     private boolean mAddUsersWhenLocked;
     private boolean mPauseRefreshUsers;
-    private boolean mAllowUserSwitchingWhenSystemUserLocked;
     private SparseBooleanArray mForcePictureLoadForUserId = new SparseBooleanArray(2);
 
     public UserSwitcherController(Context context, KeyguardMonitor keyguardMonitor,
@@ -140,6 +141,7 @@ public class UserSwitcherController {
         mSettingsObserver.onChange(false);
 
         keyguardMonitor.addCallback(mCallback);
+        listenForCallState();
 
         refreshUsers(UserHandle.USER_NULL);
     }
@@ -186,8 +188,7 @@ public class UserSwitcherController {
                 }
                 ArrayList<UserRecord> records = new ArrayList<>(infos.size());
                 int currentId = ActivityManager.getCurrentUser();
-                boolean allowUserSwitching = mAllowUserSwitchingWhenSystemUserLocked
-                        || mUserManager.isUserUnlocked(UserHandle.SYSTEM);
+                boolean canSwitchUsers = mUserManager.canSwitchUsers();
                 UserInfo currentUserInfo = null;
                 UserRecord guestRecord = null;
                 int avatarSize = mContext.getResources()
@@ -198,12 +199,14 @@ public class UserSwitcherController {
                     if (isCurrent) {
                         currentUserInfo = info;
                     }
-                    boolean switchToEnabled = allowUserSwitching || isCurrent;
+                    boolean switchToEnabled = canSwitchUsers || isCurrent;
                     if (info.isEnabled()) {
                         if (info.isGuest()) {
+                            // Tapping guest icon triggers remove and a user switch therefore
+                            // the icon shouldn't be enabled even if the user is current
                             guestRecord = new UserRecord(info, null /* picture */,
                                     true /* isGuest */, isCurrent, false /* isAddUser */,
-                                    false /* isRestricted */, switchToEnabled);
+                                    false /* isRestricted */, canSwitchUsers);
                         } else if (info.supportsSwitchToByUser()) {
                             Bitmap picture = bitmaps.get(info.id);
                             if (picture == null) {
@@ -240,7 +243,7 @@ public class UserSwitcherController {
                         if (canCreateGuest) {
                             guestRecord = new UserRecord(null /* info */, null /* picture */,
                                     true /* isGuest */, false /* isCurrent */,
-                                    false /* isAddUser */, createIsRestricted, allowUserSwitching);
+                                    false /* isAddUser */, createIsRestricted, canSwitchUsers);
                             checkIfAddUserDisallowedByAdminOnly(guestRecord);
                             records.add(guestRecord);
                         }
@@ -253,7 +256,7 @@ public class UserSwitcherController {
                 if (!mSimpleUserSwitcher && canCreateUser) {
                     UserRecord addUserRecord = new UserRecord(null /* info */, null /* picture */,
                             false /* isGuest */, false /* isCurrent */, true /* isAddUser */,
-                            createIsRestricted, allowUserSwitching);
+                            createIsRestricted, canSwitchUsers);
                     checkIfAddUserDisallowedByAdminOnly(addUserRecord);
                     records.add(addUserRecord);
                 }
@@ -417,6 +420,24 @@ public class UserSwitcherController {
         mUserManager.removeUser(id);
     }
 
+    private void listenForCallState() {
+        TelephonyManager.from(mContext).listen(new PhoneStateListener() {
+            private int mCallState;
+            @Override
+            public void onCallStateChanged(int state, String incomingNumber) {
+                if (mCallState == state) return;
+                if (DEBUG) Log.v(TAG, "Call state changed: " + state);
+                mCallState = state;
+                int currentUserId = ActivityManager.getCurrentUser();
+                UserInfo userInfo = mUserManager.getUserInfo(currentUserId);
+                if (userInfo != null && userInfo.isGuest()) {
+                    showGuestNotification(currentUserId);
+                }
+                refreshUsers(UserHandle.USER_NULL);
+            }
+        }, PhoneStateListener.LISTEN_CALL_STATE);
+    }
+
     private BroadcastReceiver mReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -488,25 +509,6 @@ public class UserSwitcherController {
             }
         }
 
-        private void showGuestNotification(int guestUserId) {
-            PendingIntent removeGuestPI = PendingIntent.getBroadcastAsUser(mContext,
-                    0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.SYSTEM);
-            Notification notification = new Notification.Builder(mContext)
-                    .setVisibility(Notification.VISIBILITY_SECRET)
-                    .setPriority(Notification.PRIORITY_MIN)
-                    .setSmallIcon(R.drawable.ic_person)
-                    .setContentTitle(mContext.getString(R.string.guest_notification_title))
-                    .setContentText(mContext.getString(R.string.guest_notification_text))
-                    .setContentIntent(removeGuestPI)
-                    .setShowWhen(false)
-                    .addAction(R.drawable.ic_delete,
-                            mContext.getString(R.string.guest_notification_remove_action),
-                            removeGuestPI)
-                    .build();
-            NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST, ID_REMOVE_GUEST,
-                    notification, new UserHandle(guestUserId));
-        }
-
         private void showLogoutNotification(int userId) {
             PendingIntent logoutPI = PendingIntent.getBroadcastAsUser(mContext,
                     0, new Intent(ACTION_LOGOUT_USER), 0, UserHandle.SYSTEM);
@@ -528,6 +530,28 @@ public class UserSwitcherController {
         }
     };
 
+    private void showGuestNotification(int guestUserId) {
+        boolean canSwitchUsers = mUserManager.canSwitchUsers();
+        // Disable 'Remove guest' action if cannot switch users right now
+        PendingIntent removeGuestPI = canSwitchUsers ? PendingIntent.getBroadcastAsUser(mContext,
+                0, new Intent(ACTION_REMOVE_GUEST), 0, UserHandle.SYSTEM) : null;
+
+        Notification notification = new Notification.Builder(mContext)
+                .setVisibility(Notification.VISIBILITY_SECRET)
+                .setPriority(Notification.PRIORITY_MIN)
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentTitle(mContext.getString(R.string.guest_notification_title))
+                .setContentText(mContext.getString(R.string.guest_notification_text))
+                .setContentIntent(removeGuestPI)
+                .setShowWhen(false)
+                .addAction(R.drawable.ic_delete,
+                        mContext.getString(R.string.guest_notification_remove_action),
+                        removeGuestPI)
+                .build();
+        NotificationManager.from(mContext).notifyAsUser(TAG_REMOVE_GUEST, ID_REMOVE_GUEST,
+                notification, new UserHandle(guestUserId));
+    }
+
     private final Runnable mUnpauseRefreshUsers = new Runnable() {
         @Override
         public void run() {
@@ -543,9 +567,6 @@ public class UserSwitcherController {
                     SIMPLE_USER_SWITCHER_GLOBAL_SETTING, 0) != 0;
             mAddUsersWhenLocked = Settings.Global.getInt(mContext.getContentResolver(),
                     Settings.Global.ADD_USERS_WHEN_LOCKED, 0) != 0;
-            mAllowUserSwitchingWhenSystemUserLocked = Settings.Global.getInt(
-                    mContext.getContentResolver(),
-                    Settings.Global.ALLOW_USER_SWITCHING_WHEN_SYSTEM_USER_LOCKED, 0) != 0;
             refreshUsers(UserHandle.USER_NULL);
         };
     };
index cc98eb6..a6ed04f 100644 (file)
@@ -28,6 +28,7 @@ import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.AsyncChannel;
 import com.android.settingslib.wifi.WifiStatusTracker;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 
 import java.util.Objects;
 
@@ -72,7 +73,7 @@ public class WifiSignalController extends
     }
 
     @Override
-    public void notifyListeners() {
+    public void notifyListeners(SignalCallback callback) {
         // only show wifi in the cluster if connected or if wifi-only
         boolean wifiVisible = mCurrentState.enabled
                 && (mCurrentState.connected || !mHasMobileData);
@@ -83,7 +84,7 @@ public class WifiSignalController extends
         IconState statusIcon = new IconState(wifiVisible, getCurrentIconId(), contentDescription);
         IconState qsIcon = new IconState(mCurrentState.connected, getQsCurrentIconId(),
                 contentDescription);
-        mCallbackHandler.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
+        callback.setWifiIndicators(mCurrentState.enabled, statusIcon, qsIcon,
                 ssidPresent && mCurrentState.activityIn, ssidPresent && mCurrentState.activityOut,
                 wifiDesc);
     }
index 030c8b7..7955733 100644 (file)
@@ -167,6 +167,7 @@ public class NotificationChildrenContainer extends ViewGroup {
         int newIndex = childIndex < 0 ? mChildren.size() : childIndex;
         mChildren.add(newIndex, row);
         addView(row);
+        row.setUserLocked(mUserLocked);
 
         View divider = inflateDivider();
         addView(divider);
@@ -191,6 +192,7 @@ public class NotificationChildrenContainer extends ViewGroup {
         });
 
         row.setSystemChildExpanded(false);
+        row.setUserLocked(false);
         updateGroupOverflow();
     }
 
@@ -262,10 +264,14 @@ public class NotificationChildrenContainer extends ViewGroup {
     }
 
     private void updateExpansionStates() {
-        // Let's make the first child expanded if the parent is
-        for (int i = 0; i < mChildren.size(); i++) {
+        if (mChildrenExpanded || mUserLocked) {
+            // we don't modify it the group is expanded or if we are expanding it
+            return;
+        }
+        int size = mChildren.size();
+        for (int i = 0; i < size; i++) {
             ExpandableNotificationRow child = mChildren.get(i);
-            child.setSystemChildExpanded(false);
+            child.setSystemChildExpanded(i == 0 && size == 1);
         }
     }
 
@@ -489,6 +495,7 @@ public class NotificationChildrenContainer extends ViewGroup {
 
     public void setChildrenExpanded(boolean childrenExpanded) {
         mChildrenExpanded = childrenExpanded;
+        updateExpansionStates();
     }
 
     public void setNotificationParent(ExpandableNotificationRow parent) {
@@ -566,8 +573,28 @@ public class NotificationChildrenContainer extends ViewGroup {
         return getIntrinsicHeight(NUMBER_OF_CHILDREN_WHEN_COLLAPSED);
     }
 
-    public int getMinExpandHeight() {
-        return getIntrinsicHeight(getMaxAllowedVisibleChildren(true /* forceCollapsed */));
+    public int getMinExpandHeight(boolean onKeyguard) {
+        int maxAllowedVisibleChildren = onKeyguard ? NUMBER_OF_CHILDREN_WHEN_COLLAPSED
+                : getMaxAllowedVisibleChildren(true /* forceCollapsed */);
+        int minExpandHeight = mNotificationHeaderHeight;
+        int visibleChildren = 0;
+        boolean firstChild = true;
+        int childCount = mChildren.size();
+        for (int i = 0; i < childCount; i++) {
+            if (visibleChildren >= maxAllowedVisibleChildren) {
+                break;
+            }
+            if (!firstChild) {
+                minExpandHeight += mChildPadding;
+            } else {
+                firstChild = false;
+            }
+            ExpandableNotificationRow child = mChildren.get(i);
+            minExpandHeight += child.getMinHeight();
+            visibleChildren++;
+        }
+        minExpandHeight += mCollapsedBottompadding;
+        return minExpandHeight;
     }
 
     public void setDark(boolean dark, boolean fade, long delay) {
index 340ebb4..aa444f5 100644 (file)
@@ -48,6 +48,8 @@ import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
 import android.widget.OverScroller;
 
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.MetricsProto.MetricsEvent;
 import com.android.systemui.ExpandHelper;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
@@ -361,9 +363,11 @@ public class NotificationStackScrollLayout extends ViewGroup
     }
 
     @Override
-    public void onGearTouched(ExpandableNotificationRow row) {
+    public void onGearTouched(ExpandableNotificationRow row, int x, int y) {
         if (mLongPressListener != null) {
-            mLongPressListener.onLongPress(row, 0, 0);
+            MetricsLogger.action(mContext, MetricsEvent.ACTION_TOUCH_GEAR,
+                    row.getStatusBarNotification().getPackageName());
+            mLongPressListener.onLongPress(row, x, y);
         }
     }
 
@@ -418,12 +422,9 @@ public class NotificationStackScrollLayout extends ViewGroup
                 .getDimensionPixelSize(R.dimen.notification_divider_height));
         mIncreasedPaddingBetweenElements = context.getResources()
                 .getDimensionPixelSize(R.dimen.notification_divider_height_increased);
-
         mBottomStackSlowDownHeight = mStackScrollAlgorithm.getBottomStackSlowDownLength();
         mMinTopOverScrollToEscape = getResources().getDimensionPixelSize(
                 R.dimen.min_top_overscroll_to_qs);
-        mCollapseSecondCardPadding = getResources().getDimensionPixelSize(
-                R.dimen.notification_collapse_second_card_padding);
     }
 
     private void notifyHeightChangeListener(ExpandableView view) {
@@ -509,14 +510,6 @@ public class NotificationStackScrollLayout extends ViewGroup
     }
 
     /**
-     * @return whether the height of the layout needs to be adapted, in order to ensure that the
-     *         last child is not in the bottom stack.
-     */
-    private boolean needsHeightAdaption() {
-        return getNotGoneChildCount() > 1;
-    }
-
-    /**
      * Updates the children views according to the stack scroll algorithm. Call this whenever
      * modifications to {@link #mOwnScrollY} are performed to reflect it in the view layout.
      */
@@ -599,7 +592,7 @@ public class NotificationStackScrollLayout extends ViewGroup
         mLastSetStackHeight = height;
         setIsExpanded(height > 0.0f);
         int newStackHeight = (int) height;
-        int minStackHeight = getMinStackHeight();
+        int minStackHeight = getLayoutMinHeight();
         int stackHeight;
         float paddingOffset;
         boolean trackingHeadsUp = mTrackingHeadsUp || mHeadsUpManager.hasPinnedHeadsUp();
@@ -612,20 +605,7 @@ public class NotificationStackScrollLayout extends ViewGroup
             stackHeight = newStackHeight;
         } else {
             int translationY;
-            if (!trackingHeadsUp) {
-                // We did not reach the position yet where we actually start growing,
-                // so we translate the stack upwards.
-                translationY = (newStackHeight - minStackHeight);
-                // A slight parallax effect is introduced in order for the stack to catch up with
-                // the top card.
-                float partiallyThere = (newStackHeight - mTopPadding - mTopPaddingOverflow)
-                        / minStackHeight;
-                partiallyThere = Math.max(0, partiallyThere);
-                translationY += (1 - partiallyThere) * (mBottomStackPeekSize +
-                        mCollapseSecondCardPadding);
-            } else {
-                translationY = (int) (height - normalUnfoldPositionStart);
-            }
+            translationY = newStackHeight - normalUnfoldPositionStart;
             paddingOffset = translationY - mTopPadding;
             stackHeight = (int) (height - (translationY - mTopPadding));
         }
@@ -668,8 +648,8 @@ public class NotificationStackScrollLayout extends ViewGroup
         return mBottomStackPeekSize;
     }
 
-    public int getCollapseSecondCardPadding() {
-        return mCollapseSecondCardPadding;
+    public int getBottomStackSlowDownHeight() {
+        return mBottomStackSlowDownHeight;
     }
 
     public void setLongPressListener(SwipeHelper.LongPressListener listener) {
@@ -734,6 +714,7 @@ public class NotificationStackScrollLayout extends ViewGroup
 
         if (targetLeft == 0 && mCurrIconRow != null) {
             mCurrIconRow.resetState();
+            mCurrIconRow = null;
             if (mGearExposedView != null && mGearExposedView == mTranslatingParentView) {
                 mGearExposedView = null;
             }
@@ -1850,7 +1831,7 @@ public class NotificationStackScrollLayout extends ViewGroup
             boolean ignoreIntrinsicPadding) {
         float start = qsHeight;
         float stackHeight = getHeight() - start;
-        int minStackHeight = getMinStackHeight();
+        int minStackHeight = getLayoutMinHeight();
         if (stackHeight <= minStackHeight) {
             float overflow = minStackHeight - stackHeight;
             stackHeight = minStackHeight;
@@ -1864,11 +1845,16 @@ public class NotificationStackScrollLayout extends ViewGroup
         setStackHeight(mLastSetStackHeight);
     }
 
-    public int getMinStackHeight() {
+    public int getLayoutMinHeight() {
         final ExpandableView firstChild = getFirstChildNotGone();
-        final int firstChildMinHeight = firstChild != null ? firstChild.getMinHeight()
+        int firstChildMinHeight = firstChild != null
+                ? firstChild.getIntrinsicHeight()
                 : mCollapsedSize;
-        return firstChildMinHeight + mBottomStackPeekSize + mCollapseSecondCardPadding;
+        if (mOwnScrollY > 0) {
+            firstChildMinHeight = Math.max(firstChildMinHeight - mOwnScrollY, mCollapsedSize);
+        }
+        return Math.min(firstChildMinHeight + mBottomStackPeekSize + mBottomStackSlowDownHeight,
+                mMaxLayoutHeight - mTopPadding);
     }
 
     public float getTopPaddingOverflow() {
@@ -1880,7 +1866,7 @@ public class NotificationStackScrollLayout extends ViewGroup
         final int firstChildMinHeight = firstChild != null ? (int) firstChild.getMinHeight()
                 : mCollapsedSize;
         return mIntrinsicPadding + firstChildMinHeight + mBottomStackPeekSize
-                + mCollapseSecondCardPadding;
+                + mBottomStackSlowDownHeight;
     }
 
     private int clampPadding(int desiredPadding) {
@@ -1994,7 +1980,6 @@ public class NotificationStackScrollLayout extends ViewGroup
     }
 
     private void onViewRemovedInternal(View child) {
-        mStackScrollAlgorithm.notifyChildrenChanged(this);
         if (mChangePositionInProgress) {
             // This is only a position change, don't do anything special
             return;
@@ -2175,7 +2160,6 @@ public class NotificationStackScrollLayout extends ViewGroup
 
     private void onViewAddedInternal(View child) {
         updateHideSensitiveForChild(child);
-        mStackScrollAlgorithm.notifyChildrenChanged(this);
         ((ExpandableView) child).setOnHeightChangedListener(this);
         generateAddAnimation(child, false /* fromMoreCard */);
         updateAnimationState(child);
@@ -2643,12 +2627,8 @@ public class NotificationStackScrollLayout extends ViewGroup
     }
 
     public int getEmptyBottomMargin() {
-        int emptyMargin = mMaxLayoutHeight - mContentHeight - mBottomStackPeekSize;
-        if (needsHeightAdaption()) {
-            emptyMargin -= mBottomStackSlowDownHeight;
-        } else {
-            emptyMargin -= mCollapseSecondCardPadding;
-        }
+        int emptyMargin = mMaxLayoutHeight - mContentHeight - mBottomStackPeekSize
+                - mBottomStackSlowDownHeight;
         return Math.max(emptyMargin, 0);
     }
 
@@ -2659,12 +2639,10 @@ public class NotificationStackScrollLayout extends ViewGroup
 
     public void onExpansionStarted() {
         mIsExpansionChanging = true;
-        mStackScrollAlgorithm.onExpansionStarted(mCurrentStackScrollState);
     }
 
     public void onExpansionStopped() {
         mIsExpansionChanging = false;
-        mStackScrollAlgorithm.onExpansionStopped();
         if (!mIsExpanded) {
             mOwnScrollY = 0;
 
@@ -2732,7 +2710,6 @@ public class NotificationStackScrollLayout extends ViewGroup
         if (mIsExpanded && mAnimationsEnabled) {
             mRequestViewResizeAnimationOnLayout = true;
         }
-        mStackScrollAlgorithm.onReset(view);
         updateAnimationState(view);
         updateChronometerForChild(view);
     }
@@ -3163,15 +3140,7 @@ public class NotificationStackScrollLayout extends ViewGroup
     }
 
     public int getDismissViewHeight() {
-        int height = mDismissView.getHeight() + mPaddingBetweenElements;
-
-        // Hack: Accommodate for additional distance when we only have one notification and the
-        // dismiss all button.
-        if (getNotGoneChildCount() == 2 && getLastChildNotGone() == mDismissView
-                && getFirstChildNotGone() instanceof ActivatableNotificationView) {
-            height += mCollapseSecondCardPadding;
-        }
-        return height;
+        return mDismissView.getHeight() + mPaddingBetweenElements;
     }
 
     public int getEmptyShadeViewHeight() {
@@ -3399,7 +3368,6 @@ public class NotificationStackScrollLayout extends ViewGroup
 
         private static final long GEAR_SHOW_DELAY = 60;
 
-        private ArrayList<View> mTranslatingViews = new ArrayList<>();
         private CheckForDrag mCheckForDrag;
         private Handler mHandler;
         private int mMoveState = MOVE_STATE_UNDEFINED;
@@ -3416,6 +3384,7 @@ public class NotificationStackScrollLayout extends ViewGroup
 
             // Reset check for drag gesture
             mCheckForDrag = null;
+            mCurrIconRow = null;
 
             // Slide back any notifications that might be showing a gear
             resetExposedGearView();
@@ -3424,9 +3393,6 @@ public class NotificationStackScrollLayout extends ViewGroup
                 // Set the listener for the current row's gear
                 mCurrIconRow = ((ExpandableNotificationRow) currView).getSettingsRow();
                 mCurrIconRow.setGearListener(NotificationStackScrollLayout.this);
-
-                // And the translating children
-                mTranslatingViews = ((ExpandableNotificationRow) currView).getContentViews();
             }
             mMoveState = MOVE_STATE_UNDEFINED;
         }
@@ -3440,15 +3406,12 @@ public class NotificationStackScrollLayout extends ViewGroup
             }
             mMoveState = newMoveState;
 
-            if (view instanceof ExpandableNotificationRow) {
-                ((ExpandableNotificationRow) view).setTranslationForOutline(translation);
-                if (!isPinnedHeadsUp(view)) {
-                    // Only show the gear if we're not a heads up view.
-                    checkForDrag();
-                    if (mCurrIconRow != null) {
-                        mCurrIconRow.updateSettingsIcons(translation, getSize(view));
-                    }
-                }
+            final boolean gutsExposed = (view instanceof ExpandableNotificationRow)
+                    && ((ExpandableNotificationRow) view).areGutsExposed();
+
+            if (!isPinnedHeadsUp(view) && !gutsExposed) {
+                // Only show the gear if we're not a heads up view and guts aren't exposed.
+                checkForDrag();
             }
         }
 
@@ -3471,12 +3434,12 @@ public class NotificationStackScrollLayout extends ViewGroup
                     (!fromLeft && absTrans >= snapBackThreshold * 0.4f
                             && absTrans <= notiThreshold);
 
-            if (pastGear && !isPinnedHeadsUp(animView)) {
+            if (pastGear && !isPinnedHeadsUp(animView)
+                    && (animView instanceof ExpandableNotificationRow)) {
                 // bouncity
                 final float target = fromLeft ? snapBackThreshold : -snapBackThreshold;
                 mGearExposedView = mTranslatingParentView;
-                if (mGearDisplayedListener != null
-                        && (animView instanceof ExpandableNotificationRow)) {
+                if (mGearDisplayedListener != null) {
                     mGearDisplayedListener.onGearDisplayed((ExpandableNotificationRow) animView);
                 }
                 super.snapChild(animView, target, velocity);
@@ -3486,38 +3449,16 @@ public class NotificationStackScrollLayout extends ViewGroup
         }
 
         @Override
-        public void onTranslationUpdate(View animView, float value, boolean canBeDismissed) {
-            if (mDismissAllInProgress) {
-                // When dismissing all, we translate the entire view instead.
-                super.onTranslationUpdate(animView, value, canBeDismissed);
-                return;
-            }
-            if (animView instanceof ExpandableNotificationRow) {
-                ((ExpandableNotificationRow) animView).setTranslationForOutline(value);
-            }
-            if (mCurrIconRow != null) {
-                mCurrIconRow.updateSettingsIcons(value, getSize(animView));
-            }
-        }
-
-        @Override
         public Animator getViewTranslationAnimator(View v, float target,
                 AnimatorUpdateListener listener) {
             if (mDismissAllInProgress) {
                 // When dismissing all, we translate the entire view instead.
                 return super.getViewTranslationAnimator(v, target, listener);
+            } else if (v instanceof ExpandableNotificationRow) {
+                return ((ExpandableNotificationRow) v).getTranslateViewAnimator(target, listener);
+            } else {
+                return super.getViewTranslationAnimator(v, target, listener);
             }
-            ArrayList<Animator> animators = new ArrayList<Animator>();
-            for (int i = 0; i < mTranslatingViews.size(); i++) {
-                ObjectAnimator anim = createTranslationAnimation(mTranslatingViews.get(i), target);
-                animators.add(anim);
-                if (i == 0 && listener != null) {
-                    anim.addUpdateListener(listener);
-                }
-            }
-            AnimatorSet set = new AnimatorSet();
-            set.playTogether(animators);
-            return set;
         }
 
         @Override
@@ -3525,13 +3466,8 @@ public class NotificationStackScrollLayout extends ViewGroup
             if (mDismissAllInProgress) {
                 // When dismissing all, we translate the entire view instead.
                 super.setTranslation(v, translate);
-                return;
-            }
-            // Translate the group of views
-            for (int i = 0; i < mTranslatingViews.size(); i++) {
-                if (mTranslatingViews.get(i) != null) {
-                    super.setTranslation(mTranslatingViews.get(i), translate);
-                }
+            } else {
+                ((ExpandableView) v).setTranslation(translate);
             }
         }
 
@@ -3540,15 +3476,11 @@ public class NotificationStackScrollLayout extends ViewGroup
             if (mDismissAllInProgress) {
                 // When dismissing all, we translate the entire view instead.
                 return super.getTranslation(v);
+            } else {
+                return ((ExpandableView) v).getTranslation();
             }
-            // All of the views in the list should have same translation, just use first one.
-            if (mTranslatingViews.size() > 0) {
-                return super.getTranslation(mTranslatingViews.get(0));
-            }
-            return 0;
         }
 
-
         /**
          * Returns the horizontal space in pixels required to display the gear behind a
          * notification.
@@ -3603,26 +3535,11 @@ public class NotificationStackScrollLayout extends ViewGroup
             final View prevGearExposedView = mGearExposedView;
             mGearExposedView = null;
 
-            AnimatorListenerAdapter listener = new AnimatorListenerAdapter() {
-                public void onAnimationEnd(Animator animator) {
-                    if (prevGearExposedView instanceof ExpandableNotificationRow) {
-                        ((ExpandableNotificationRow) prevGearExposedView).getSettingsRow()
-                                .resetState();
-                    }
-                }
-            };
-            AnimatorUpdateListener updateListener = new AnimatorUpdateListener() {
-                @Override
-                public void onAnimationUpdate(ValueAnimator animation) {
-                    if (prevGearExposedView instanceof ExpandableNotificationRow) {
-                        ((ExpandableNotificationRow) prevGearExposedView)
-                                .setTranslationForOutline((float) animation.getAnimatedValue());
-                    }
-                }
-            };
-            Animator set = getViewTranslationAnimator(prevGearExposedView, 0, updateListener);
-            set.addListener(listener);
-            set.start();
+            Animator anim = getViewTranslationAnimator(prevGearExposedView,
+                    0 /* leftTarget */, null /* updateListener */);
+            if (anim != null) {
+                anim.start();
+            }
         }
     }
 
index eea923f..4c94fe9 100644 (file)
@@ -52,13 +52,8 @@ public class StackScrollAlgorithm {
     private StackIndentationFunctor mBottomStackIndentationFunctor;
 
     private StackScrollAlgorithmState mTempAlgorithmState = new StackScrollAlgorithmState();
-    private boolean mIsExpansionChanging;
-    private int mFirstChildMaxHeight;
     private boolean mIsExpanded;
-    private ExpandableView mFirstChildWhileExpanding;
-    private boolean mExpandedOnStart;
     private int mBottomStackSlowDownLength;
-    private int mCollapseSecondCardPadding;
 
     public StackScrollAlgorithm(Context context) {
         initView(context);
@@ -86,8 +81,6 @@ public class StackScrollAlgorithm {
         mZBasicHeight = (MAX_ITEMS_IN_BOTTOM_STACK + 1) * mZDistanceBetweenElements;
         mBottomStackSlowDownLength = context.getResources()
                 .getDimensionPixelSize(R.dimen.bottom_stack_slow_down_length);
-        mCollapseSecondCardPadding = context.getResources().getDimensionPixelSize(
-                R.dimen.notification_collapse_second_card_padding);
         mBottomStackIndentationFunctor = new PiecewiseLinearIndentationFunctor(
                 MAX_ITEMS_IN_BOTTOM_STACK,
                 mBottomStackPeekSize,
@@ -508,7 +501,7 @@ public class StackScrollAlgorithm {
             int childHeight, int minHeight, AmbientState ambientState) {
 
         int bottomStackStart = ambientState.getInnerHeight()
-                - mBottomStackPeekSize - mCollapseSecondCardPadding;
+                - mBottomStackPeekSize - mBottomStackSlowDownLength;
         int childStart = bottomStackStart - childHeight;
         if (childStart < childViewState.yTranslation) {
             float newHeight = bottomStackStart - childViewState.yTranslation;
@@ -595,12 +588,9 @@ public class StackScrollAlgorithm {
 
             // The starting position of the bottom stack peek
             int bottomPeekStart = ambientState.getInnerHeight() - mBottomStackPeekSize -
-                    mCollapseSecondCardPadding + ambientState.getScrollY();
+                    mBottomStackSlowDownLength + ambientState.getScrollY();
             // Collapse and expand the first child while the shade is being expanded
-            float maxHeight = mIsExpansionChanging && child == mFirstChildWhileExpanding
-                    ? mFirstChildMaxHeight
-                    : childHeight;
-            childViewState.height = (int) Math.max(Math.min(bottomPeekStart, maxHeight),
+        childViewState.height = (int) Math.max(Math.min(bottomPeekStart, (float) childHeight),
                     child.getMinHeight());
     }
 
@@ -656,55 +646,6 @@ public class StackScrollAlgorithm {
         }
     }
 
-    public void onExpansionStarted(StackScrollState currentState) {
-        mIsExpansionChanging = true;
-        mExpandedOnStart = mIsExpanded;
-        ViewGroup hostView = currentState.getHostView();
-        updateFirstChildHeightWhileExpanding(hostView);
-    }
-
-    private void updateFirstChildHeightWhileExpanding(ViewGroup hostView) {
-        mFirstChildWhileExpanding = (ExpandableView) findFirstVisibleChild(hostView);
-        if (mFirstChildWhileExpanding != null) {
-            if (mExpandedOnStart) {
-
-                // We are collapsing the shade, so the first child can get as most as high as the
-                // current height or the end value of the animation.
-                mFirstChildMaxHeight = StackStateAnimator.getFinalActualHeight(
-                        mFirstChildWhileExpanding);
-            } else {
-                updateFirstChildMaxSizeToMaxHeight();
-            }
-        } else {
-            mFirstChildMaxHeight = 0;
-        }
-    }
-
-    private void updateFirstChildMaxSizeToMaxHeight() {
-        // We are expanding the shade, expand it to its full height.
-        if (!isMaxSizeInitialized(mFirstChildWhileExpanding)) {
-
-            // This child was not layouted yet, wait for a layout pass
-            mFirstChildWhileExpanding
-                    .addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
-                        @Override
-                        public void onLayoutChange(View v, int left, int top, int right,
-                                int bottom, int oldLeft, int oldTop, int oldRight,
-                                int oldBottom) {
-                            if (mFirstChildWhileExpanding != null) {
-                                mFirstChildMaxHeight = getMaxAllowedChildHeight(
-                                        mFirstChildWhileExpanding);
-                            } else {
-                                mFirstChildMaxHeight = 0;
-                            }
-                            v.removeOnLayoutChangeListener(this);
-                        }
-                    });
-        } else {
-            mFirstChildMaxHeight = getMaxAllowedChildHeight(mFirstChildWhileExpanding);
-        }
-    }
-
     private boolean isMaxSizeInitialized(ExpandableView child) {
         if (child instanceof ExpandableNotificationRow) {
             ExpandableNotificationRow row = (ExpandableNotificationRow) child;
@@ -724,32 +665,10 @@ public class StackScrollAlgorithm {
         return null;
     }
 
-    public void onExpansionStopped() {
-        mIsExpansionChanging = false;
-        mFirstChildWhileExpanding = null;
-    }
-
     public void setIsExpanded(boolean isExpanded) {
         this.mIsExpanded = isExpanded;
     }
 
-    public void notifyChildrenChanged(final NotificationStackScrollLayout hostView) {
-        if (mIsExpansionChanging) {
-            hostView.post(new Runnable() {
-                @Override
-                public void run() {
-                    updateFirstChildHeightWhileExpanding(hostView);
-                }
-            });
-        }
-    }
-
-    public void onReset(ExpandableView view) {
-        if (view.equals(mFirstChildWhileExpanding)) {
-            updateFirstChildMaxSizeToMaxHeight();
-        }
-    }
-
     class StackScrollAlgorithmState {
 
         /**
index 0ed6ef8..2524e1a 100644 (file)
@@ -125,7 +125,7 @@ public class TvStatusBar extends BaseStatusBar {
     }
 
     @Override
-    protected boolean isPanelFullyCollapsed() {
+    public boolean isPanelFullyCollapsed() {
         return false;
     }
 
index 61135bd..26e1d46 100644 (file)
@@ -20,6 +20,8 @@ import android.content.Intent;
 import android.provider.Settings;
 
 import com.android.internal.logging.MetricsProto.MetricsEvent;
+import com.android.systemui.Prefs;
+import com.android.systemui.Prefs.Key;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.statusbar.policy.NightModeController;
@@ -46,6 +48,12 @@ public class NightModeTile extends QSTile<QSTile.State> implements NightModeCont
     }
 
     @Override
+    public boolean isAvailable() {
+        return Prefs.getBoolean(mContext, Key.QS_NIGHT_ADDED, false)
+                && TunerService.isTunerEnabled(mContext);
+    }
+
+    @Override
     public void setListening(boolean listening) {
         if (listening) {
             mNightModeController.addListener(this);
index fb7fa4d..285dfd1 100644 (file)
@@ -25,6 +25,9 @@ import android.widget.ImageView;
 import android.widget.TextView;
 
 import com.android.systemui.R;
+import com.android.systemui.SystemUI;
+import com.android.systemui.SystemUIApplication;
+import com.android.systemui.recents.Recents;
 
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_PICTURE_IN_PICTURE;
@@ -47,6 +50,7 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
     private TextView mPlayPauseDescriptionTextView;
     private View mCloseButtonView;
     private View mCloseDescriptionView;
+    private boolean mPipMovedToFullscreen;
 
     private MediaController.Callback mMediaControllerCallback = new MediaController.Callback() {
         @Override
@@ -66,6 +70,7 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
             @Override
             public void onClick(View v) {
                 mPipManager.movePipToFullscreen();
+                mPipMovedToFullscreen = true;
                 finish();
             }
         });
@@ -164,7 +169,9 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
     }
 
     private void restorePipAndFinish() {
-        mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
+        if (!mPipMovedToFullscreen) {
+            mPipManager.resizePinnedStack(PipManager.STATE_PIP_OVERLAY);
+        }
         finish();
     }
 
@@ -214,4 +221,18 @@ public class PipMenuActivity extends Activity implements PipManager.Listener {
         mPipManager.suspendPipResizing(
                 PipManager.SUSPEND_PIP_RESIZE_REASON_WAITING_FOR_MENU_ACTIVITY_FINISH);
     }
+
+    @Override
+    public void finish() {
+        super.finish();
+        if (mPipManager.isRecentsShown() && !mPipMovedToFullscreen) {
+            SystemUI[] services = ((SystemUIApplication) getApplication()).getServices();
+            for (int i = services.length - 1; i >= 0; i--) {
+                if (services[i] instanceof Recents) {
+                    ((Recents) services[i]).showRecents(false, null);
+                    break;
+                }
+            }
+        }
+    }
 }
index c06b63b..005767f 100644 (file)
@@ -131,7 +131,7 @@ public class ZenFooter extends LinearLayout {
 
         final boolean isForever = mConfig != null && mConfig.manualRule != null
                 && mConfig.manualRule.conditionId == null;
-        final String line2 =
+        final CharSequence line2 =
                 isForever ? mContext.getString(com.android.internal.R.string.zen_mode_forever_dnd)
                 : ZenModeConfig.getConditionSummary(mContext, mConfig, mController.getCurrentUser(),
                         true /*shortVersion*/);
index 1841251..0151464 100644 (file)
@@ -43,7 +43,7 @@ public class TileServicesTests extends SysuiTestCase {
         QSTileHost host = new QSTileHost(mContext, null, null, null, null,
                 networkController, null,
                 Mockito.mock(HotspotController.class), null,
-                null, null, null, null, null, null, null);
+                null, null, null, null, null, null, null, null);
         mTileService = new TestTileServices(host, Looper.myLooper());
     }
 
index 00b8de2..19cb243 100644 (file)
@@ -19,12 +19,10 @@ import android.os.HandlerThread;
 import android.telephony.SubscriptionInfo;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
-
 import com.android.systemui.R;
+import com.android.systemui.statusbar.policy.NetworkController.EmergencyListener;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
 import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
-import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
-
 import org.mockito.ArgumentCaptor;
 import org.mockito.Mock;
 import org.mockito.Mockito;
index ebd5384..60d33fa 100644 (file)
@@ -32,6 +32,7 @@ import com.android.internal.telephony.cdma.EriInfo;
 import com.android.settingslib.net.DataUsageController;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
+import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.Config;
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.SubscriptionDefaults;
 import org.mockito.ArgumentCaptor;
@@ -100,7 +101,7 @@ public class NetworkControllerBaseTest extends SysuiTestCase {
 
         // Trigger blank callbacks to always get the current state (some tests don't trigger
         // changes from default state).
-        mNetworkController.addSignalCallback(null);
+        mNetworkController.addSignalCallback(mock(SignalCallback.class));
         mNetworkController.addEmergencyListener(null);
     }
 
index 471feef..f3140d2 100644 (file)
@@ -24,334 +24,1734 @@ message MetricsEvent {
 
   // Known visual elements: views or controls.
   enum View {
+    // Unknown view
     VIEW_UNKNOWN = 0;
+
+    // OBSOLETE
     MAIN_SETTINGS = 1;
+
+    // OPEN: Settings > Accessibility
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY = 2;
+
+    // OPEN: Settings > Accessibility > Captions
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY_CAPTION_PROPERTIES = 3;
+
+    // OPEN: Settings > Accessibility > [Service]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY_SERVICE = 4;
+
+    // OPEN: Settings > Accessibility > Color correction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY_TOGGLE_DALTONIZER = 5;
+
+    // OPEN: Settings > Accessibility > Accessibility shortcut
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY_TOGGLE_GLOBAL_GESTURE = 6;
+
+    // OPEN: Settings > Accessibility > Magnification gestures
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCESSIBILITY_TOGGLE_SCREEN_MAGNIFICATION = 7;
+
+    // OPEN: Settings > Accounts
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCOUNT = 8;
+
+    // OPEN: Settings > Accounts > [Single Account Sync Settings]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCOUNTS_ACCOUNT_SYNC = 9;
+
+    // OPEN: Settings > Accounts > Add an account
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCOUNTS_CHOOSE_ACCOUNT_ACTIVITY = 10;
+
+    // OPEN: Settings > Accounts > [List of accounts when more than one]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACCOUNTS_MANAGE_ACCOUNTS = 11;
+
+    // OPEN: Settings > Cellular network settings > APNs
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APN = 12;
+
+    // OPEN: Settings > More > Cellular network settings > APNs > [Edit APN]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APN_EDITOR = 13;
+
+    // OBSOLETE
     APP_OPS_DETAILS = 14;
+
+    // OBSOLETE
     APP_OPS_SUMMARY = 15;
+
+    // OBSOLETE
     APPLICATION = 16;
+
+    // OPEN: Settings > Apps > Configure apps > App links > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_APP_LAUNCH = 17;
+
+    // OBSOLETE
     APPLICATIONS_APP_PERMISSION = 18;
+
+    // OPEN: Settings > Internal storage > Apps storage > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_APP_STORAGE = 19;
+
+    // OPEN: Settings > Apps > [App info]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_INSTALLED_APP_DETAILS = 20;
+
+    // OPEN: Settings > Memory > App usage > [App Memory usage]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_PROCESS_STATS_DETAIL = 21;
+
+    // OBSOLETE
     APPLICATIONS_PROCESS_STATS_MEM_DETAIL = 22;
+
+    // OPEN: Settings > Memory > App usage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_PROCESS_STATS_UI = 23;
+
+    // OPEN: Settings > Bluetooth
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     BLUETOOTH = 24;
+
+    // OPEN: Choose Bluetooth device (ex: when sharing)
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     BLUETOOTH_DEVICE_PICKER = 25;
+
+    // OBSOLETE
     BLUETOOTH_DEVICE_PROFILES = 26;
+
+    // OPEN: Settings > Security > Choose screen lock
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CHOOSE_LOCK_GENERIC = 27;
+
+    // OPEN: Settings > Security > Choose screen lock > Choose your password
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CHOOSE_LOCK_PASSWORD = 28;
+
+    // OPEN: Settings > Security > Choose screen lock > Choose your pattern
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CHOOSE_LOCK_PATTERN = 29;
+
+    // OPEN: Settings > Security > Choose screen lock > Confirm your password
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CONFIRM_LOCK_PASSWORD = 30;
+
+    // OPEN: Settings > Security > Choose screen lock > Confirm your pattern
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CONFIRM_LOCK_PATTERN = 31;
+
+    // OPEN: Settings > Security > Encrypt phone
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CRYPT_KEEPER = 32;
+
+    // OPEN: Settings > Security > Encrypt phone > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     CRYPT_KEEPER_CONFIRM = 33;
+
+    // OPEN: Settings > Search results
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DASHBOARD_SEARCH_RESULTS = 34;
+
+    // OPEN: Settings (Root page)
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DASHBOARD_SUMMARY = 35;
+
+    // OBSOLETE
     DATA_USAGE = 36;
+
+    // OPEN: Settings > Data usage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DATA_USAGE_SUMMARY = 37;
+
+    // OPEN: Settings > Date & time
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DATE_TIME = 38;
+
+    // OPEN: Settings > Developer options
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVELOPMENT = 39;
+
+    // OPEN: Settings > About phone
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVICEINFO = 40;
+
+    // OPEN: Settings > About phone > Status > IMEI information
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVICEINFO_IMEI_INFORMATION = 41;
+
+    // OPEN: Settings > Internal storage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVICEINFO_STORAGE = 42;
+
+    // OPEN: Settings > About phone > Status > SIM status
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVICEINFO_SIM_STATUS = 43;
+
+    // OPEN: Settings > About phone > Status
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DEVICEINFO_STATUS = 44;
+
+    // OBSOLETE
     DEVICEINFO_USB = 45;
+
+    // OPEN: Settings > Display
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DISPLAY = 46;
+
+    // OPEN: Settings > Display > Daydream
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     DREAM = 47;
+
+    // OPEN: Settings > Security > Screen lock > Secure start-up
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ENCRYPTION = 48;
+
+    // OPEN: Settings > Security > Nexus Imprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FINGERPRINT = 49;
+
+    // OBSOLETE
     FINGERPRINT_ENROLL = 50;
+
+    // OPEN: Settings > Battery > History details
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FUELGAUGE_BATTERY_HISTORY_DETAIL = 51;
+
+    // OPEN: Settings > Battery > Battery saver
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FUELGAUGE_BATTERY_SAVER = 52;
+
+    // OPEN: Settings > Battery > [App Use details]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FUELGAUGE_POWER_USAGE_DETAIL = 53;
+
+    // OPEN: Settings > Battery
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FUELGAUGE_POWER_USAGE_SUMMARY = 54;
+
+    // OPEN: Settings > Home
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     HOME = 55;
+
+    // OPEN: Settings > Security > SIM card lock settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ICC_LOCK = 56;
+
+    // OPEN: Settings > Language & input
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     INPUTMETHOD_LANGUAGE = 57;
+
+    // OPEN: Settings > Language & input > Physical keyboard
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     INPUTMETHOD_KEYBOARD = 58;
+
+    // OPEN: Settings > Language & input > Spell checker
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     INPUTMETHOD_SPELL_CHECKERS = 59;
+
+    // OBSOLETE
     INPUTMETHOD_SUBTYPE_ENABLER = 60;
+
+    // OPEN: Settings > Language & input > Personal dictionary
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     INPUTMETHOD_USER_DICTIONARY = 61;
+
+    // OPEN: Settings > Language & input > Add word
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     INPUTMETHOD_USER_DICTIONARY_ADD_WORD = 62;
+
+    // OPEN: Settings > Location
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     LOCATION = 63;
+
+    // OPEN: Settings > Location > Location mode
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     LOCATION_MODE = 64;
+
+    // OPEN: Settings > Apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     MANAGE_APPLICATIONS = 65;
+
+    // OPEN: Settings > Backup & reset > Factory data reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     MASTER_CLEAR = 66;
+
+    // OPEN: Settings > Backup & reset > Factory data reset > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     MASTER_CLEAR_CONFIRM = 67;
+
+    // OPEN: Settings > Data usage > Network restrictions
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NET_DATA_USAGE_METERED = 68;
+
+    // OPEN: Settings > More > Android Beam
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NFC_BEAM = 69;
+
+    // OPEN: Settings > Tap & pay
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NFC_PAYMENT = 70;
+
+    // OPEN: Settings > Sound & notification
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION = 71;
+
+    // OPEN: Settings > Sound & notification > App notifications > [App]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_APP_NOTIFICATION = 72;
+
+    // OPEN: Settings > Sound & notification > Other sounds
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_OTHER_SOUND = 73;
+
+    // OBSOLETE
     NOTIFICATION_REDACTION = 74;
+
+    // OPEN: Settings Widget > Notification log
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_STATION = 75;
+
+    // OPEN: Settings > Sound & notification > Do not disturb
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE = 76;
+
+    // OPEN: OBSOLETE
     OWNER_INFO = 77;
+
+    // OPEN: Print job notification > Print job settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     PRINT_JOB_SETTINGS = 78;
+
+    // OPEN: Settings > Printing > [Print Service]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     PRINT_SERVICE_SETTINGS = 79;
+
+    // OPEN: Settings > Printing
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     PRINT_SETTINGS = 80;
+
+    // OPEN: Settings > Backup & reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     PRIVACY = 81;
+
+    //OBSOLETE
     PROXY_SELECTOR = 82;
+
+    // OPEN: Settings > Backup & reset > Network settings reset
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     RESET_NETWORK = 83;
+
+    // OPEN: Settings > Backup & reset > Network settings reset > Confirm
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     RESET_NETWORK_CONFIRM = 84;
+
+    // OPEN: Settings > Developer Options > Running Services
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     RUNNING_SERVICE_DETAILS = 85;
+
+    // OPEN: Settings > Security > Screen pinning
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     SCREEN_PINNING = 86;
+
+    // OPEN: Settings > Security
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     SECURITY = 87;
+
+    // OPEN: Settings > SIM cards
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     SIM = 88;
+
+    // OBSOLETE
     TESTING = 89;
+
+    // OPEN: Settings > More > Tethering & portable hotspot
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TETHER = 90;
+
+    // OPEN: Settings > Security > Trust agents
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TRUST_AGENT = 91;
+
+    // OPEN: Settings > Security > Trusted credentials
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TRUSTED_CREDENTIALS = 92;
+
+    // OPEN: Settings > Language & input > TTS output > [Engine] > Settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TTS_ENGINE_SETTINGS = 93;
+
+    // OPEN: Settings > Language & input > Text-to-speech output
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TTS_TEXT_TO_SPEECH = 94;
+
+    // OPEN: Settings > Security > Apps with usage access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     USAGE_ACCESS = 95;
+
+    // OPEN: Settings > Users
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     USER = 96;
+
+    // OPEN: Settings > Users > [Restricted profile app & content access]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     USERS_APP_RESTRICTIONS = 97;
+
+    // OPEN: Settings > Users > [User settings]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     USER_DETAILS = 98;
+
+    // OBSOLETE
     VOICE_INPUT = 99;
+
+    // OPEN: Settings > More > VPN
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     VPN = 100;
+
+    // OPEN: Settings > Display > Choose wallpaper from
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WALLPAPER_TYPE = 101;
+
+    // OPEN: Settings > Display > Cast
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WFD_WIFI_DISPLAY = 102;
+
+    // OPEN: Settings > Wi-Fi
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIFI = 103;
+
+    // OPEN: Settings > Wi-Fi > Advanced Wi-Fi
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIFI_ADVANCED = 104;
+
+    // OPEN: Settings > More > Wi-Fi Calling
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIFI_CALLING = 105;
+
+    // OPEN: Settings > Wi-Fi > Saved networks
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIFI_SAVED_ACCESS_POINTS = 106;
+
+    // OBSOLETE
     WIFI_APITEST = 107;
+
+    // OBSOLETE
     WIFI_INFO = 108;
+
+    // OPEN: Settings > Wi-Fi > Advanced Wi-Fi > Wi-Fi Direct
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIFI_P2P = 109;
+
+    // OPEN: Settings > More
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     WIRELESS = 110;
+
+    // OPEN: Quick Settings Panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_PANEL = 111;
+
+    // OPEN: QS Airplane mode tile shown
+    // ACTION: QS Airplane mode tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_AIRPLANEMODE = 112;
+
+    // OPEN: QS Bluetooth tile shown
+    // ACTION: QS Bluetooth tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_BLUETOOTH = 113;
+
+    // OPEN: QS Cast tile shown
+    // ACTION: QS Cast tile tapped
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_CAST = 114;
+
+    // OPEN: QS Cellular tile shown
+    // ACTION: QS Cellular tile tapped
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_CELLULAR = 115;
+
+    // OPEN: QS Color inversion tile shown
+    // ACTION: QS Color inversion tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_COLORINVERSION = 116;
+
+    // OPEN: QS Cellular tile > Cellular detail panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_DATAUSAGEDETAIL = 117;
+
+    // OPEN: QS Do not disturb tile shown
+    // ACTION: QS Do not disturb tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_DND = 118;
+
+    // OPEN: QS Flashlight tile shown
+    // ACTION: QS Flashlight tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_FLASHLIGHT = 119;
+
+    // OPEN: QS Hotspot tile shown
+    // ACTION: QS Hotspot tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_HOTSPOT = 120;
+
+    // OPEN: QS 3P tile shown
+    // ACTION: QS 3P tile tapped
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_INTENT = 121;
+
+    // OPEN: QS Location tile shown
+    // ACTION: QS Location tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_LOCATION = 122;
+
+    // OPEN: QS Rotation tile shown
+    // ACTION: QS Rotation tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_ROTATIONLOCK = 123;
+
+    // OBSOLETE
     QS_USERDETAILITE = 124;
+
+    // OPEN: QS User list panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_USERDETAIL = 125;
+
+    // OPEN: QS WiFi tile shown
+    // ACTION: QS WiFi tile tapped
+    //  SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.46
     QS_WIFI = 126;
+
+    // OPEN: Notification Panel (including lockscreen)
+    // CATEGORY: NOTIFICATION
+    // OS: 5.1.1
+    // GMS: 7.5.26
     NOTIFICATION_PANEL = 127;
+
+    // OPEN: Notification in panel became visible.
+    //   PACKAGE: App that posted the notification.
+    // ACTION: Notification is tapped.
+    //   PACKAGE: App that posted the notification
+    // DETAIL: Notification is expanded by user.
+    //   PACKAGE: App that posted the notification
+    // DISMISS: Notification is dismissed.
+    //   PACKAGE: App that posted the notification
+    //   SUBTYPE: Dismiss reason from NotificationManagerService.java
+    // CATEGORY: NOTIFICATION
+    // OS: 5.1.1
+    // GMS: 7.5.26
     NOTIFICATION_ITEM = 128;
+
+    // ACTION: User tapped notification action
+    //   PACKAGE: App that posted the notification
+    //   SUBTYPE: Index of action on notification
+    // CATEGORY: NOTIFICATION
+    // OS: 5.0
+    // GMS: 7.5.26
     NOTIFICATION_ITEM_ACTION = 129;
+
+    // OPEN: Settings > Apps > Configure apps > App permissions
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_ADVANCED = 130;
+
+    // OPEN: Settings > Location > Scanning
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     LOCATION_SCANNING = 131;
+
+    // OBSOLETE
     MANAGE_APPLICATIONS_ALL = 132;
+
+    // OPEN: Settings > Sound & notification > App notifications
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     MANAGE_APPLICATIONS_NOTIFICATIONS = 133;
+
+    // ACTION: Settings > Wi-Fi > Overflow > Add Network
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_ADD_NETWORK = 134;
+
+    // ACTION: Settings > Wi-Fi > [Long press network] > Connect to network
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_CONNECT = 135;
+
+    // ACTION: Settings > Wi-Fi > Overflow > Refresh
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_FORCE_SCAN = 136;
+
+    // ACTION: Settings > Wi-Fi > [Long press network] > Forget network
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_FORGET = 137;
+
+    // ACTION: Settings > Wi-Fi > Toggle off
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_OFF = 138;
+
+    // ACTION: Settings > Wi-Fi > Toggle on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_WIFI_ON = 139;
+
+    // OBSOLETE
     MANAGE_PERMISSIONS = 140;
+
+    // OPEN: Settings > Sound & notification > DND > Priority only allows
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_PRIORITY = 141;
+
+    // OPEN: Settings > Sound & notification > DND > Automatic rules
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_AUTOMATION = 142;
+
+    // OPEN: Settings > Apps > Configure apps > App links
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     MANAGE_DOMAIN_URLS = 143;
+
+    // OPEN: Settings > Sound & notification > DND > [Time based rule]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_SCHEDULE_RULE = 144;
+
+    // OPEN: Settings > Sound & notification > DND > [External rule]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_EXTERNAL_RULE = 145;
+
+    // OPEN: Settings > Sound & notification > DND > [Event rule]
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_EVENT_RULE = 146;
+
+    // ACTION: App notification settings > Block Notifications
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BAN_APP_NOTES = 147;
+
+    // ACTION: Notification shade > Dismiss all button
+    // CATEGORY: NOTIFICATION
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_DISMISS_ALL_NOTES = 148;
+
+    // OPEN: QS Do Not Disturb detail panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_DND_DETAILS = 149;
+
+    // OPEN: QS Bluetooth detail panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_BLUETOOTH_DETAILS = 150;
+
+    // OPEN: QS Cast detail panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_CAST_DETAILS = 151;
+
+    // OPEN: QS Wi-Fi detail panel
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_WIFI_DETAILS = 152;
+
+    // ACTION: QS Wi-Fi detail panel > Wi-Fi toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_WIFI_TOGGLE = 153;
+
+    // ACTION: QS Bluetooth detail panel > Bluetooth toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_BLUETOOTH_TOGGLE = 154;
+
+    // ACTION: QS Cellular detail panel > Cellular toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_CELLULAR_TOGGLE = 155;
+
+    // ACTION: QS User list panel > Select different user
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_SWITCH_USER = 156;
+
+    // ACTION: QS Cast detail panel > Select cast device
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_CAST_SELECT = 157;
+
+    // ACTION: QS Cast detail panel > Disconnect cast device
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_CAST_DISCONNECT = 158;
+
+    // ACTION: Settings > Bluetooth > Toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BLUETOOTH_TOGGLE = 159;
+
+    // ACTION: Settings > Bluetooth > Overflow > Refresh
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BLUETOOTH_SCAN = 160;
+
+    // ACTION: Settings > Bluetooth > Overflow > Rename this device
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BLUETOOTH_RENAME = 161;
+
+    // ACTION: Settings > Bluetooth > Overflow > Show received files
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BLUETOOTH_FILES = 162;
+
+    // ACTION: QS DND details panel > Increase / Decrease exit time
+    //   SUBTYPE: true is increase, false is decrease
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_DND_TIME = 163;
+
+    // ACTION: QS DND details panel > [Exit condition]
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_DND_CONDITION_SELECT = 164;
+
+    // ACTION: QS DND details panel > [DND mode]
+    //  SUBTYPE: 1 is priority, 2 is silence, 3 is alarms only
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_DND_ZEN_SELECT = 165;
+
+    // ACTION: QS DND detail panel > DND toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     QS_DND_TOGGLE = 166;
+
+    // ACTION: DND Settings > Priority only allows > Reminder toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ALLOW_REMINDERS = 167;
+
+    // ACTION: DND Settings > Priority only allows > Event toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ALLOW_EVENTS = 168;
+
+    // ACTION: DND Settings > Priority only allows > Messages
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ALLOW_MESSAGES = 169;
+
+    // ACTION: DND Settings > Priority only allows > Calls
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ALLOW_CALLS = 170;
+
+    // ACTION: DND Settings > Priority only allows > Repeat callers toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ALLOW_REPEAT_CALLS = 171;
+
+    // ACTION: DND Settings > Automatic rules > Add rule
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ADD_RULE = 172;
+
+    // ACTION: DND Settings > Automatic rules > Add rule > OK
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ADD_RULE_OK = 173;
+
+    // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_DELETE_RULE = 174;
+
+    // ACTION: DND Settings > Automatic rules > [Rule] > Delete rule > Delete
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_DELETE_RULE_OK = 175;
+
+    // ACTION: DND Settings > Automatic rules > [Rule] > Toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ZEN_ENABLE_RULE = 176;
+
+    // ACTION: Settings > More > Airplane mode toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_AIRPLANE_TOGGLE = 177;
+
+    // ACTION: Settings > Data usage > Cellular data toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_CELL_DATA_TOGGLE = 178;
+
+    // OPEN: Settings > Sound & notification > Notification access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ACCESS = 179;
+
+    // OPEN: Settings > Sound & notification > Do Not Disturb access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     NOTIFICATION_ZEN_MODE_ACCESS = 180;
+
+    // OPEN: Settings > Apps > Configure apps > Default Apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_DEFAULT_APPS = 181;
+
+    // OPEN: Settings > Internal storage > Apps storage
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_STORAGE_APPS = 182;
+
+    // OPEN: Settings > Security > Usage access
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_USAGE_ACCESS_DETAIL = 183;
+
+    // OPEN: Settings > Battery > Battery optimization
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_HIGH_POWER_APPS = 184;
+
+    // OBSOLETE
     FUELGAUGE_HIGH_POWER_DETAILS = 185;
+
+    // ACTION: Lockscreen > Unlock gesture
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_UNLOCK = 186;
+
+    // ACTION: Lockscreen > Pull shade open
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_SHADE = 187;
+
+    // ACTION: Lockscreen > Tap on lock, shows hint
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_HINT = 188;
+
+    // ACTION: Lockscreen > Camera
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_CAMERA = 189;
+
+    // ACTION: Lockscreen > Dialer
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_DIALER = 190;
+
+    // ACTION: Lockscreen > Tap on lock, locks phone
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_LOCK = 191;
+
+    // ACTION: Lockscreen > Tap on notification, false touch rejection
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     ACTION_LS_NOTE = 192;
+
+    // ACTION: Lockscreen > Swipe down to open quick settings
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.8.22
     ACTION_LS_QS = 193;
+
+    // ACTION: Swipe down to open quick settings when unlocked
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.8.22
     ACTION_SHADE_QS_PULL = 194;
+
+    // ACTION: Notification shade > Tap to open quick settings
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.8.22
     ACTION_SHADE_QS_TAP = 195;
+
+    // OPEN: Lockscreen
+    //   SUBTYPE: 0 is unsecure, 1 is secured by password / pattern / PIN
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     LOCKSCREEN = 196;
+
+    // OPEN: Lockscreen > Screen to enter password / pattern / PIN
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     BOUNCER = 197;
+
+    // OPEN: Screen turned on
+    //   SUBTYPE: 2 is user action
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.8.22
     SCREEN = 198;
+
+    // OPEN: Notification caused sound, vibration, and/or LED blink
+    //   SUBTYPE: 1 is buzz, 2 is beep, blink is 4, or'd together
+    // CATEGORY: NOTIFICATION
+    // OS: 5.1.1
+    // GMS: 7.8.53
     NOTIFICATION_ALERT = 199;
+
+    // ACTION: Lockscreen > Emergency Call button
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 5.1.1
+    // GMS: 7.5.26
     ACTION_EMERGENCY_CALL = 200;
+
+    // OPEN: Settings > Apps > Configure > Default apps > Assist & voice input
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     APPLICATIONS_MANAGE_ASSIST = 201;
+
+    // OPEN: Settings > Memory
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     PROCESS_STATS_SUMMARY = 202;
+
+    // ACTION: Settings > Display > When device is rotated
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ROTATION_LOCK = 203;
+
+    // ACTION: Long press on notification to view controls
+    // CATEGORY: NOTIFICATION
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_NOTE_CONTROLS = 204;
+
+    // ACTION: Notificatoin controls > Info button
+    // CATEGORY: NOTIFICATION
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_NOTE_INFO = 205;
+
+    // ACTION: Notification controls > Settings button
+    // CATEGORY: NOTIFICATION
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_APP_NOTE_SETTINGS = 206;
+
+    // OPEN: Volume Dialog (with hardware buttons)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     VOLUME_DIALOG = 207;
+
+    // OPEN: Volume dialog > Expanded volume dialog (multiple sliders)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     VOLUME_DIALOG_DETAILS = 208;
+
+    // ACTION: Volume dialog > Adjust volume slider
+    //   SUBTYPE: volume level (0-7)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_VOLUME_SLIDER = 209;
+
+    // ACTION: Volume dialog > Select non-active stream
+    //   SUBTYPE: stream (defined in AudioSystem.java)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_VOLUME_STREAM = 210;
+
+    // ACTION: Adjust volume with hardware key
+    //   SUBTYPE: volume level (0-7)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_VOLUME_KEY = 211;
+
+    // ACTION: Volume dialog > Mute a stream by tapping icon
+    //   SUBTYPE: mute is 1, audible is 2
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_VOLUME_ICON = 212;
+
+    // ACTION: Volume dialog > Change ringer mode by tapping icon
+    //   SUBTYPE: 2 is audible, 3 is vibrate
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_RINGER_MODE = 213;
+
+    // ACTION: Chooser shown (share target, file open, etc.)
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ACTIVITY_CHOOSER_SHOWN = 214;
+
+    // ACTION: Chooser > User taps an app target
+    //   SUBTYPE: Index of target
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ACTIVITY_CHOOSER_PICKED_APP_TARGET = 215;
+
+    // ACTION: Chooser > User taps a service target
+    //   SUBTYPE: Index of target
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ACTIVITY_CHOOSER_PICKED_SERVICE_TARGET = 216;
+
+    // ACTION: Chooser > User taps a standard target
+    //   SUBTYPE: Index of target
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ACTIVITY_CHOOSER_PICKED_STANDARD_TARGET = 217;
+
+    // ACTION: QS Brightness Slider (with auto brightness disabled)
+    //   SUBTYPE: slider value
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BRIGHTNESS = 218;
+
+    // ACTION: QS Brightness Slider (with auto brightness enabled)
+    //   SUBTYPE: slider value
+    // CATEGORY: QUICK_SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_BRIGHTNESS_AUTO = 219;
+
+    // OPEN: Settings > Display > Brightness Slider
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     BRIGHTNESS_DIALOG = 220;
+
+    // OPEN: Settings > Apps > Configure Apps > Draw over other apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     SYSTEM_ALERT_WINDOW_APPS = 221;
+
+    // OPEN: Display has entered dream mode
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     DREAMING = 222;
+
+    // OPEN: Display has entered ambient notification mode
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     DOZING = 223;
+
+    // OPEN: Overview
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     OVERVIEW_ACTIVITY = 224;
+
+    // OPEN: Settings > About phone > Legal information
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ABOUT_LEGAL_SETTINGS = 225;
+
+    // OPEN: Settings > Search > Perform search
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_SEARCH_RESULTS = 226;
+
+    // OPEN: Settings > System UI Tuner
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER = 227;
+
+    // OPEN: Settings > System UI Tuner > Quick Settings
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_QS = 228;
+
+    // OPEN: Settings > System UI Tuner > Demo mode
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_DEMO_MODE = 229;
+
+    // ACTION: Settings > System UI Tuner > Quick Settings > Move tile
+    //   PACKAGE: Tile
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_QS_REORDER = 230;
+
+    // ACTION: Settings > System UI Tuner > Quick Settings > Add tile
+    //   PACKAGE: Tile
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_QS_ADD = 231;
+
+    // ACTION: Settings > System UI Tuner > Quick Settings > Remove tile
+    //   PACKAGE: Tile
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_QS_REMOVE = 232;
+
+    // ACTION: Settings > System UI Tuner > Status bar > Enable icon
+    //   PACKAGE: Icon
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_STATUS_BAR_ENABLE = 233;
+
+    // ACTION: Settings > System UI Tuner > Status bar > Disable icon
+    //   PACKAGE: Icon
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_STATUS_BAR_DISABLE = 234;
+
+    // ACTION: Settings > System UI Tuner > Demo mode > Enable demo mode
+    //   SUBTYPE: false is disabled, true is enabled
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_DEMO_MODE_ENABLED = 235;
+
+    // ACTION: Settings > System UI Tuner > Demo mode > Show demo mode
+    //   SUBTYPE: false is disabled, true is enabled
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_DEMO_MODE_ON = 236;
+
+    // ACTION: Settings > System UI Tuner > Show embedded battery percentage
+    //   SUBTYPE: 0 is disabled, 1 is enabled
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     TUNER_BATTERY_PERCENTAGE = 237;
+
+    // OPEN: Settings > Developer options > Inactive apps
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.5.26
     FUELGAUGE_INACTIVE_APPS = 238;
+
+    // ACTION: Long press home to bring up assistant
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.5.26
     ACTION_ASSIST_LONG_PRESS = 239;
+
+    // OPEN: Settings > Security > Nexus Imprint > Add Fingerprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLLING = 240;
+
+    // OPEN: Fingerprint Enroll > Find Sensor
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_FIND_SENSOR = 241;
+
+    // OPEN: Fingerprint Enroll > Fingerprint Enrolled!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_FINISH = 242;
+
+    // OPEN: Fingerprint Enroll introduction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_INTRO = 243;
+
+    // OPEN: Fingerprint Enroll onboarding
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_ONBOARD = 244;
+
+    // OPEN: Fingerprint Enroll > Let's Start!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_SIDECAR = 245;
+
+    // OPEN: Fingerprint Enroll SUW > Let's Start!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLLING_SETUP = 246;
+
+    // OPEN: Fingerprint Enroll SUW > Find Sensor
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_FIND_SENSOR_SETUP = 247;
+
+    // OPEN: Fingerprint Enroll SUW > Fingerprint Enrolled!
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_FINISH_SETUP = 248;
+
+    // OPEN: Fingerprint Enroll SUW introduction
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_INTRO_SETUP = 249;
+
+    // OPEN: Fingerprint Enroll SUW onboarding
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     FINGERPRINT_ENROLL_ONBOARD_SETUP = 250;
+
+    // ACTION: Add fingerprint > Enroll fingerprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_FINGERPRINT_ENROLL = 251;
+
+    // ACTION: Authenticate using fingerprint
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_FINGERPRINT_AUTH = 252;
+
+    // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Delete
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_FINGERPRINT_DELETE = 253;
+
+    // ACTION: Settings > Security > Nexus Imprint > [Fingerprint] > Rename
+    // CATEGORY: SETTINGS
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_FINGERPRINT_RENAME = 254;
+
+    // ACTION: Double tap camera shortcut
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
+
+    // ACTION: Double twist camera shortcut
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: 6.0
+    // GMS: 7.8.99
     ACTION_WIGGLE_CAMERA_GESTURE = 256;
+
+    // OPEN: QS Work Mode tile shown
+    // ACTION: QS Work Mode tile tapped
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_WORKMODE = 257;
+
+    // OPEN: Settings > Developer Options > Background Check
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     BACKGROUND_CHECK_SUMMARY = 258;
+
+    // OPEN: QS Lock tile shown
+    // ACTION: QS Lock tile tapped
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_LOCK_TILE = 259;
+
+    // OPEN: QS User Tile shown
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_USER_TILE = 260;
+
+    // OPEN: QS Battery tile shown
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_BATTERY_TILE = 261;
+
+    // OPEN: Settings > Sound > Do not disturb > Visual interruptions
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     NOTIFICATION_ZEN_MODE_VISUAL_INTERRUPTIONS = 262;
+
+    // ACTION: Visual interruptions > No screen interuptions toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_ZEN_ALLOW_WHEN_SCREEN_OFF = 263;
-    // Dead
+
+    // ACTION: Visual interruptions > No notification light toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_ZEN_ALLOW_LIGHTS = 264;
+
+    // OPEN: Settings > Notifications > [App] > Topic Notifications
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     NOTIFICATION_TOPIC_NOTIFICATION = 265;
+
+    // ACTION: Settings > Apps > Default Apps > Select different SMS app
+    //   PACKAGE: Selected SMS app
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_DEFAULT_SMS_APP_CHANGED = 266;
+
+    // OPEN: QS Color modification tile shown
+    // ACTION: QS Color modification tile tapped
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_COLOR_MATRIX = 267;
+
+    // OPEN: QS Custom tile shown
+    // ACTION: QS Work Mode tile tapped
+    // CATEGORY: QUICK_SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     QS_CUSTOM = 268;
+
+    // ACTION: Visual interruptions > Never turn off the screen toggle
+    //   SUBTYPE: 0 is off, 1 is on
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_ZEN_ALLOW_WHEN_SCREEN_ON = 269;
 
-    // Logged when the user docks a window from recents by
-    // longpressing a task and dragging it to the dock area.
+    // ACTION: Overview > Long-press task, drag to enter split-screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_WINDOW_DOCK_DRAG_DROP = 270;
 
-    // Logged when the user docks a fullscreen window by long pressing
-    // recents which also opens recents on the lower/right side.
+    // ACTION: In App > Long-press Overview button to enter split-screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_WINDOW_DOCK_LONGPRESS = 271;
 
-    // Logged when the user docks a window by dragging from the navbar
-    // which also opens recents on the lower/right side.
+    // ACTION: In App > Swipe Overview button to enter split-screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_WINDOW_DOCK_SWIPE = 272;
 
-    // Logged when the user launches a profile-specific app and we
-    // intercept it with the confirm credentials UI.
+    // ACTION: Launch profile-specific app > Confirm credentials
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     PROFILE_CHALLENGE = 273;
 
+    // OPEN: QS Battery detail panel
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     QS_BATTERY_DETAIL = 274;
 
-    // Logged when the user goes into the overview history.
+    // OPEN: Overview > History
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     OVERVIEW_HISTORY = 275;
 
-    // Logged when the user pages through overview.
-    OVERVIEW_PAGE = 276;
+    // ACTION: Overview > Page by tapping Overview button
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_OVERVIEW_PAGE = 276;
 
-    // Logged when the user launches a task from overview.
-    OVERVIEW_SELECT = 277;
+    // ACTION: Overview > Select app
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
+    ACTION_OVERVIEW_SELECT = 277;
 
-    // Logged when the user views the emergency info.
+    // ACTION: View emergency info
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_VIEW_EMERGENCY_INFO = 278;
 
-    // Logged when the user views the edit emergency info activity.
+    // ACTION: Edit emergency info activity
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_EDIT_EMERGENCY_INFO = 279;
 
-    // Logged when the user edits an emergency info field.
+    // ACTION: Edit emergency info field
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_EDIT_EMERGENCY_INFO_FIELD = 280;
 
-    // Logged when the user adds a new emergency contact.
+    // ACTION: Add emergency contact
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_ADD_EMERGENCY_CONTACT = 281;
 
-    // Logged when the user deletes an emergency contact.
+    // ACTION: Delete emergency contact
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_DELETE_EMERGENCY_CONTACT = 282;
 
-    // Logged when the user calls an emergency contact.
+    // ACTION: Call emergency contact
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     ACTION_CALL_EMERGENCY_CONTACT = 283;
 
-    // QS Tile for Data Saver.
+    // OPEN: QS Data Saver tile shown
+    // ACTION: QS Data Saver tile tapped
+    // CATEGORY: QUICK_SETTINGS
     QS_DATA_SAVER = 284;
 
     // OPEN: Settings > Security > User credentials
     // CATEGORY: Settings
-    // OS: 6.1
+    // OS: N
     // GMS: 7.8.99
     USER_CREDENTIALS = 285;
 
-    // Logged when the user undocks a previously docked window by long pressing recents while in
-    // docked mode.
+    // ACTION: In App (splitscreen) > Long-press Overview to exit split-screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_WINDOW_UNDOCK_LONGPRESS = 286;
 
     // Logged when the user scrolls through overview manually
@@ -370,43 +1770,84 @@ message MetricsEvent {
     // indicate the user lowered the importance; positive means they increased it.
     ACTION_SAVE_IMPORTANCE = 291;
 
-    // Interactive bug report initiated from power menu.
+    // ACTION: Long-press power button, then tap "Take bug report" option.
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE = 292;
 
-    // Full bug report initiated from power menu.
+    // ACTION: Long-press power button, then long-press "Take bug report" option.
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_FROM_POWER_MENU_FULL = 293;
 
+    // ACTION: Settings -> Developer Options -> Take bug report -> Interactive report
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
     // Interactive bug report initiated from Settings.
     ACTION_BUGREPORT_FROM_SETTINGS_INTERACTIVE = 294;
 
-    // Full bug report initiated from Settings.
+    // ACTION: Settings -> Developer Options -> Take bug report -> Full report
+    // CATEGORY: SETTINGS
+    // OS: N
+    // GMS: 7.8.99
+    // Interactive bug report initiated from Settings.
     ACTION_BUGREPORT_FROM_SETTINGS_FULL = 295;
 
-    // Bug report canceled using system notification.
+    // ACTION: User tapped notification action to cancel a bug report
+    // CATEGORY: NOTIFICATION
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_NOTIFICATION_ACTION_CANCEL = 296;
 
-    // Bug report details screen open using system notification.
+    // ACTION: User tapped notification action to launch bug report details screen
+    // CATEGORY: NOTIFICATION
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_NOTIFICATION_ACTION_DETAILS = 297;
 
-    // Additional Bug report screen shot taken using system notification.
+    // ACTION: User tapped notification action to take adition screenshot on bug report
+    // CATEGORY: NOTIFICATION
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_NOTIFICATION_ACTION_SCREENSHOT = 298;
 
-    // Bug report shared by user using system notification.
+    // ACTION: User tapped notification to share bug report
+    // CATEGORY: NOTIFICATION
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_NOTIFICATION_ACTION_SHARE = 299;
 
-    // User changed bug report name using the details screen.
+    // ACTION: User changed bug report name using the details screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_DETAILS_NAME_CHANGED = 300;
 
-    // User changed bug report title using the details screen.
+    // ACTION: User changed bug report title using the details screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_DETAILS_TITLE_CHANGED = 301;
 
-    // User changed bug report description using the details screen.
+    // ACTION: User changed bug report description using the details screen
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_DETAILS_DESCRIPTION_CHANGED = 302;
 
-    // Changes made on bug report details screen were saved by user.
+    // ACTION: User tapped Save in the bug report details screen.
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_DETAILS_SAVED = 303;
 
-    // Changes made on bug report details screen were canceled by user.
+    // ACTION: User tapped Cancel in the bug report details screen.
+    // CATEGORY: GLOBAL_SYSTEM_UI
+    // OS: N
+    // GMS: 7.8.99
     ACTION_BUGREPORT_DETAILS_CANCELED = 304;
 
     // Tuner: Open/close calibrate dialog.
@@ -478,5 +1919,42 @@ message MetricsEvent {
     // Logged when we execute an app transition. This indicates the device uptime in seconds when
     // the transition was executed.
     APP_TRANSITION_DEVICE_UPTIME_SECONDS = 325;
+
+    // User granted access to the request folder; action takes an integer
+    // representing the folder's index on Environment.STANDARD_DIRECTORIES
+    ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_FOLDER = 326;
+
+    // User denied access to the request folder; action takes an integer
+    // representing the folder's index on Environment.STANDARD_DIRECTORIES
+    ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_FOLDER = 327;
+
+    // User granted access to the request folder; action pass package name
+    // of calling package.
+    ACTION_SCOPED_DIRECTORY_ACCESS_GRANTED_BY_PACKAGE = 328;
+
+    // User denied access to the request folder; action pass package name
+    // of calling package.
+    ACTION_SCOPED_DIRECTORY_ACCESS_DENIED_BY_PACKAGE = 329;
+
+    // App requested access to a directory it has already been granted
+    // access before; action takes an integer representing the folder's
+    // index on Environment.STANDARD_DIRECTORIES
+    ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_FOLDER = 330;
+
+    // App requested access to a directory it has already been granted
+    // access before; action pass package name of calling package.
+    ACTION_SCOPED_DIRECTORY_ACCESS_ALREADY_GRANTED_BY_PACKAGE = 331;
+
+    // Logged when the user slides a notification and
+    // reveals the gear beneath it.
+    ACTION_REVEAL_GEAR = 332;
+
+    // Logged when the user taps on the gear beneath
+    // a notification.
+    ACTION_TOUCH_GEAR = 333;
+
+    // Add new aosp constants above this line.
+    // END OF AOSP CONSTANTS
+
   }
 }
index 8c78a3a..fc92966 100644 (file)
@@ -115,7 +115,7 @@ public class Allocation extends BaseObj {
 
         if (cmp == Short.TYPE) {
             if (checkType) {
-                validateIsInt16();
+                validateIsInt16OrFloat16();
                 return mType.mElement.mType;
             }
             return Element.DataType.SIGNED_16;
@@ -402,9 +402,10 @@ public class Allocation extends BaseObj {
             "32 bit integer source does not match allocation type " + mType.mElement.mType);
     }
 
-    private void validateIsInt16() {
+    private void validateIsInt16OrFloat16() {
         if ((mType.mElement.mType == Element.DataType.SIGNED_16) ||
-            (mType.mElement.mType == Element.DataType.UNSIGNED_16)) {
+            (mType.mElement.mType == Element.DataType.UNSIGNED_16) ||
+            (mType.mElement.mType == Element.DataType.FLOAT_16)) {
             return;
         }
         throw new RSIllegalArgumentException(
@@ -751,7 +752,7 @@ public class Allocation extends BaseObj {
      * @param d the source data array
      */
     public void copyFrom(short[] d) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copyFromUnchecked(d, Element.DataType.SIGNED_16, d.length);
     }
 
@@ -1060,7 +1061,7 @@ public class Allocation extends BaseObj {
      * @param d the source data array
      */
     public void copy1DRangeFrom(int off, int count, short[] d) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copy1DRangeFromUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
     }
 
@@ -1204,7 +1205,7 @@ public class Allocation extends BaseObj {
      * @param data to be placed into the Allocation
      */
     public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copy2DRangeFromUnchecked(xoff, yoff, w, h, data,
                                  Element.DataType.SIGNED_16, data.length);
     }
@@ -1473,7 +1474,7 @@ public class Allocation extends BaseObj {
      * @param d The array to be set from the Allocation.
      */
     public void copyTo(short[] d) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copyTo(d, Element.DataType.SIGNED_16, d.length);
     }
 
@@ -1693,7 +1694,7 @@ public class Allocation extends BaseObj {
      * @param d the source data array
      */
     public void copy1DRangeTo(int off, int count, short[] d) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copy1DRangeToUnchecked(off, count, d, Element.DataType.SIGNED_16, d.length);
     }
 
@@ -1794,7 +1795,7 @@ public class Allocation extends BaseObj {
      * @param data Dest Array to be copied into
      */
     public void copy2DRangeTo(int xoff, int yoff, int w, int h, short[] data) {
-        validateIsInt16();
+        validateIsInt16OrFloat16();
         copy2DRangeToUnchecked(xoff, yoff, w, h, data,
                                Element.DataType.SIGNED_16, data.length);
     }
index 3bef19e..4877a37 100644 (file)
@@ -151,6 +151,7 @@ void UNUSED(T... t) {}
         return;                                                                         \
     case RS_TYPE_SIGNED_16:                                                             \
     case RS_TYPE_UNSIGNED_16:                                                           \
+    case RS_TYPE_FLOAT_16:                                                              \
         len = _env->GetArrayLength((jshortArray)data);                                  \
         ptr = _env->GetShortArrayElements((jshortArray)data, flag);                     \
         if (ptr == nullptr) {                                                           \
@@ -1061,7 +1062,7 @@ nElementCreate(JNIEnv *_env, jobject _this, jlong con, jlong type, jint kind, jb
               type, kind, norm, size);
     }
     return (jlong)(uintptr_t)rsElementCreate((RsContext)con, (RsDataType)type, (RsDataKind)kind,
-                                             norm, size);
+                                             norm, size, true);
 }
 
 static jlong
@@ -1100,7 +1101,7 @@ nElementCreate2(JNIEnv *_env, jobject _this, jlong con,
     jlong id = (jlong)(uintptr_t)rsElementCreate2((RsContext)con,
                                      (const RsElement *)ids, fieldCount,
                                      nameArray, fieldCount * sizeof(size_t),  sizeArray,
-                                     (const uint32_t *)arraySizes, fieldCount);
+                                     (const uint32_t *)arraySizes, fieldCount, true);
 
     free(ids);
     free(arraySizes);
@@ -1174,7 +1175,7 @@ nTypeCreate(JNIEnv *_env, jobject _this, jlong con, jlong eid,
     }
 
     return (jlong)(uintptr_t)rsTypeCreate((RsContext)con, (RsElement)eid, dimx, dimy, dimz, mips,
-                                          faces, yuv);
+                                          faces, yuv, true);
 }
 
 static void
@@ -1210,7 +1211,7 @@ nAllocationCreateTyped(JNIEnv *_env, jobject _this, jlong con, jlong type, jint
     }
     return (jlong)(uintptr_t) rsAllocationCreateTyped((RsContext)con, (RsType)type,
                                                       (RsAllocationMipmapControl)mips,
-                                                      (uint32_t)usage, (uintptr_t)pointer);
+                                                      (uint32_t)usage, (uintptr_t)pointer, true);
 }
 
 static void
@@ -1315,7 +1316,7 @@ nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong type,
     const void* ptr = bitmap.getPixels();
     jlong id = (jlong)(uintptr_t)rsAllocationCreateFromBitmap((RsContext)con,
                                                   (RsType)type, (RsAllocationMipmapControl)mip,
-                                                  ptr, bitmap.getSize(), usage);
+                                                  ptr, bitmap.getSize(), usage, true);
     bitmap.unlockPixels();
     return id;
 }
@@ -1331,7 +1332,7 @@ nAllocationCreateBitmapBackedAllocation(JNIEnv *_env, jobject _this, jlong con,
     const void* ptr = bitmap.getPixels();
     jlong id = (jlong)(uintptr_t)rsAllocationCreateTyped((RsContext)con,
                                             (RsType)type, (RsAllocationMipmapControl)mip,
-                                            (uint32_t)usage, (uintptr_t)ptr);
+                                            (uint32_t)usage, (uintptr_t)ptr, true);
     bitmap.unlockPixels();
     return id;
 }
@@ -1347,7 +1348,7 @@ nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, jlong con, jlong ty
     const void* ptr = bitmap.getPixels();
     jlong id = (jlong)(uintptr_t)rsAllocationCubeCreateFromBitmap((RsContext)con,
                                                       (RsType)type, (RsAllocationMipmapControl)mip,
-                                                      ptr, bitmap.getSize(), usage);
+                                                      ptr, bitmap.getSize(), usage, true);
     bitmap.unlockPixels();
     return id;
 }
index acd57b1..9e6c21c 100644 (file)
@@ -655,10 +655,9 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
             userState.mUiAutomationServiceOwner = owner;
             userState.mUiAutomationServiceClient = serviceClient;
             userState.mUiAutomationFlags = flags;
-            userState.mIsAccessibilityEnabled = true;
             userState.mInstalledServices.add(accessibilityServiceInfo);
             if ((flags & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0) {
-                // Set the temporary state.
+                // Set the temporary state, and use it instead of settings
                 userState.mIsTouchExplorationEnabled = false;
                 userState.mIsEnhancedWebAccessibilityEnabled = false;
                 userState.mIsDisplayMagnificationEnabled = false;
@@ -709,7 +708,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                 return;
             }
 
-            userState.mIsAccessibilityEnabled = true;
             userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
             userState.mIsEnhancedWebAccessibilityEnabled = false;
             userState.mIsDisplayMagnificationEnabled = false;
@@ -1245,17 +1243,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
         }
     }
 
-    private void manageServicesLocked(UserState userState) {
+    private void updateServicesLocked(UserState userState) {
         Map<ComponentName, Service> componentNameToServiceMap =
                 userState.mComponentNameToServiceMap;
         boolean isUnlocked = mContext.getSystemService(UserManager.class)
                 .isUserUnlocked(userState.mUserId);
-        boolean isEnabled = userState.mIsAccessibilityEnabled;
 
         for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
             AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
             ComponentName componentName = ComponentName.unflattenFromString(
                     installedService.getId());
+
             Service service = componentNameToServiceMap.get(componentName);
 
             // Ignore non-encryption-aware services until user is unlocked
@@ -1264,45 +1262,25 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                 continue;
             }
 
-            if (isEnabled) {
-                // Wait for the binding if it is in process.
-                if (userState.mBindingServices.contains(componentName)) {
+            // Wait for the binding if it is in process.
+            if (userState.mBindingServices.contains(componentName)) {
+                continue;
+            }
+            if (userState.mEnabledServices.contains(componentName)) {
+                if (service == null) {
+                    service = new Service(userState.mUserId, componentName, installedService);
+                } else if (userState.mBoundServices.contains(service)) {
                     continue;
                 }
-                if (userState.mEnabledServices.contains(componentName)) {
-                    if (service == null) {
-                        service = new Service(userState.mUserId, componentName, installedService);
-                    } else if (userState.mBoundServices.contains(service)) {
-                        continue;
-                    }
-                    service.bindLocked();
-                } else {
-                    if (service != null) {
-                        service.unbindLocked();
-                    }
-                }
+                service.bindLocked();
             } else {
                 if (service != null) {
                     service.unbindLocked();
-                } else {
-                    userState.mBindingServices.remove(componentName);
                 }
             }
         }
 
-        // No enabled installed services => disable accessibility to avoid
-        // sending accessibility events with no recipient across processes.
-        if (isEnabled && isUnlocked && userState.mBoundServices.isEmpty()
-                && userState.mBindingServices.isEmpty()) {
-            userState.mIsAccessibilityEnabled = false;
-            final long identity = Binder.clearCallingIdentity();
-            try {
-                Settings.Secure.putIntForUser(mContext.getContentResolver(),
-                        Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
-            } finally {
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
+        updateAccessibilityEnabledSetting(userState);
     }
 
     private void scheduleUpdateClientsIfNeededLocked(UserState userState) {
@@ -1329,7 +1307,8 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
             }
             // Touch exploration without accessibility makes no sense.
-            if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
+            if (userState.isHandlingAccessibilityEvents()
+                    && userState.mIsTouchExplorationEnabled) {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_TOUCH_EXPLORATION;
             }
             if (userState.mIsFilterKeyEventsEnabled) {
@@ -1468,25 +1447,17 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
     }
 
     private void updateWindowsForAccessibilityCallbackLocked(UserState userState) {
-        if (userState.mIsAccessibilityEnabled) {
-            // We observe windows for accessibility only if there is at least
-            // one bound service that can retrieve window content that specified
-            // it is interested in accessing such windows. For services that are
-            // binding we do an update pass after each bind event, so we run this
-            // code and register the callback if needed.
-            boolean boundServiceCanRetrieveInteractiveWindows = false;
-
-            List<Service> boundServices = userState.mBoundServices;
-            final int boundServiceCount = boundServices.size();
-            for (int i = 0; i < boundServiceCount; i++) {
-                Service boundService = boundServices.get(i);
-                if (boundService.canRetrieveInteractiveWindowsLocked()) {
-                    boundServiceCanRetrieveInteractiveWindows = true;
-                    break;
-                }
-            }
+        // We observe windows for accessibility only if there is at least
+        // one bound service that can retrieve window content that specified
+        // it is interested in accessing such windows. For services that are
+        // binding we do an update pass after each bind event, so we run this
+        // code and register the callback if needed.
 
-            if (boundServiceCanRetrieveInteractiveWindows) {
+        List<Service> boundServices = userState.mBoundServices;
+        final int boundServiceCount = boundServices.size();
+        for (int i = 0; i < boundServiceCount; i++) {
+            Service boundService = boundServices.get(i);
+            if (boundService.canRetrieveInteractiveWindowsLocked()) {
                 if (mWindowsForAccessibilityCallback == null) {
                     mWindowsForAccessibilityCallback = new WindowsForAccessibilityCallback();
                     mWindowManagerService.setWindowsForAccessibilityCallback(
@@ -1554,37 +1525,30 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
         userState.mIsFilterKeyEventsEnabled = false;
     }
 
-    private void updateServicesLocked(UserState userState) {
-        if (userState.mIsAccessibilityEnabled) {
-            manageServicesLocked(userState);
-        } else {
-            unbindAllServicesLocked(userState);
-        }
-    }
-
     private boolean readConfigurationForUserStateLocked(UserState userState) {
-        boolean somthingChanged = readAccessibilityEnabledSettingLocked(userState);
-        somthingChanged |= readInstalledAccessibilityServiceLocked(userState);
-        somthingChanged |= readEnabledAccessibilityServicesLocked(userState);
-        somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
-        somthingChanged |= readTouchExplorationEnabledSettingLocked(userState);
-        somthingChanged |= readHighTextContrastEnabledSettingLocked(userState);
-        somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
-        somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
-        somthingChanged |= readAutoclickEnabledSettingLocked(userState);
-        somthingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
-        return somthingChanged;
+        boolean somethingChanged = readInstalledAccessibilityServiceLocked(userState);
+        somethingChanged |= readEnabledAccessibilityServicesLocked(userState);
+        somethingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
+        somethingChanged |= readTouchExplorationEnabledSettingLocked(userState);
+        somethingChanged |= readHighTextContrastEnabledSettingLocked(userState);
+        somethingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
+        somethingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
+        somethingChanged |= readAutoclickEnabledSettingLocked(userState);
+        somethingChanged |= readDisplayColorAdjustmentSettingsLocked(userState);
+
+        return somethingChanged;
     }
 
-    private boolean readAccessibilityEnabledSettingLocked(UserState userState) {
-        final boolean accessibilityEnabled = Settings.Secure.getIntForUser(
-               mContext.getContentResolver(),
-               Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
-        if (accessibilityEnabled != userState.mIsAccessibilityEnabled) {
-            userState.mIsAccessibilityEnabled = accessibilityEnabled;
-            return true;
+    private void updateAccessibilityEnabledSetting(UserState userState) {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                    Settings.Secure.ACCESSIBILITY_ENABLED,
+                    userState.isHandlingAccessibilityEvents() ? 0 : 1,
+                    userState.mUserId);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
-        return false;
     }
 
     private boolean readTouchExplorationEnabledSettingLocked(UserState userState) {
@@ -1809,7 +1773,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
             // Check whether any Accessibility Services are still enabled and, if not, remove flag
             // requesting no soft keyboard
             final boolean accessibilityRequestingNoIme = userState.mSoftKeyboardShowMode == 1;
-            if (accessibilityRequestingNoIme && !userState.mIsAccessibilityEnabled) {
+            if (accessibilityRequestingNoIme && !userState.isHandlingAccessibilityEvents()) {
                 // No active Accessibility Services can be requesting the soft keyboard to be hidden
                 Settings.Secure.putIntForUser(mContext.getContentResolver(),
                         Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
@@ -1853,7 +1817,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                 UserState userState = mUserStates.valueAt(i);
                 pw.append("User state[attributes:{id=" + userState.mUserId);
                 pw.append(", currentUser=" + (userState.mUserId == mCurrentUserId));
-                pw.append(", accessibilityEnabled=" + userState.mIsAccessibilityEnabled);
                 pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled);
                 pw.append(", displayMagnificationEnabled="
                         + userState.mIsDisplayMagnificationEnabled);
@@ -2003,7 +1966,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
         private void announceNewUserIfNeeded() {
             synchronized (mLock) {
                 UserState userState = getCurrentUserStateLocked();
-                if (userState.mIsAccessibilityEnabled) {
+                if (userState.isHandlingAccessibilityEvents()) {
                     UserManager userManager = (UserManager) mContext.getSystemService(
                             Context.USER_SERVICE);
                     String message = mContext.getString(R.string.user_switched,
@@ -4061,7 +4024,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
 
         public int mSoftKeyboardShowMode = 0;
 
-        public boolean mIsAccessibilityEnabled;
         public boolean mIsTouchExplorationEnabled;
         public boolean mIsTextHighContrastEnabled;
         public boolean mIsEnhancedWebAccessibilityEnabled;
@@ -4096,11 +4058,11 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
 
         public int getClientState() {
             int clientState = 0;
-            if (mIsAccessibilityEnabled) {
+            if (isHandlingAccessibilityEvents()) {
                 clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
             }
             // Touch exploration relies on enabled accessibility.
-            if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
+            if (isHandlingAccessibilityEvents() && mIsTouchExplorationEnabled) {
                 clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
             }
             if (mIsTextHighContrastEnabled) {
@@ -4109,6 +4071,10 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
             return clientState;
         }
 
+        public boolean isHandlingAccessibilityEvents() {
+            return !mBoundServices.isEmpty() || !mBoundServices.isEmpty();
+        }
+
         public void onSwitchToAnotherUser() {
             // Clear UI test automation state.
             if (mUiAutomationService != null) {
@@ -4128,7 +4094,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
             // Clear state persisted in settings.
             mEnabledServices.clear();
             mTouchExplorationGrantedServices.clear();
-            mIsAccessibilityEnabled = false;
             mIsTouchExplorationEnabled = false;
             mIsEnhancedWebAccessibilityEnabled = false;
             mIsDisplayMagnificationEnabled = false;
@@ -4155,9 +4120,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
 
     private final class AccessibilityContentObserver extends ContentObserver {
 
-        private final Uri mAccessibilityEnabledUri = Settings.Secure.getUriFor(
-                Settings.Secure.ACCESSIBILITY_ENABLED);
-
         private final Uri mTouchExplorationEnabledUri = Settings.Secure.getUriFor(
                 Settings.Secure.TOUCH_EXPLORATION_ENABLED);
 
@@ -4199,8 +4161,6 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
         }
 
         public void register(ContentResolver contentResolver) {
-            contentResolver.registerContentObserver(mAccessibilityEnabledUri,
-                    false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(mTouchExplorationEnabledUri,
                     false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(mDisplayMagnificationEnabledUri,
@@ -4240,11 +4200,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub {
                     return;
                 }
 
-                if (mAccessibilityEnabledUri.equals(uri)) {
-                    if (readAccessibilityEnabledSettingLocked(userState)) {
-                        onUserStateChangedLocked(userState);
-                    }
-                } else if (mTouchExplorationEnabledUri.equals(uri)) {
+                if (mTouchExplorationEnabledUri.equals(uri)) {
                     if (readTouchExplorationEnabledSettingLocked(userState)) {
                         onUserStateChangedLocked(userState);
                     }
index f537d18..8603981 100644 (file)
 
 package com.android.server.appwidget;
 
+import static android.content.Context.KEYGUARD_SERVICE;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+
 import android.app.AlarmManager;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.KeyguardManager;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.DevicePolicyManagerInternal.OnCrossProfileWidgetProvidersChangeListener;
@@ -72,10 +77,12 @@ import android.util.SparseIntArray;
 import android.util.TypedValue;
 import android.util.Xml;
 import android.view.Display;
+import android.view.View;
 import android.view.WindowManager;
 import android.widget.RemoteViews;
 
 import com.android.internal.R;
+import com.android.internal.app.UnlaunchableAppActivity;
 import com.android.internal.appwidget.IAppWidgetHost;
 import com.android.internal.appwidget.IAppWidgetService;
 import com.android.internal.os.BackgroundThread;
@@ -146,7 +153,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
             final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
 
             if (DEBUG) {
-                Slog.i(TAG, "Received broadcast: " + action);
+                Slog.i(TAG, "Received broadcast: " + action + " on user " + userId);
             }
 
             if (Intent.ACTION_CONFIGURATION_CHANGED.equals(action)) {
@@ -156,10 +163,10 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
             } else if (Intent.ACTION_USER_STOPPED.equals(action)) {
                 onUserStopped(userId);
             } else if (Intent.ACTION_USER_SWITCHED.equals(action)) {
-                reloadWidgetsMaskedStateForUser(userId);
+                reloadWidgetsMaskedStateForGroup(userId);
             } else if (Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED.equals(action)) {
                 synchronized (mLock) {
-                    reloadWidgetProfileUnavailableMaskedStateLocked(userId);
+                    reloadWidgetsMaskedState(userId);
                 }
             } else if (Intent.ACTION_PACKAGES_SUSPENDED.equals(action)) {
                 String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
@@ -202,6 +209,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
     private final AlarmManager mAlarmManager;
     private final UserManager mUserManager;
     private final AppOpsManager mAppOpsManager;
+    private final KeyguardManager mKeyguardManager;
 
     private final SecurityPolicy mSecurityPolicy;
 
@@ -223,6 +231,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
         mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mKeyguardManager = (KeyguardManager) mContext.getSystemService(KEYGUARD_SERVICE);
         mSaveStateHandler = BackgroundThread.getHandler();
         mCallbackHandler = new CallbackHandler(mContext.getMainLooper());
         mBackupRestoreController = new BackupRestoreController();
@@ -436,48 +445,51 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
     /**
      * Reload all widgets' masked state for the given user and its associated profiles, including
      * due to user not being available and package suspension.
+     * userId must be the group parent.
      */
-    private void reloadWidgetsMaskedStateForUser(int userId) {
-        if (!mUserManager.isUserUnlocked(userId) ||
-                isProfileWithLockedParent(userId)) {
+    private void reloadWidgetsMaskedStateForGroup(int userId) {
+        if (!mUserManager.isUserUnlocked(userId)) {
             return;
         }
         synchronized (mLock) {
-            reloadWidgetPackageSuspensionMaskedStateLocked(userId);
+            reloadWidgetsMaskedState(userId);
             List<UserInfo> profiles = mUserManager.getEnabledProfiles(userId);
             if (profiles != null) {
                 for (int i = 0; i < profiles.size(); i++) {
                     UserInfo user  = profiles.get(i);
-                    reloadWidgetProfileUnavailableMaskedStateLocked(user.id);
-                    reloadWidgetPackageSuspensionMaskedStateLocked(user.id);
+                    reloadWidgetsMaskedState(user.id);
                 }
             }
         }
     }
 
-    /**
-     * Mask/unmask widgets in the given profile, depending on the quiet state
-     * or locked state of the profile.
-     */
-    private void reloadWidgetProfileUnavailableMaskedStateLocked(int profileId) {
+    private void reloadWidgetsMaskedState(int userId) {
         final long identity = Binder.clearCallingIdentity();
         try {
-            if (!isProfileWithUnlockedParent(profileId)) {
-                return;
-            }
-            UserInfo user  = mUserManager.getUserInfo(profileId);
-            boolean shouldMask = user.isQuietModeEnabled() ||
-                    !mUserManager.isUserUnlocked(user.getUserHandle());
+            UserInfo user  = mUserManager.getUserInfo(userId);
+
+            boolean lockedProfile = !mUserManager.isUserUnlocked(userId);
+            boolean quietProfile = user.isQuietModeEnabled();
             final int N = mProviders.size();
             for (int i = 0; i < N; i++) {
                 Provider provider = mProviders.get(i);
                 int providerUserId = provider.getUserId();
-                if (providerUserId != profileId) {
+                if (providerUserId != userId) {
                     continue;
                 }
-                if (provider.setMaskedByProfileUnavailabledLocked(shouldMask)) {
+
+                boolean changed = provider.setMaskedByLockedProfileLocked(lockedProfile);
+                changed |= provider.setMaskedByQuietProfileLocked(quietProfile);
+                try {
+                    boolean suspended = mPackageManager.isPackageSuspendedForUser(
+                            provider.info.provider.getPackageName(), provider.getUserId());
+                    changed |= provider.setMaskedBySuspendedPackageLocked(suspended);
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to query application info", e);
+                }
+                if (changed) {
                     if (provider.isMaskedLocked()) {
-                        maskWidgetsViewsLocked(provider);
+                        maskWidgetsViewsLocked(provider, null);
                     } else {
                         unmaskWidgetsViewsLocked(provider);
                     }
@@ -489,33 +501,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
     }
 
     /**
-     * Reload widget's masked state due to package suspension state.
-     */
-    private void reloadWidgetPackageSuspensionMaskedStateLocked(int profileId) {
-        final int N = mProviders.size();
-        for (int i = 0; i < N; i++) {
-            Provider provider = mProviders.get(i);
-            int providerUserId = provider.getUserId();
-            if (providerUserId != profileId) {
-                continue;
-            }
-            try {
-                boolean suspended = mPackageManager.isPackageSuspendedForUser(
-                        provider.info.provider.getPackageName(), provider.getUserId());
-                if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
-                    if (provider.isMaskedLocked()) {
-                        maskWidgetsViewsLocked(provider);
-                    } else {
-                        unmaskWidgetsViewsLocked(provider);
-                    }
-                }
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to query application info", e);
-            }
-        }
-    }
-
-    /**
      * Incrementally update the masked state due to package suspension state.
      */
     private void updateWidgetPackageSuspensionMaskedState(String[] packagesArray, boolean suspended,
@@ -535,7 +520,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
                 }
                 if (provider.setMaskedBySuspendedPackageLocked(suspended)) {
                     if (provider.isMaskedLocked()) {
-                        maskWidgetsViewsLocked(provider);
+                        maskWidgetsViewsLocked(provider, null);
                     } else {
                         unmaskWidgetsViewsLocked(provider);
                     }
@@ -544,14 +529,13 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
         }
     }
 
-    private Bitmap createMaskedWidgetBitmap(Provider provider) {
+    private Bitmap createMaskedWidgetBitmap(String providerPackage, int providerUserId) {
         final long identity = Binder.clearCallingIdentity();
         try {
             // Load the unbadged application icon and pass it to the widget to appear on
             // the masked view.
-            final String providerPackage = provider.info.provider.getPackageName();
             Context userContext = mContext.createPackageContextAsUser(providerPackage, 0,
-                    UserHandle.of(provider.getUserId()));
+                    UserHandle.of(providerUserId));
             PackageManager pm = userContext.getPackageManager();
             Drawable icon = pm.getApplicationInfo(providerPackage, 0).loadUnbadgedIcon(pm);
             // Create a bitmap of the icon which is what the widget's remoteview requires.
@@ -566,18 +550,73 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
         }
     }
 
-    private void maskWidgetsViewsLocked(Provider provider) {
-        Bitmap iconBitmap = createMaskedWidgetBitmap(provider);
+    private RemoteViews createMaskedWidgetRemoteViews(Bitmap icon, boolean showBadge,
+            PendingIntent onClickIntent) {
+        RemoteViews views = new RemoteViews(mContext.getPackageName(),
+                R.layout.work_widget_mask_view);
+        if (icon != null) {
+            views.setImageViewBitmap(R.id.work_widget_app_icon, icon);
+        }
+        if (!showBadge) {
+            views.setViewVisibility(R.id.work_widget_badge_icon, View.INVISIBLE);
+        }
+        if (onClickIntent != null) {
+            views.setOnClickPendingIntent(R.id.work_widget_mask_frame, onClickIntent);
+        }
+        return views;
+    }
+
+    /**
+     * Mask the target widget belonging to the specified provider, or all active widgets
+     * of the provider if target widget == null.
+     */
+    private void maskWidgetsViewsLocked(Provider provider, Widget targetWidget) {
+        final int widgetCount = provider.widgets.size();
+        if (widgetCount == 0) {
+            return;
+        }
+        final String providerPackage = provider.info.provider.getPackageName();
+        final int providerUserId = provider.getUserId();
+        Bitmap iconBitmap = createMaskedWidgetBitmap(providerPackage, providerUserId);
         if (iconBitmap == null) {
             return;
         }
+        final boolean showBadge;
+        final Intent onClickIntent;
+        if (provider.maskedBySuspendedPackage) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                UserInfo userInfo = mUserManager.getUserInfo(providerUserId);
+                showBadge = userInfo.isManagedProfile();
+                onClickIntent = UnlaunchableAppActivity.createPackageSuspendedDialogIntent(
+                        providerPackage, providerUserId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        } else if (provider.maskedByQuietProfile) {
+            showBadge = true;
+            onClickIntent = UnlaunchableAppActivity.createInQuietModeDialogIntent(
+                    providerUserId);
+        } else /* provider.maskedByLockedProfile */ {
+            showBadge = true;
+            onClickIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null,
+                    providerUserId);
+            if (onClickIntent != null) {
+                onClickIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+            }
+        }
 
-        final int widgetCount = provider.widgets.size();
         for (int j = 0; j < widgetCount; j++) {
             Widget widget = provider.widgets.get(j);
-            if (widget.replaceWithMaskedViewsLocked(mContext, iconBitmap)) {
-                scheduleNotifyUpdateAppWidgetLocked(widget,
-                        widget.getEffectiveViewsLocked());
+            if (targetWidget != null && targetWidget != widget) continue;
+            PendingIntent intent = null;
+            if (onClickIntent != null) {
+                intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
+                        onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+            }
+            RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
+            if (widget.replaceWithMaskedViewsLocked(views)) {
+                scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
             }
         }
     }
@@ -587,8 +626,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
         for (int j = 0; j < widgetCount; j++) {
             Widget widget = provider.widgets.get(j);
             if (widget.clearMaskedViewsLocked()) {
-                scheduleNotifyUpdateAppWidgetLocked(widget,
-                        widget.getEffectiveViewsLocked());
+                scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
             }
         }
     }
@@ -2472,7 +2510,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
         }
         synchronized (mLock) {
             ensureGroupStateLoadedLocked(userId);
-            reloadWidgetsMaskedStateForUser(userId);
+            reloadWidgetsMaskedStateForGroup(mSecurityPolicy.getGroupParent(userId));
 
             final int N = mProviders.size();
             for (int i = 0; i < N; i++) {
@@ -2614,10 +2652,7 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
         // If we are adding a widget it might be for a provider that
         // is currently masked, if so mask the widget.
         if (widget.provider.isMaskedLocked()) {
-            Bitmap bitmap = createMaskedWidgetBitmap(widget.provider);
-            if (bitmap != null) {
-                widget.replaceWithMaskedViewsLocked(mContext, bitmap);
-            }
+            maskWidgetsViewsLocked(widget.provider, widget);
         } else {
             widget.clearMaskedViewsLocked();
         }
@@ -3014,7 +3049,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
 
     private void onUserStopped(int userId) {
         synchronized (mLock) {
-            boolean providersChanged = false;
             boolean crossProfileWidgetsChanged = false;
 
             // Remove widgets that have both host and provider in the user.
@@ -3050,16 +3084,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
                 }
             }
 
-            // Remove the providers and notify hosts in other profiles.
-            final int providerCount = mProviders.size();
-            for (int i = providerCount - 1; i >= 0; i--) {
-                Provider provider = mProviders.get(i);
-                if (provider.getUserId() == userId) {
-                    crossProfileWidgetsChanged |= !provider.widgets.isEmpty();
-                    providersChanged = true;
-                    deleteProviderLocked(provider);
-                }
-            }
+            // Leave the providers present as hosts will show the widgets
+            // masked while the user is stopped.
 
             // Remove grants for this user.
             final int grantCount = mPackagesWithBindWidgetPermission.size();
@@ -3082,11 +3108,6 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
                 mNextAppWidgetIds.removeAt(nextIdIndex);
             }
 
-            // Announce removed provider changes to all hosts in the group.
-            if (providersChanged) {
-                scheduleNotifyGroupHostsForProvidersChangedLocked(userId);
-            }
-
             // Save state if removing a profile changed the group state.
             // Nothing will be saved if the group parent was removed.
             if (crossProfileWidgetsChanged) {
@@ -3624,7 +3645,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
         PendingIntent broadcast;
         boolean zombie; // if we're in safe mode, don't prune this just because nobody references it
 
-        boolean maskedByProfileUnavailable;
+        boolean maskedByLockedProfile;
+        boolean maskedByQuietProfile;
         boolean maskedBySuspendedPackage;
 
         int tag = TAG_UNDEFINED; // for use while saving state (the index)
@@ -3656,22 +3678,29 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
             return "Provider{" + id + (zombie ? " Z" : "") + '}';
         }
 
-        // returns true if the provider's masked state is changed as a result
-        public boolean setMaskedByProfileUnavailabledLocked(boolean masked) {
-            boolean oldMaskedState = isMaskedLocked();
-            maskedByProfileUnavailable = masked;
-            return isMaskedLocked() != oldMaskedState;
+        // returns true if it's different from previous state.
+        public boolean setMaskedByQuietProfileLocked(boolean masked) {
+            boolean oldState = maskedByQuietProfile;
+            maskedByQuietProfile = masked;
+            return masked != oldState;
+        }
+
+        // returns true if it's different from previous state.
+        public boolean setMaskedByLockedProfileLocked(boolean masked) {
+            boolean oldState = maskedByLockedProfile;
+            maskedByLockedProfile = masked;
+            return masked != oldState;
         }
 
-        // returns true if the provider's masked state is changed as a result
+        // returns true if it's different from previous state.
         public boolean setMaskedBySuspendedPackageLocked(boolean masked) {
-            boolean oldMaskedState = isMaskedLocked();
+            boolean oldState = maskedBySuspendedPackage;
             maskedBySuspendedPackage = masked;
-            return isMaskedLocked() != oldMaskedState;
+            return masked != oldState;
         }
 
         public boolean isMaskedLocked() {
-            return maskedByProfileUnavailable || maskedBySuspendedPackage;
+            return maskedByQuietProfile || maskedByLockedProfile || maskedBySuspendedPackage;
         }
     }
 
@@ -3828,14 +3857,8 @@ class AppWidgetServiceImpl extends IAppWidgetService.Stub implements WidgetBacku
             return "AppWidgetId{" + appWidgetId + ':' + host + ':' + provider + '}';
         }
 
-        private boolean replaceWithMaskedViewsLocked(Context context, Bitmap icon) {
-            if (maskedViews != null) {
-                return false;
-            }
-            maskedViews = new RemoteViews(context.getPackageName(), R.layout.work_widget_mask_view);
-            if (icon != null) {
-                maskedViews.setImageViewBitmap(R.id.work_widget_app_icon, icon);
-            }
+        private boolean replaceWithMaskedViewsLocked(RemoteViews views) {
+            maskedViews = views;
             return true;
         }
 
index f1a9c44..cd4d107 100644 (file)
@@ -3495,9 +3495,8 @@ public class BackupManagerService {
             // The agent was running with a stub Application object, so shut it down.
             // !!! We hardcode the confirmation UI's package name here rather than use a
             //     manifest flag!  TODO something less direct.
-            if (app.uid != Process.SYSTEM_UID
-                    && !app.packageName.equals("com.android.backupconfirm")
-                    && app.uid != Process.PHONE_UID) {
+            if (app.uid >= Process.FIRST_APPLICATION_UID
+                    && !app.packageName.equals("com.android.backupconfirm")) {
                 if (MORE_DEBUG) Slog.d(TAG, "Killing agent host process");
                 mActivityManager.killApplicationProcess(app.processName, app.uid);
             } else {
@@ -6881,7 +6880,7 @@ if (MORE_DEBUG) Slog.v(TAG, "   + got " + nRead + "; now wanting " + (size - soF
                     // The agent was running with a stub Application object, so shut it down.
                     // !!! We hardcode the confirmation UI's package name here rather than use a
                     //     manifest flag!  TODO something less direct.
-                    if (app.uid != Process.SYSTEM_UID
+                    if (app.uid >= Process.FIRST_APPLICATION_UID
                             && !app.packageName.equals("com.android.backupconfirm")) {
                         if (DEBUG) Slog.d(TAG, "Killing host process");
                         mActivityManager.killApplicationProcess(app.processName, app.uid);
@@ -8625,13 +8624,15 @@ if (MORE_DEBUG) Slog.v(TAG, "   + got " + nRead + "; now wanting " + (size - soF
                     // it is explicitly not killed following that operation.
                     //
                     // We execute this kill when these conditions hold:
-                    //    1. the app did not request its own restore (mTargetPackage == null), and either
-                    //    2a. the app is a full-data target (TYPE_FULL_STREAM) or
+                    //    1. it's not a system-uid process,
+                    //    2. the app did not request its own restore (mTargetPackage == null), and either
+                    //    3a. the app is a full-data target (TYPE_FULL_STREAM) or
                     //     b. the app does not state android:killAfterRestore="false" in its manifest
                     final int appFlags = mCurrentPackage.applicationInfo.flags;
                     final boolean killAfterRestore =
-                            (mRestoreDescription.getDataType() == RestoreDescription.TYPE_FULL_STREAM)
-                            || ((appFlags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0);
+                            (mCurrentPackage.applicationInfo.uid >= Process.FIRST_APPLICATION_UID)
+                            && ((mRestoreDescription.getDataType() == RestoreDescription.TYPE_FULL_STREAM)
+                                    || ((appFlags & ApplicationInfo.FLAG_KILL_AFTER_RESTORE) != 0));
 
                     if (mTargetPackage == null && killAfterRestore) {
                         if (DEBUG) Slog.d(TAG, "Restore complete, killing host process of "
index 4300920..86040c2 100644 (file)
@@ -125,6 +125,7 @@ import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkMonitor;
 import com.android.server.connectivity.PacManager;
 import com.android.server.connectivity.PermissionMonitor;
+import com.android.server.connectivity.ApfFilter;
 import com.android.server.connectivity.Tethering;
 import com.android.server.connectivity.Vpn;
 import com.android.server.net.BaseNetworkObserver;
@@ -163,7 +164,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
         implements PendingIntent.OnFinished {
     private static final String TAG = "ConnectivityService";
 
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false;
 
     private static final boolean LOGD_RULES = false;
@@ -353,6 +354,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
      */
     private static final int EVENT_REGISTER_NETWORK_LISTENER_WITH_INTENT = 31;
 
+    /**
+     * used to push APF program to NetworkAgent
+     * replyTo = NetworkAgent message handler
+     * obj = byte[] of APF program
+     */
+    private static final int EVENT_PUSH_APF_PROGRAM_TO_NETWORK = 32;
+
     /** Handler thread used for both of the handlers below. */
     @VisibleForTesting
     protected final HandlerThread mHandlerThread;
@@ -447,7 +455,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
      */
     private class LegacyTypeTracker {
 
-        private static final boolean DBG = true;
+        private static final boolean DBG = false;
         private static final boolean VDBG = false;
         private static final String TAG = "CSLegacyTypeTracker";
 
@@ -750,7 +758,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
         intentFilter.addAction(Intent.ACTION_USER_STOPPING);
         intentFilter.addAction(Intent.ACTION_USER_ADDED);
         intentFilter.addAction(Intent.ACTION_USER_REMOVED);
-        intentFilter.addAction(Intent.ACTION_USER_PRESENT);
+        intentFilter.addAction(Intent.ACTION_USER_UNLOCKED);
         mContext.registerReceiverAsUser(
                 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
 
@@ -2190,6 +2198,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
             mKeepaliveTracker.handleStopAllKeepalives(nai,
                     ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
             nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+            if (nai.apfFilter != null) nai.apfFilter.shutdown();
             mNetworkAgentInfos.remove(msg.replyTo);
             updateClat(null, nai.linkProperties, nai);
             synchronized (mNetworkForNetId) {
@@ -2404,6 +2413,13 @@ public class ConnectivityService extends IConnectivityManager.Stub
                 accept ? 1 : 0, always ? 1: 0, network));
     }
 
+    public void pushApfProgramToNetwork(NetworkAgentInfo nai, byte[] program) {
+        enforceConnectivityInternalPermission();
+        Message msg = mHandler.obtainMessage(EVENT_PUSH_APF_PROGRAM_TO_NETWORK, program);
+        msg.replyTo = nai.messenger;
+        mHandler.sendMessage(msg);
+    }
+
     private void handleSetAcceptUnvalidated(Network network, boolean accept, boolean always) {
         if (DBG) log("handleSetAcceptUnvalidated network=" + network +
                 " accept=" + accept + " always=" + always);
@@ -2553,6 +2569,16 @@ public class ConnectivityService extends IConnectivityManager.Stub
                     handleMobileDataAlwaysOn();
                     break;
                 }
+                case EVENT_PUSH_APF_PROGRAM_TO_NETWORK: {
+                    NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
+                    if (nai == null) {
+                        loge("EVENT_PUSH_APF_PROGRAM_TO_NETWORK from unknown NetworkAgent");
+                    } else {
+                         nai.asyncChannel.sendMessage(NetworkAgent.CMD_PUSH_APF_PROGRAM,
+                                 (byte[]) msg.obj);
+                    }
+                    break;
+                }
                 // Sent by KeepaliveTracker to process an app request on the state machine thread.
                 case NetworkAgent.CMD_START_PACKET_KEEPALIVE: {
                     mKeepaliveTracker.handleStartKeepalive(msg);
@@ -3633,7 +3659,7 @@ public class ConnectivityService extends IConnectivityManager.Stub
         }
     }
 
-    private void onUserPresent(int userId) {
+    private void onUserUnlocked(int userId) {
         // User present may be sent because of an unlock, which might mean an unlocked keystore.
         if (mUserManager.getUserInfo(userId).isPrimary() && LockdownVpnTracker.isEnabled()) {
             updateLockdownVpn();
@@ -3657,8 +3683,8 @@ public class ConnectivityService extends IConnectivityManager.Stub
                 onUserAdded(userId);
             } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 onUserRemoved(userId);
-            } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
-                onUserPresent(userId);
+            } else if (Intent.ACTION_USER_UNLOCKED.equals(action)) {
+                onUserUnlocked(userId);
             }
         }
     };
@@ -4068,6 +4094,9 @@ public class ConnectivityService extends IConnectivityManager.Stub
         if (networkAgent.clatd != null) {
             networkAgent.clatd.fixupLinkProperties(oldLp);
         }
+        if (networkAgent.apfFilter != null) {
+            networkAgent.apfFilter.updateFilter();
+        }
 
         updateInterfaces(newLp, oldLp, netId);
         updateMtu(newLp, oldLp);
index 63c9822..3b6c62b 100644 (file)
@@ -1960,14 +1960,6 @@ public class InputMethodManagerService extends IInputMethodManager.Stub
             throw new IllegalArgumentException("Unknown id: " + id);
         }
 
-        if (mCurClient != null && mCurAttribute != null) {
-            // We have already made sure that the package name belongs to the application's UID.
-            // No further UID check is required.
-            if (SystemConfig.getInstance().getFixedImeApps().contains(mCurAttribute.packageName)) {
-                return;
-            }
-        }
-
         // See if we need to notify a subtype change within the same IME.
         if (id.equals(mCurMethodId)) {
             final int subtypeCount = info.getSubtypeCount();
diff --git a/services/core/java/com/android/server/LockGuard.java b/services/core/java/com/android/server/LockGuard.java
new file mode 100644 (file)
index 0000000..3a381ae
--- /dev/null
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server;
+
+import android.util.ArrayMap;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * LockGuard is a mechanism to help detect lock inversions inside the system
+ * server. It works by requiring each lock acquisition site to follow this
+ * pattern:
+ *
+ * <pre>
+ * synchronized (LockGuard.guard(lock)) {
+ * }
+ * </pre>
+ *
+ * <pre>
+ * $ find services/ -name "*.java" -exec sed -i -r \
+ *     's/synchronized.?\((.+?)\)/synchronized \(com.android.server.LockGuard.guard\(\1\)\)/' {} \;
+ * </pre>
+ *
+ * The {@link #guard(Object)} method internally verifies that all locking is
+ * done in a consistent order, and will log if any inversion is detected. For
+ * example, if the calling thread is trying to acquire the
+ * {@code ActivityManager} lock while holding the {@code PackageManager} lock,
+ * it will yell.
+ * <p>
+ * This class requires no prior knowledge of locks or their ordering; it derives
+ * all of this data at runtime. However, this means the overhead is
+ * <em>substantial</em> and it should not be enabled by default. For example,
+ * here are some benchmarked timings:
+ * <ul>
+ * <li>An unguarded synchronized block takes 40ns.
+ * <li>A guarded synchronized block takes 50ns when disabled.
+ * <li>A guarded synchronized block takes 460ns per lock checked when enabled.
+ * </ul>
+ */
+public class LockGuard {
+    private static final String TAG = "LockGuard";
+
+    private static ArrayMap<Object, LockInfo> sKnown = new ArrayMap<>(0, true);
+
+    private static class LockInfo {
+        /** Friendly label to describe this lock */
+        public String label;
+
+        /** Child locks that can be acquired while this lock is already held */
+        public ArraySet<Object> children = new ArraySet<>(0, true);
+    }
+
+    private static LockInfo findOrCreateLockInfo(Object lock) {
+        LockInfo info = sKnown.get(lock);
+        if (info == null) {
+            info = new LockInfo();
+            info.label = "0x" + Integer.toHexString(System.identityHashCode(lock)) + " ["
+                    + new Throwable().getStackTrace()[2].toString() + "]";
+            sKnown.put(lock, info);
+        }
+        return info;
+    }
+
+    /**
+     * Check if the calling thread is holding any locks in an inverted order.
+     *
+     * @param lock The lock the calling thread is attempting to acquire.
+     */
+    public static Object guard(Object lock) {
+        // If we already hold this lock, ignore
+        if (lock == null || Thread.holdsLock(lock)) return lock;
+
+        // Check to see if we're already holding any child locks
+        boolean triggered = false;
+        final LockInfo info = findOrCreateLockInfo(lock);
+        for (int i = 0; i < info.children.size(); i++) {
+            final Object child = info.children.valueAt(i);
+            if (child == null) continue;
+
+            if (Thread.holdsLock(child)) {
+                Slog.w(TAG, "Calling thread " + Thread.currentThread().getName() + " is holding "
+                      + lockToString(child) + " while trying to acquire "
+                      + lockToString(lock), new Throwable());
+                triggered = true;
+            }
+        }
+
+        if (!triggered) {
+            // If no trouble found above, record this lock as being a valid
+            // child of all locks currently being held
+            for (int i = 0; i < sKnown.size(); i++) {
+                final Object test = sKnown.keyAt(i);
+                if (test == null || test == lock) continue;
+
+                if (Thread.holdsLock(test)) {
+                    sKnown.valueAt(i).children.add(lock);
+                }
+            }
+        }
+
+        return lock;
+    }
+
+    /**
+     * Report the given lock with a well-known label.
+     */
+    public static void installLock(Object lock, String label) {
+        final LockInfo info = findOrCreateLockInfo(lock);
+        info.label = label;
+    }
+
+    private static String lockToString(Object lock) {
+        final LockInfo info = sKnown.get(lock);
+        if (info != null) {
+            return info.label;
+        } else {
+            return "0x" + Integer.toHexString(System.identityHashCode(lock));
+        }
+    }
+
+    public static void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        for (int i = 0; i < sKnown.size(); i++) {
+            final Object lock = sKnown.keyAt(i);
+            final LockInfo info = sKnown.valueAt(i);
+            pw.println("Lock " + lockToString(lock) + ":");
+            for (int j = 0; j < info.children.size(); j++) {
+                pw.println("  Child " + lockToString(info.children.valueAt(j)));
+            }
+            pw.println();
+        }
+    }
+}
index c318140..6fb0671 100644 (file)
@@ -345,9 +345,9 @@ public class LockSettingsService extends ILockSettings.Stub {
                     final int userId = users.get(user).id;
                     final String OWNER_INFO = Secure.LOCK_SCREEN_OWNER_INFO;
                     String ownerInfo = Settings.Secure.getStringForUser(cr, OWNER_INFO, userId);
-                    if (ownerInfo != null) {
+                    if (!TextUtils.isEmpty(ownerInfo)) {
                         setString(OWNER_INFO, ownerInfo, userId);
-                        Settings.Secure.putStringForUser(cr, ownerInfo, "", userId);
+                        Settings.Secure.putStringForUser(cr, OWNER_INFO, "", userId);
                     }
 
                     // Migrate owner info enabled.  Note there was a bug where older platforms only
@@ -545,9 +545,23 @@ public class LockSettingsService extends ILockSettings.Stub {
         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
         final KeyStore ks = KeyStore.getInstance();
 
-        final List<UserInfo> profiles = um.getProfiles(userHandle);
-        for (UserInfo pi : profiles) {
-            ks.onUserPasswordChanged(pi.id, password);
+        if (um.getUserInfo(userHandle).isManagedProfile()) {
+            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
+                ks.onUserPasswordChanged(userHandle, password);
+            } else {
+                throw new RuntimeException("Can't set keystore password on a profile that "
+                        + "doesn't have a profile challenge.");
+            }
+        } else {
+            final List<UserInfo> profiles = um.getProfiles(userHandle);
+            for (UserInfo pi : profiles) {
+                // Change password on the given user and all its profiles that don't have
+                // their own profile challenge enabled.
+                if (pi.id == userHandle || (pi.isManagedProfile()
+                        && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id))) {
+                    ks.onUserPasswordChanged(pi.id, password);
+                }
+            }
         }
     }
 
@@ -555,9 +569,23 @@ public class LockSettingsService extends ILockSettings.Stub {
         final UserManager um = (UserManager) mContext.getSystemService(USER_SERVICE);
         final KeyStore ks = KeyStore.getInstance();
 
-        final List<UserInfo> profiles = um.getProfiles(userHandle);
-        for (UserInfo pi : profiles) {
-            ks.unlock(pi.id, password);
+        if (um.getUserInfo(userHandle).isManagedProfile()) {
+            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
+                ks.unlock(userHandle, password);
+            } else {
+                throw new RuntimeException("Can't unlock a profile explicitly if it "
+                        + "doesn't have a profile challenge.");
+            }
+        } else {
+            final List<UserInfo> profiles = um.getProfiles(userHandle);
+            for (UserInfo pi : profiles) {
+                // Unlock the given user and all its profiles that don't have
+                // their own profile challenge enabled.
+                if (pi.id == userHandle || (pi.isManagedProfile()
+                        && !mLockPatternUtils.isSeparateProfileChallengeEnabled(pi.id))) {
+                    ks.unlock(pi.id, password);
+                }
+            }
         }
     }
 
index 53923ba..a3322fc 100644 (file)
@@ -1945,11 +1945,16 @@ class MountService extends IMountService.Stub
                         "Emulation not available on device with native FBE");
             }
 
-            final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
-            SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
+            final long token = Binder.clearCallingIdentity();
+            try {
+                final boolean emulateFbe = (flags & StorageManager.DEBUG_EMULATE_FBE) != 0;
+                SystemProperties.set(StorageManager.PROP_EMULATE_FBE, Boolean.toString(emulateFbe));
 
-            // Perform hard reboot to kick policy into place
-            mContext.getSystemService(PowerManager.class).reboot(null);
+                // Perform hard reboot to kick policy into place
+                mContext.getSystemService(PowerManager.class).reboot(null);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
         }
 
         if ((mask & StorageManager.DEBUG_FORCE_ADOPTABLE) != 0) {
index 799d0bd..329f716 100644 (file)
@@ -22,8 +22,10 @@ import static android.Manifest.permission.SHUTDOWN;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_DOZABLE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_NONE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_POWERSAVE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NAME_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_NONE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
 import static android.net.NetworkPolicyManager.FIREWALL_TYPE_BLACKLIST;
@@ -43,7 +45,6 @@ import static com.android.server.NetworkManagementService.NetdResponseCode.Tethe
 import static com.android.server.NetworkManagementService.NetdResponseCode.TetheringStatsListResult;
 import static com.android.server.NetworkManagementService.NetdResponseCode.TtyListResult;
 import static com.android.server.NetworkManagementSocketTagger.PROP_QTAGUID_ENABLED;
-
 import android.annotation.NonNull;
 import android.app.ActivityManagerNative;
 import android.content.Context;
@@ -226,6 +227,12 @@ public class NetworkManagementService extends INetworkManagementService.Stub
      */
     @GuardedBy("mQuotaLock")
     private SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
+    /**
+     * Set of UIDs that are to be blocked/allowed by firewall controller.  This set of Ids matches
+     * to device on power-save mode.
+     */
+    @GuardedBy("mQuotaLock")
+    private SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
     /** Set of states for the child firewall chains. True if the chain is active. */
     @GuardedBy("mQuotaLock")
     final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -286,8 +293,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
         Watchdog.getInstance().addMonitor(this);
     }
 
-    static NetworkManagementService create(Context context,
-            String socket) throws InterruptedException {
+    static NetworkManagementService create(Context context, String socket)
+            throws InterruptedException {
         final NetworkManagementService service = new NetworkManagementService(context, socket);
         final CountDownLatch connectedSignal = service.mConnectedSignal;
         if (DBG) Slog.d(TAG, "Creating NetworkManagementService");
@@ -303,8 +310,15 @@ public class NetworkManagementService extends INetworkManagementService.Stub
     }
 
     public void systemReady() {
-        prepareNativeDaemon();
-        if (DBG) Slog.d(TAG, "Prepared");
+        if (DBG) {
+            final long start = System.currentTimeMillis();
+            prepareNativeDaemon();
+            final long delta = System.currentTimeMillis() - start;
+            Slog.d(TAG, "Prepared in " + delta + "ms");
+            return;
+        } else {
+            prepareNativeDaemon();
+        }
     }
 
     private IBatteryStats getBatteryStats() {
@@ -339,8 +353,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).interfaceStatusChanged(iface, up);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -358,8 +371,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).interfaceLinkStateChanged(iface, up);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -376,8 +388,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).interfaceAdded(iface);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -399,8 +410,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).interfaceRemoved(iface);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -417,8 +427,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).limitReached(limitName, iface);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -476,8 +485,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                     try {
                         mObservers.getBroadcastItem(i).interfaceClassDataActivityChanged(
                                 Integer.toString(type), isActive, tsNanos);
-                    } catch (RemoteException e) {
-                    } catch (RuntimeException e) {
+                    } catch (RemoteException | RuntimeException e) {
                     }
                 }
             } finally {
@@ -520,7 +528,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                 Log.wtf(TAG, "problem enabling bandwidth controls", e);
             }
         } else {
-            Slog.d(TAG, "not enabling bandwidth control");
+            Slog.i(TAG, "not enabling bandwidth control");
         }
 
         SystemProperties.set(PROP_QTAGUID_ENABLED, mBandwidthControlEnabled ? "1" : "0");
@@ -543,7 +551,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
         synchronized (mQuotaLock) {
             int size = mActiveQuotas.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active quota rules");
+                if (DBG) Slog.d(TAG, "Pushing " + size + " active quota rules");
                 final HashMap<String, Long> activeQuotas = mActiveQuotas;
                 mActiveQuotas = Maps.newHashMap();
                 for (Map.Entry<String, Long> entry : activeQuotas.entrySet()) {
@@ -553,7 +561,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
 
             size = mActiveAlerts.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active alert rules");
+                if (DBG) Slog.d(TAG, "Pushing " + size + " active alert rules");
                 final HashMap<String, Long> activeAlerts = mActiveAlerts;
                 mActiveAlerts = Maps.newHashMap();
                 for (Map.Entry<String, Long> entry : activeAlerts.entrySet()) {
@@ -563,7 +571,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
 
             size = mUidRejectOnQuota.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active UID rules");
+                if (DBG) Slog.d(TAG, "Pushing " + size + " active UID rules");
                 final SparseBooleanArray uidRejectOnQuota = mUidRejectOnQuota;
                 mUidRejectOnQuota = new SparseBooleanArray();
                 for (int i = 0; i < uidRejectOnQuota.size(); i++) {
@@ -573,7 +581,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
 
             size = mUidCleartextPolicy.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active UID cleartext policies");
+                if (DBG) Slog.d(TAG, "Pushing " + size + " active UID cleartext policies");
                 final SparseIntArray local = mUidCleartextPolicy;
                 mUidCleartextPolicy = new SparseIntArray();
                 for (int i = 0; i < local.size(); i++) {
@@ -585,7 +593,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
 
             size = mUidFirewallRules.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active firewall UID rules");
+                if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall UID rules");
                 final SparseIntArray uidFirewallRules = mUidFirewallRules;
                 mUidFirewallRules = new SparseIntArray();
                 for (int i = 0; i < uidFirewallRules.size(); i++) {
@@ -596,7 +604,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
 
             size = mUidFirewallStandbyRules.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active firewall standby UID rules");
+                if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall standby UID rules");
                 final SparseIntArray uidFirewallRules = mUidFirewallStandbyRules;
                 mUidFirewallStandbyRules = new SparseIntArray();
                 for (int i = 0; i < uidFirewallRules.size(); i++) {
@@ -610,7 +618,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
 
             size = mUidFirewallDozableRules.size();
             if (size > 0) {
-                Slog.d(TAG, "Pushing " + size + " active firewall dozable UID rules");
+                if (DBG) Slog.d(TAG, "Pushing " + size + " active firewall dozable UID rules");
                 final SparseIntArray uidFirewallRules = mUidFirewallDozableRules;
                 mUidFirewallDozableRules = new SparseIntArray();
                 for (int i = 0; i < uidFirewallRules.size(); i++) {
@@ -621,6 +629,20 @@ public class NetworkManagementService extends INetworkManagementService.Stub
             if (mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE)) {
                 setFirewallChainEnabled(FIREWALL_CHAIN_DOZABLE, true);
             }
+
+            size = mUidFirewallPowerSaveRules.size();
+            if (size > 0) {
+                Slog.d(TAG, "Pushing " + size + " active firewall powersave UID rules");
+                final SparseIntArray uidFirewallRules = mUidFirewallPowerSaveRules;
+                mUidFirewallPowerSaveRules = new SparseIntArray();
+                for (int i = 0; i < uidFirewallRules.size(); i++) {
+                    setFirewallUidRuleInternal(FIREWALL_CHAIN_POWERSAVE, uidFirewallRules.keyAt(i),
+                            uidFirewallRules.valueAt(i));
+                }
+            }
+            if (mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE)) {
+                setFirewallChainEnabled(FIREWALL_CHAIN_POWERSAVE, true);
+            }
         }
     }
 
@@ -633,8 +655,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).addressUpdated(iface, address);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -651,8 +672,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
             for (int i = 0; i < length; i++) {
                 try {
                     mObservers.getBroadcastItem(i).addressRemoved(iface, address);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -670,8 +690,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                 try {
                     mObservers.getBroadcastItem(i).interfaceDnsServerInfo(iface, lifetime,
                         addresses);
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -692,8 +711,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                     } else {
                         mObservers.getBroadcastItem(i).routeRemoved(route);
                     }
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -1210,7 +1228,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
         // TODO: remove from aidl if nobody calls externally
         mContext.enforceCallingOrSelfPermission(SHUTDOWN, TAG);
 
-        Slog.d(TAG, "Shutting down");
+        Slog.i(TAG, "Shutting down");
     }
 
     @Override
@@ -2023,6 +2041,9 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                     case FIREWALL_CHAIN_DOZABLE:
                         chainName = FIREWALL_CHAIN_NAME_DOZABLE;
                         break;
+                    case FIREWALL_CHAIN_POWERSAVE:
+                        chainName = FIREWALL_CHAIN_NAME_POWERSAVE;
+                        break;
                     default:
                         throw new IllegalArgumentException("Bad child chain: " + chain);
                 }
@@ -2039,6 +2060,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                 return FIREWALL_TYPE_BLACKLIST;
             case FIREWALL_CHAIN_DOZABLE:
                 return FIREWALL_TYPE_WHITELIST;
+            case FIREWALL_CHAIN_POWERSAVE:
+                return FIREWALL_TYPE_WHITELIST;
             default:
                 return isFirewallEnabled() ? FIREWALL_TYPE_WHITELIST : FIREWALL_TYPE_BLACKLIST;
         }
@@ -2138,6 +2161,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                 return mUidFirewallStandbyRules;
             case FIREWALL_CHAIN_DOZABLE:
                 return mUidFirewallDozableRules;
+            case FIREWALL_CHAIN_POWERSAVE:
+                return mUidFirewallPowerSaveRules;
             case FIREWALL_CHAIN_NONE:
                 return mUidFirewallRules;
             default:
@@ -2151,6 +2176,8 @@ public class NetworkManagementService extends INetworkManagementService.Stub
                 return FIREWALL_CHAIN_NAME_STANDBY;
             case FIREWALL_CHAIN_DOZABLE:
                 return FIREWALL_CHAIN_NAME_DOZABLE;
+            case FIREWALL_CHAIN_POWERSAVE:
+                return FIREWALL_CHAIN_NAME_POWERSAVE;
             case FIREWALL_CHAIN_NONE:
                 return FIREWALL_CHAIN_NAME_NONE;
             default:
@@ -2225,8 +2252,7 @@ public class NetworkManagementService extends INetworkManagementService.Stub
             for (int i = 0; i < length; i++) {
                 try {
                     mNetworkActivityListeners.getBroadcastItem(i).onNetworkActive();
-                } catch (RemoteException e) {
-                } catch (RuntimeException e) {
+                } catch (RemoteException | RuntimeException e) {
                 }
             }
         } finally {
@@ -2271,43 +2297,25 @@ public class NetworkManagementService extends INetworkManagementService.Stub
         }
 
         synchronized (mUidFirewallRules) {
-            pw.print("UID firewall rule: [");
-            final int size = mUidFirewallRules.size();
-            for (int i = 0; i < size; i++) {
-                pw.print(mUidFirewallRules.keyAt(i));
-                pw.print(":");
-                pw.print(mUidFirewallRules.valueAt(i));
-                if (i < size - 1) pw.print(",");
-            }
-            pw.println("]");
+            dumpUidFirewallRule(pw, "", mUidFirewallRules);
         }
 
         pw.println("UID firewall standby chain enabled: " +
                 mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY));
         synchronized (mUidFirewallStandbyRules) {
-            pw.print("UID firewall standby rule: [");
-            final int size = mUidFirewallStandbyRules.size();
-            for (int i = 0; i < size; i++) {
-                pw.print(mUidFirewallStandbyRules.keyAt(i));
-                pw.print(":");
-                pw.print(mUidFirewallStandbyRules.valueAt(i));
-                if (i < size - 1) pw.print(",");
-            }
-            pw.println("]");
+            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_STANDBY, mUidFirewallStandbyRules);
         }
 
         pw.println("UID firewall dozable chain enabled: " +
                 mFirewallChainStates.get(FIREWALL_CHAIN_DOZABLE));
         synchronized (mUidFirewallDozableRules) {
-            pw.print("UID firewall dozable rule: [");
-            final int size = mUidFirewallDozableRules.size();
-            for (int i = 0; i < size; i++) {
-                pw.print(mUidFirewallDozableRules.keyAt(i));
-                pw.print(":");
-                pw.print(mUidFirewallDozableRules.valueAt(i));
-                if (i < size - 1) pw.print(",");
-            }
-            pw.println("]");
+            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_DOZABLE, mUidFirewallDozableRules);
+        }
+
+        pw.println("UID firewall powersave chain enabled: " +
+                mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE));
+        synchronized (mUidFirewallPowerSaveRules) {
+            dumpUidFirewallRule(pw, FIREWALL_CHAIN_NAME_POWERSAVE, mUidFirewallPowerSaveRules);
         }
 
         synchronized (mIdleTimerLock) {
@@ -2324,6 +2332,20 @@ public class NetworkManagementService extends INetworkManagementService.Stub
         pw.print("Firewall enabled: "); pw.println(mFirewallEnabled);
     }
 
+    private void dumpUidFirewallRule(PrintWriter pw, String name, SparseIntArray rules) {
+        pw.print("UID firewall");
+        pw.print(name);
+        pw.print(" rule: [");
+        final int size = rules.size();
+        for (int i = 0; i < size; i++) {
+            pw.print(rules.keyAt(i));
+            pw.print(":");
+            pw.print(rules.valueAt(i));
+            if (i < size - 1) pw.print(",");
+        }
+        pw.println("]");
+    }
+
     @Override
     public void createPhysicalNetwork(int netId, String permission) {
         mContext.enforceCallingOrSelfPermission(CONNECTIVITY_INTERNAL, TAG);
index 3f0664d..b64c65d 100644 (file)
@@ -23,8 +23,10 @@ import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.net.ConnectivityManager;
+import android.os.Binder;
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
@@ -34,10 +36,14 @@ import android.os.PowerManager;
 import android.provider.Settings;
 import android.util.Log;
 import android.util.NtpTrustedTime;
+import android.util.TimeUtils;
 import android.util.TrustedTime;
 
 import com.android.internal.telephony.TelephonyIntents;
 
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
 /**
  * Monitors the network time and updates the system time if it is out of sync
  * and there hasn't been any NITZ update from the carrier recently.
@@ -48,7 +54,7 @@ import com.android.internal.telephony.TelephonyIntents;
  * available.
  * </p>
  */
-public class NetworkTimeUpdateService {
+public class NetworkTimeUpdateService extends Binder {
 
     private static final String TAG = "NetworkTimeUpdateService";
     private static final boolean DBG = false;
@@ -59,6 +65,8 @@ public class NetworkTimeUpdateService {
 
     private static final String ACTION_POLL =
             "com.android.server.NetworkTimeUpdateService.action.POLL";
+
+    private static final int NETWORK_CHANGE_EVENT_DELAY_MS = 1000;
     private static int POLL_REQUEST = 0;
 
     private static final long NOT_SET = -1;
@@ -245,6 +253,7 @@ public class NetworkTimeUpdateService {
         @Override
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
+            if (DBG) Log.d(TAG, "Received " + action);
             if (TelephonyIntents.ACTION_NETWORK_SET_TIME.equals(action)) {
                 mNitzTimeSetTime = SystemClock.elapsedRealtime();
             } else if (TelephonyIntents.ACTION_NETWORK_SET_TIMEZONE.equals(action)) {
@@ -260,8 +269,11 @@ public class NetworkTimeUpdateService {
         public void onReceive(Context context, Intent intent) {
             String action = intent.getAction();
             if (ConnectivityManager.CONNECTIVITY_ACTION.equals(action)) {
+                if (DBG) Log.d(TAG, "Received CONNECTIVITY_ACTION ");
                 // Don't bother checking if we have connectivity, NtpTrustedTime does that for us.
-                mHandler.obtainMessage(EVENT_NETWORK_CHANGED).sendToTarget();
+                Message message = mHandler.obtainMessage(EVENT_NETWORK_CHANGED);
+                // Send with a short delay to make sure the network is ready for use
+                mHandler.sendMessageDelayed(message, NETWORK_CHANGE_EVENT_DELAY_MS);
             }
         }
     };
@@ -308,4 +320,28 @@ public class NetworkTimeUpdateService {
             mHandler.obtainMessage(mMsg).sendToTarget();
         }
     }
+
+    @Override
+    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                != PackageManager.PERMISSION_GRANTED) {
+            pw.println("Permission Denial: can't dump NetworkTimeUpdateService from from pid="
+                    + Binder.getCallingPid()
+                    + ", uid=" + Binder.getCallingUid()
+                    + " without permission "
+                    + android.Manifest.permission.DUMP);
+            return;
+        }
+        pw.print("PollingIntervalMs: ");
+        TimeUtils.formatDuration(mPollingIntervalMs, pw);
+        pw.print("\nPollingIntervalShorterMs: ");
+        TimeUtils.formatDuration(mPollingIntervalShorterMs, pw);
+        pw.println("\nTryAgainTimesMax: " + mTryAgainTimesMax);
+        pw.print("TimeErrorThresholdMs: ");
+        TimeUtils.formatDuration(mTimeErrorThresholdMs, pw);
+        pw.println("\nTryAgainCounter: " + mTryAgainCounter);
+        pw.print("LastNtpFetchTime: ");
+        TimeUtils.formatDuration(mLastNtpFetchTime, pw);
+        pw.println();
+    }
 }
index f4c6225..11aef17 100644 (file)
@@ -58,7 +58,7 @@ public class NsdService extends INsdManager.Stub {
     private static final String TAG = "NsdService";
     private static final String MDNS_TAG = "mDnsConnector";
 
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     private Context mContext;
     private ContentResolver mContentResolver;
index d237fe7..d284d07 100644 (file)
@@ -17,6 +17,8 @@
 package com.android.server;
 
 import android.content.Context;
+import android.net.LocalSocket;
+import android.net.LocalSocketAddress;
 import android.os.IRecoverySystem;
 import android.os.IRecoverySystemProgressListener;
 import android.os.RecoverySystem;
@@ -26,9 +28,11 @@ import android.system.ErrnoException;
 import android.system.Os;
 import android.util.Slog;
 
-import java.io.BufferedReader;
+import libcore.io.IoUtils;
+
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
 import java.io.File;
-import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 
@@ -43,10 +47,10 @@ public final class RecoverySystemService extends SystemService {
     private static final String TAG = "RecoverySystemService";
     private static final boolean DEBUG = false;
 
-    // A pipe file to monitor the uncrypt progress.
-    private static final String UNCRYPT_STATUS_FILE = "/cache/recovery/uncrypt_status";
-    // Temporary command file to communicate between the system server and uncrypt.
-    private static final String COMMAND_FILE = "/cache/recovery/command";
+    // The socket at /dev/socket/uncrypt to communicate with uncrypt.
+    private static final String UNCRYPT_SOCKET = "uncrypt";
+
+    private static final int SOCKET_CONNECTION_MAX_RETRY = 30;
 
     private Context mContext;
 
@@ -79,60 +83,63 @@ public final class RecoverySystemService extends SystemService {
                 return false;
             }
 
-            // Create the status pipe file to communicate with uncrypt.
-            new File(UNCRYPT_STATUS_FILE).delete();
-            try {
-                Os.mkfifo(UNCRYPT_STATUS_FILE, 0600);
-            } catch (ErrnoException e) {
-                Slog.e(TAG, "ErrnoException when creating named pipe \"" + UNCRYPT_STATUS_FILE +
-                        "\": " + e.getMessage());
-                return false;
-            }
-
             // Trigger uncrypt via init.
             SystemProperties.set("ctl.start", "uncrypt");
 
-            // Read the status from the pipe.
-            try (BufferedReader reader = new BufferedReader(new FileReader(UNCRYPT_STATUS_FILE))) {
+            // Connect to the uncrypt service socket.
+            LocalSocket socket = connectService();
+            if (socket == null) {
+                Slog.e(TAG, "Failed to connect to uncrypt socket");
+                return false;
+            }
+
+            // Read the status from the socket.
+            try (DataInputStream dis = new DataInputStream(socket.getInputStream());
+                    DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) {
                 int lastStatus = Integer.MIN_VALUE;
                 while (true) {
-                    String str = reader.readLine();
-                    try {
-                        int status = Integer.parseInt(str);
-
-                        // Avoid flooding the log with the same message.
-                        if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
-                            continue;
-                        }
-                        lastStatus = status;
-
-                        if (status >= 0 && status <= 100) {
-                            // Update status
-                            Slog.i(TAG, "uncrypt read status: " + status);
-                            if (listener != null) {
-                                try {
-                                    listener.onProgress(status);
-                                } catch (RemoteException unused) {
-                                    Slog.w(TAG, "RemoteException when posting progress");
-                                }
-                            }
-                            if (status == 100) {
-                                Slog.i(TAG, "uncrypt successfully finished.");
-                                break;
+                    int status = dis.readInt();
+                    // Avoid flooding the log with the same message.
+                    if (status == lastStatus && lastStatus != Integer.MIN_VALUE) {
+                        continue;
+                    }
+                    lastStatus = status;
+
+                    if (status >= 0 && status <= 100) {
+                        // Update status
+                        Slog.i(TAG, "uncrypt read status: " + status);
+                        if (listener != null) {
+                            try {
+                                listener.onProgress(status);
+                            } catch (RemoteException unused) {
+                                Slog.w(TAG, "RemoteException when posting progress");
                             }
-                        } else {
-                            // Error in /system/bin/uncrypt.
-                            Slog.e(TAG, "uncrypt failed with status: " + status);
-                            return false;
                         }
-                    } catch (NumberFormatException unused) {
-                        Slog.e(TAG, "uncrypt invalid status received: " + str);
+                        if (status == 100) {
+                            Slog.i(TAG, "uncrypt successfully finished.");
+                            // Ack receipt of the final status code. uncrypt
+                            // waits for the ack so the socket won't be
+                            // destroyed before we receive the code.
+                            dos.writeInt(0);
+                            dos.flush();
+                            break;
+                        }
+                    } else {
+                        // Error in /system/bin/uncrypt.
+                        Slog.e(TAG, "uncrypt failed with status: " + status);
+                        // Ack receipt of the final status code. uncrypt waits
+                        // for the ack so the socket won't be destroyed before
+                        // we receive the code.
+                        dos.writeInt(0);
+                        dos.flush();
                         return false;
                     }
                 }
-            } catch (IOException unused) {
-                Slog.e(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\".");
+            } catch (IOException e) {
+                Slog.e(TAG, "IOException when reading status: " + e);
                 return false;
+            } finally {
+                IoUtils.closeQuietly(socket);
             }
 
             return true;
@@ -150,29 +157,35 @@ public final class RecoverySystemService extends SystemService {
             return setupOrClearBcb(true, command);
         }
 
-        private boolean setupOrClearBcb(boolean isSetup, String command) {
-            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
-
-            if (isSetup) {
-                // Set up the command file to be read by uncrypt.
-                try (FileWriter commandFile = new FileWriter(COMMAND_FILE)) {
-                    commandFile.write(command + "\n");
-                } catch (IOException e) {
-                    Slog.e(TAG, "IOException when writing \"" + COMMAND_FILE +
-                            "\": " + e.getMessage());
-                    return false;
+        private LocalSocket connectService() {
+            LocalSocket socket = new LocalSocket();
+            boolean done = false;
+            // The uncrypt socket will be created by init upon receiving the
+            // service request. It may not be ready by this point. So we will
+            // keep retrying until success or reaching timeout.
+            for (int retry = 0; retry < SOCKET_CONNECTION_MAX_RETRY; retry++) {
+                try {
+                    socket.connect(new LocalSocketAddress(UNCRYPT_SOCKET,
+                            LocalSocketAddress.Namespace.RESERVED));
+                    done = true;
+                    break;
+                } catch (IOException unused) {
+                    try {
+                        Thread.sleep(1000);
+                    } catch (InterruptedException e) {
+                        Slog.w(TAG, "Interrupted: " + e);
+                    }
                 }
             }
-
-            // Create the status pipe file to communicate with uncrypt.
-            new File(UNCRYPT_STATUS_FILE).delete();
-            try {
-                Os.mkfifo(UNCRYPT_STATUS_FILE, 0600);
-            } catch (ErrnoException e) {
-                Slog.e(TAG, "ErrnoException when creating named pipe \"" +
-                        UNCRYPT_STATUS_FILE + "\": " + e.getMessage());
-                return false;
+            if (!done) {
+                Slog.e(TAG, "Timed out connecting to uncrypt socket");
+                return null;
             }
+            return socket;
+        }
+
+        private boolean setupOrClearBcb(boolean isSetup, String command) {
+            mContext.enforceCallingOrSelfPermission(android.Manifest.permission.RECOVERY, null);
 
             if (isSetup) {
                 SystemProperties.set("ctl.start", "setup-bcb");
@@ -180,34 +193,45 @@ public final class RecoverySystemService extends SystemService {
                 SystemProperties.set("ctl.start", "clear-bcb");
             }
 
-            // Read the status from the pipe.
-            try (BufferedReader reader = new BufferedReader(new FileReader(UNCRYPT_STATUS_FILE))) {
-                while (true) {
-                    String str = reader.readLine();
-                    try {
-                        int status = Integer.parseInt(str);
+            // Connect to the uncrypt service socket.
+            LocalSocket socket = connectService();
+            if (socket == null) {
+                Slog.e(TAG, "Failed to connect to uncrypt socket");
+                return false;
+            }
 
-                        if (status == 100) {
-                            Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") +
-                                    " bcb successfully finished.");
-                            break;
-                        } else {
-                            // Error in /system/bin/uncrypt.
-                            Slog.e(TAG, "uncrypt failed with status: " + status);
-                            return false;
-                        }
-                    } catch (NumberFormatException unused) {
-                        Slog.e(TAG, "uncrypt invalid status received: " + str);
-                        return false;
-                    }
+            try (DataInputStream dis = new DataInputStream(socket.getInputStream());
+                    DataOutputStream dos = new DataOutputStream(socket.getOutputStream())) {
+                // Send the BCB commands if it's to setup BCB.
+                if (isSetup) {
+                    dos.writeInt(command.length());
+                    dos.writeBytes(command);
+                    dos.flush();
                 }
-            } catch (IOException unused) {
-                Slog.e(TAG, "IOException when reading \"" + UNCRYPT_STATUS_FILE + "\".");
+
+                // Read the status from the socket.
+                int status = dis.readInt();
+
+                // Ack receipt of the status code. uncrypt waits for the ack so
+                // the socket won't be destroyed before we receive the code.
+                dos.writeInt(0);
+                dos.flush();
+
+                if (status == 100) {
+                    Slog.i(TAG, "uncrypt " + (isSetup ? "setup" : "clear") +
+                            " bcb successfully finished.");
+                } else {
+                    // Error in /system/bin/uncrypt.
+                    Slog.e(TAG, "uncrypt failed with status: " + status);
+                    return false;
+                }
+            } catch (IOException e) {
+                Slog.e(TAG, "IOException when getting output stream: " + e);
                 return false;
+            } finally {
+                IoUtils.closeQuietly(socket);
             }
 
-            // Delete the command file as we don't need it anymore.
-            new File(COMMAND_FILE).delete();
             return true;
         }
     }
index 1c1784e..73d8bdd 100644 (file)
@@ -105,9 +105,6 @@ public class SystemConfig {
     // background while in data-usage save mode, as read from the configuration files.
     final ArraySet<String> mAllowInDataUsageSave = new ArraySet<>();
 
-    // These are the app package names that should not allow IME switching.
-    final ArraySet<String> mFixedImeApps = new ArraySet<>();
-
     // These are the package names of apps which should be in the 'always'
     // URL-handling state upon factory reset.
     final ArraySet<String> mLinkedApps = new ArraySet<>();
@@ -159,10 +156,6 @@ public class SystemConfig {
         return mAllowInDataUsageSave;
     }
 
-    public ArraySet<String> getFixedImeApps() {
-        return mFixedImeApps;
-    }
-
     public ArraySet<String> getLinkedApps() {
         return mLinkedApps;
     }
@@ -411,17 +404,6 @@ public class SystemConfig {
                     XmlUtils.skipCurrentTag(parser);
                     continue;
 
-                } else if ("fixed-ime-app".equals(name) && allowAll) {
-                    String pkgname = parser.getAttributeValue(null, "package");
-                    if (pkgname == null) {
-                        Slog.w(TAG, "<fixed-ime-app> without package in " + permFile + " at "
-                                + parser.getPositionDescription());
-                    } else {
-                        mFixedImeApps.add(pkgname);
-                    }
-                    XmlUtils.skipCurrentTag(parser);
-                    continue;
-
                 } else if ("app-link".equals(name) && allowAppConfigs) {
                     String pkgname = parser.getAttributeValue(null, "package");
                     if (pkgname == null) {
index 8c0ec78..63a0e87 100755 (executable)
@@ -319,7 +319,7 @@ public final class ActiveServices {
                         + " (pid=" + Binder.getCallingPid()
                         + ") when starting service " + service);
             }
-            callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+            callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
         } else {
             callerFg = true;
         }
@@ -831,7 +831,7 @@ public final class ActiveServices {
                     "BIND_TREAT_LIKE_ACTIVITY");
         }
 
-        final boolean callerFg = callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE;
+        final boolean callerFg = callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND;
         final boolean isBindExternal = (flags & Context.BIND_EXTERNAL_SERVICE) != 0;
 
         ServiceLookupResult res =
@@ -1138,7 +1138,7 @@ public final class ActiveServices {
                         for (int i=b.apps.size()-1; i>=0; i--) {
                             ProcessRecord client = b.apps.valueAt(i).client;
                             if (client != null && client.setSchedGroup
-                                    != Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+                                    != ProcessList.SCHED_GROUP_BACKGROUND) {
                                 inFg = true;
                                 break;
                             }
index 4f0d4d9..f2bf4f9 100644 (file)
@@ -46,6 +46,7 @@ class ActivityManagerDebugConfig {
 
     // Available log categories in the activity manager package.
     static final boolean DEBUG_ADD_REMOVE = DEBUG_ALL_ACTIVITIES || false;
+    static final boolean DEBUG_ANR = false;
     static final boolean DEBUG_APP = DEBUG_ALL_ACTIVITIES || false;
     static final boolean DEBUG_BACKUP = DEBUG_ALL || false;
     static final boolean DEBUG_BROADCAST = DEBUG_ALL || false;
index 5f40e5c..037ec59 100644 (file)
@@ -45,6 +45,7 @@ import com.android.server.AttributeCache;
 import com.android.server.DeviceIdleController;
 import com.android.server.IntentResolver;
 import com.android.server.LocalServices;
+import com.android.server.LockGuard;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
 import com.android.server.SystemServiceManager;
@@ -100,6 +101,8 @@ import android.app.NotificationManager;
 import android.app.PendingIntent;
 import android.app.ProfilerInfo;
 import android.app.admin.DevicePolicyManager;
+import android.app.admin.DevicePolicyManagerInternal;
+import android.app.admin.IDevicePolicyManager;
 import android.app.assist.AssistContent;
 import android.app.assist.AssistStructure;
 import android.app.backup.IBackupManager;
@@ -283,6 +286,7 @@ import static com.android.internal.util.XmlUtils.writeBooleanAttribute;
 import static com.android.internal.util.XmlUtils.writeIntAttribute;
 import static com.android.internal.util.XmlUtils.writeLongAttribute;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BACKUP;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_BROADCAST_BACKGROUND;
@@ -1293,10 +1297,12 @@ public final class ActivityManagerService extends ActivityManagerNative
     boolean mAlwaysFinishActivities = false;
     boolean mLenientBackgroundCheck = false;
     boolean mForceResizableActivities;
+    boolean mSupportsMultiWindow;
     boolean mSupportsFreeformWindowManagement;
     boolean mSupportsPictureInPicture;
     Rect mDefaultPinnedStackBounds;
     IActivityController mController = null;
+    boolean mControllerIsAMonkey = false;
     String mProfileApp = null;
     ProcessRecord mProfileProc = null;
     String mProfileFile;
@@ -1894,6 +1900,9 @@ public final class ActivityManagerService extends ActivityManagerNative
                 final int userId = msg.arg1;
                 mSystemServiceManager.unlockUser(userId);
                 mRecentTasks.loadUserRecentsLocked(userId);
+                if (userId == UserHandle.USER_SYSTEM) {
+                    startPersistentApps(PackageManager.MATCH_ENCRYPTION_UNAWARE);
+                }
                 installEncryptionUnawareProviders(userId);
                 break;
             }
@@ -5085,8 +5094,13 @@ public final class ActivityManagerService extends ActivityManagerNative
                     int num = firstPids.size();
                     for (int i = 0; i < num; i++) {
                         synchronized (observer) {
+                            if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for pid "
+                                    + firstPids.get(i));
+                            final long sime = SystemClock.elapsedRealtime();
                             Process.sendSignal(firstPids.get(i), Process.SIGNAL_QUIT);
-                            observer.wait(200);  // Wait for write-close, give up after 200msec
+                            observer.wait(1000);  // Wait for write-close, give up after 1 sec
+                            if (DEBUG_ANR) Slog.d(TAG, "Done with pid " + firstPids.get(i)
+                                    + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
                         }
                     }
                 } catch (InterruptedException e) {
@@ -5099,7 +5113,11 @@ public final class ActivityManagerService extends ActivityManagerNative
                 int[] pids = Process.getPidsForCommands(nativeProcs);
                 if (pids != null) {
                     for (int pid : pids) {
+                        if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for native pid " + pid);
+                        final long sime = SystemClock.elapsedRealtime();
                         Debug.dumpNativeBacktraceToFile(pid, tracesPath);
+                        if (DEBUG_ANR) Slog.d(TAG, "Done with native pid " + pid
+                                + " in " + (SystemClock.elapsedRealtime()-sime) + "ms");
                     }
                 }
             }
@@ -5126,13 +5144,20 @@ public final class ActivityManagerService extends ActivityManagerNative
                         numProcs++;
                         try {
                             synchronized (observer) {
+                                if (DEBUG_ANR) Slog.d(TAG, "Collecting stacks for extra pid "
+                                        + stats.pid);
+                                final long stime = SystemClock.elapsedRealtime();
                                 Process.sendSignal(stats.pid, Process.SIGNAL_QUIT);
-                                observer.wait(200);  // Wait for write-close, give up after 200msec
+                                observer.wait(1000);  // Wait for write-close, give up after 1 sec
+                                if (DEBUG_ANR) Slog.d(TAG, "Done with extra pid " + stats.pid
+                                        + " in " + (SystemClock.elapsedRealtime()-stime) + "ms");
                             }
                         } catch (InterruptedException e) {
                             Slog.wtf(TAG, e);
                         }
-
+                    } else if (DEBUG_ANR) {
+                        Slog.d(TAG, "Skipping next CPU consuming process, not a java proc: "
+                                + stats.pid);
                     }
                 }
             }
@@ -5238,9 +5263,13 @@ public final class ActivityManagerService extends ActivityManagerNative
     public boolean clearApplicationUserData(final String packageName,
             final IPackageDataObserver observer, int userId) {
         enforceNotIsolatedCaller("clearApplicationUserData");
-        if (packageName != null && packageName.equals(mDeviceOwnerName)) {
-            throw new SecurityException("Clearing DeviceOwner data is forbidden.");
+
+        final DevicePolicyManagerInternal dpmi = LocalServices
+                .getService(DevicePolicyManagerInternal.class);
+        if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+            throw new SecurityException("Cannot clear data for a device owner or a profile owner");
         }
+
         int uid = Binder.getCallingUid();
         int pid = Binder.getCallingPid();
         userId = mUserController.handleIncomingUser(pid, uid, userId, false,
@@ -5354,17 +5383,6 @@ public final class ActivityManagerService extends ActivityManagerNative
 
     @Override
     public void killAllBackgroundProcesses() {
-        killAllBackgroundProcesses(-1);
-    }
-
-    /**
-     * Kills all background processes with targetSdkVersion below the specified
-     * target SDK version.
-     *
-     * @param targetSdkVersion the target SDK version below which to kill
-     *                         processes, or {@code -1} to kill all processes
-     */
-    private void killAllBackgroundProcesses(int targetSdkVersion) {
         if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
                 != PackageManager.PERMISSION_GRANTED) {
             final String msg = "Permission Denial: killAllBackgroundProcesses() from pid="
@@ -5388,10 +5406,6 @@ public final class ActivityManagerService extends ActivityManagerNative
                             // We don't kill persistent processes.
                             continue;
                         }
-                        if (targetSdkVersion > 0
-                                && app.info.targetSdkVersion >= targetSdkVersion) {
-                            continue;
-                        }
                         if (app.removed) {
                             procs.add(app);
                         } else if (app.setAdj >= ProcessList.CACHED_APP_MIN_ADJ) {
@@ -5416,6 +5430,55 @@ public final class ActivityManagerService extends ActivityManagerNative
         }
     }
 
+    /**
+     * Kills all background processes, except those matching any of the
+     * specified properties.
+     *
+     * @param minTargetSdk the target SDK version at or above which to preserve
+     *                     processes, or {@code -1} to ignore the target SDK
+     * @param maxProcState the process state at or below which to preserve
+     *                     processes, or {@code -1} to ignore the process state
+     */
+    private void killAllBackgroundProcessesExcept(int minTargetSdk, int maxProcState) {
+        if (checkCallingPermission(android.Manifest.permission.KILL_BACKGROUND_PROCESSES)
+                != PackageManager.PERMISSION_GRANTED) {
+            final String msg = "Permission Denial: killAllBackgroundProcessesExcept() from pid="
+                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
+                    + " requires " + android.Manifest.permission.KILL_BACKGROUND_PROCESSES;
+            Slog.w(TAG, msg);
+            throw new SecurityException(msg);
+        }
+
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                final ArrayList<ProcessRecord> procs = new ArrayList<>();
+                final int NP = mProcessNames.getMap().size();
+                for (int ip = 0; ip < NP; ip++) {
+                    final SparseArray<ProcessRecord> apps = mProcessNames.getMap().valueAt(ip);
+                    final int NA = apps.size();
+                    for (int ia = 0; ia < NA; ia++) {
+                        final ProcessRecord app = apps.valueAt(ia);
+                        if (app.removed) {
+                            procs.add(app);
+                        } else if ((minTargetSdk < 0 || app.info.targetSdkVersion < minTargetSdk)
+                                && (maxProcState < 0 || app.setProcState > maxProcState)) {
+                            app.removed = true;
+                            procs.add(app);
+                        }
+                    }
+                }
+
+                final int N = procs.size();
+                for (int i = 0; i < N; i++) {
+                    removeProcessLocked(procs.get(i), false, true, "kill all background except");
+                }
+            }
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
     @Override
     public void forceStopPackage(final String packageName, int userId) {
         if (checkCallingPermission(android.Manifest.permission.FORCE_STOP_PACKAGES)
@@ -6172,7 +6235,7 @@ public final class ActivityManagerService extends ActivityManagerNative
 
         app.makeActive(thread, mProcessStats);
         app.curAdj = app.setAdj = ProcessList.INVALID_ADJ;
-        app.curSchedGroup = app.setSchedGroup = Process.THREAD_GROUP_DEFAULT;
+        app.curSchedGroup = app.setSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
         app.forcingToForeground = null;
         updateProcessForegroundLocked(app, false, false);
         app.hasShownUi = false;
@@ -6230,9 +6293,10 @@ public final class ActivityManagerService extends ActivityManagerNative
             // If the app is being launched for restore or full backup, set it up specially
             boolean isRestrictedBackupMode = false;
             if (mBackupTarget != null && mBackupAppName.equals(processName)) {
-                isRestrictedBackupMode = (mBackupTarget.backupMode == BackupRecord.RESTORE)
-                        || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
-                        || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL);
+                isRestrictedBackupMode = mBackupTarget.appInfo.uid >= Process.FIRST_APPLICATION_UID
+                        && ((mBackupTarget.backupMode == BackupRecord.RESTORE)
+                                || (mBackupTarget.backupMode == BackupRecord.RESTORE_FULL)
+                                || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
             }
 
             notifyPackageUse(app.instrumentationInfo != null
@@ -6983,6 +7047,8 @@ public final class ActivityManagerService extends ActivityManagerNative
 
     @Override
     public Intent getIntentForIntentSender(IIntentSender pendingResult) {
+        enforceCallingPermission(Manifest.permission.GET_INTENT_SENDER_INTENT,
+                "getIntentForIntentSender()");
         if (!(pendingResult instanceof PendingIntentRecord)) {
             return null;
         }
@@ -9161,7 +9227,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         // Kill the running processes.
         for (int i = 0; i < procsToKill.size(); i++) {
             ProcessRecord pr = procsToKill.get(i);
-            if (pr.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+            if (pr.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                     && pr.curReceiver == null) {
                 pr.kill("remove task", true);
             } else {
@@ -9486,7 +9552,7 @@ public final class ActivityManagerService extends ActivityManagerNative
      *                      docked stack. Pass {@code null} to use default bounds.
      */
     @Override
-    public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
+    public boolean moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()");
         synchronized (this) {
@@ -9495,7 +9561,8 @@ public final class ActivityManagerService extends ActivityManagerNative
                 if (DEBUG_STACK) Slog.d(TAG_STACK, "moveTaskToDockedStack: moving task=" + taskId
                         + " to createMode=" + createMode + " toTop=" + toTop);
                 mWindowManager.setDockedStackCreateState(createMode, initialBounds);
-                mStackSupervisor.moveTaskToStackLocked(taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS,
+                return mStackSupervisor.moveTaskToStackLocked(
+                        taskId, DOCKED_STACK_ID, toTop, !FORCE_FOCUS,
                         "moveTaskToDockedStack", animate);
             } finally {
                 Binder.restoreCallingIdentity(ident);
@@ -9574,6 +9641,20 @@ public final class ActivityManagerService extends ActivityManagerNative
     }
 
     @Override
+    public void resizePinnedStack(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "resizePinnedStack()");
+        final long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                mStackSupervisor.resizePinnedStackLocked(pinnedBounds, tempPinnedTaskBounds);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
     public void positionTaskInStack(int taskId, int stackId, int position) {
         enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
         if (stackId == HOME_STACK_ID) {
@@ -10421,7 +10502,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 cpi.packageName, r.userId)) {
 
             final boolean callerForeground = r != null ? r.setSchedGroup
-                    != Process.THREAD_GROUP_BG_NONINTERACTIVE : true;
+                    != ProcessList.SCHED_GROUP_BACKGROUND : true;
 
             // Show a permission review UI only for starting from a foreground app
             if (!callerForeground) {
@@ -10741,12 +10822,13 @@ public final class ActivityManagerService extends ActivityManagerNative
             return;
         }
 
-        final long token = Binder.clearCallingIdentity();
-        try {
-            mAppErrors.appNotResponding(host, null, null, false, "ContentProvider not responding");
-        } finally {
-            Binder.restoreCallingIdentity(token);
-        }
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                mAppErrors.appNotResponding(host, null, null, false,
+                        "ContentProvider not responding");
+            }
+        });
     }
 
     public final void installSystemProviders() {
@@ -10775,6 +10857,23 @@ public final class ActivityManagerService extends ActivityManagerNative
         //mUsageStatsService.monitorPackages();
     }
 
+    private void startPersistentApps(int matchFlags) {
+        if (mFactoryTest == FactoryTest.FACTORY_TEST_LOW_LEVEL) return;
+
+        synchronized (this) {
+            try {
+                final List<ApplicationInfo> apps = AppGlobals.getPackageManager()
+                        .getPersistentApplications(STOCK_PM_FLAGS | matchFlags);
+                for (ApplicationInfo app : apps) {
+                    if (!"android".equals(app.packageName)) {
+                        addAppLocked(app, false, null /* ABI override */);
+                    }
+                }
+            } catch (RemoteException ex) {
+            }
+        }
+    }
+
     /**
      * When a user is unlocked, we need to install encryption-unaware providers
      * belonging to any running apps.
@@ -10791,8 +10890,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         // We're only interested in providers that are encryption unaware, and
         // we don't care about uninstalled apps, since there's no way they're
         // running at this point.
-        final int matchFlags = GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE
-                | MATCH_DEBUG_TRIAGED_MISSING;
+        final int matchFlags = GET_PROVIDERS | MATCH_ENCRYPTION_UNAWARE;
 
         synchronized (this) {
             final int NP = mProcessNames.getMap().size();
@@ -11423,11 +11521,12 @@ public final class ActivityManagerService extends ActivityManagerNative
     }
 
     @Override
-    public void setActivityController(IActivityController controller) {
+    public void setActivityController(IActivityController controller, boolean imAMonkey) {
         enforceCallingPermission(android.Manifest.permission.SET_ACTIVITY_WATCHER,
                 "setActivityController()");
         synchronized (this) {
             mController = controller;
+            mControllerIsAMonkey = imAMonkey;
             Watchdog.getInstance().setActivityController(controller);
         }
     }
@@ -11454,7 +11553,7 @@ public final class ActivityManagerService extends ActivityManagerNative
     public boolean isUserAMonkey() {
         synchronized (this) {
             // If there is a controller also implies the user is a monkey.
-            return (mUserIsMonkey || mController != null);
+            return (mUserIsMonkey || (mController != null && mControllerIsAMonkey));
         }
     }
 
@@ -12312,6 +12411,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         final boolean supportsPictureInPicture =
                 mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
 
+        final boolean supportsMultiWindow = ActivityManager.supportsMultiWindow();
         final String debugApp = Settings.Global.getString(resolver, DEBUG_APP);
         final boolean waitForDebugger = Settings.Global.getInt(resolver, WAIT_FOR_DEBUGGER, 0) != 0;
         final boolean alwaysFinishActivities =
@@ -12338,8 +12438,15 @@ public final class ActivityManagerService extends ActivityManagerNative
             mLenientBackgroundCheck = lenientBackgroundCheck;
             mForceResizableActivities = forceResizable;
             mWindowManager.setForceResizableTasks(mForceResizableActivities);
-            mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
-            mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
+            if (supportsMultiWindow || forceResizable) {
+                mSupportsMultiWindow = true;
+                mSupportsFreeformWindowManagement = freeformWindowManagement || forceResizable;
+                mSupportsPictureInPicture = supportsPictureInPicture || forceResizable;
+            } else {
+                mSupportsMultiWindow = false;
+                mSupportsFreeformWindowManagement = false;
+                mSupportsPictureInPicture = false;
+            }
             // This happens before any activities are started, so we can
             // change mConfiguration in-place.
             updateConfigurationLocked(configuration, null, true);
@@ -12677,26 +12784,9 @@ public final class ActivityManagerService extends ActivityManagerNative
         mSystemServiceManager.startUser(currentUserId);
 
         synchronized (this) {
-            if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
-                try {
-                    List apps = AppGlobals.getPackageManager().
-                        getPersistentApplications(STOCK_PM_FLAGS);
-                    if (apps != null) {
-                        int N = apps.size();
-                        int i;
-                        for (i=0; i<N; i++) {
-                            ApplicationInfo info
-                                = (ApplicationInfo)apps.get(i);
-                            if (info != null &&
-                                    !info.packageName.equals("android")) {
-                                addAppLocked(info, false, null /* ABI override */);
-                            }
-                        }
-                    }
-                } catch (RemoteException ex) {
-                    // pm is in same process, this will never happen.
-                }
-            }
+            // Only start up encryption-aware persistent apps; once user is
+            // unlocked we'll come back around and start unaware apps
+            startPersistentApps(PackageManager.MATCH_ENCRYPTION_AWARE);
 
             // Start up initial activity.
             mBooting = true;
@@ -13581,6 +13671,8 @@ public final class ActivityManagerService extends ActivityManagerNative
                 synchronized (this) {
                     mServices.dumpServicesLocked(fd, pw, args, opti, true, dumpClient, dumpPackage);
                 }
+            } else if ("locks".equals(cmd)) {
+                LockGuard.dump(fd, pw, args);
             } else {
                 // Dumping a single activity?
                 if (!dumpActivity(fd, pw, cmd, args, opti, dumpAll)) {
@@ -14123,10 +14215,13 @@ public final class ActivityManagerService extends ActivityManagerNative
             }
         }
         if (dumpPackage == null) {
-            if (mAlwaysFinishActivities || mLenientBackgroundCheck || mController != null) {
+            if (mAlwaysFinishActivities || mLenientBackgroundCheck) {
                 pw.println("  mAlwaysFinishActivities=" + mAlwaysFinishActivities
-                        + " mLenientBackgroundCheck=" + mLenientBackgroundCheck
-                        + " mController=" + mController);
+                        + " mLenientBackgroundCheck=" + mLenientBackgroundCheck);
+            }
+            if (mController != null) {
+                pw.println("  mController=" + mController
+                        + " mControllerIsAMonkey=" + mControllerIsAMonkey);
             }
             if (dumpAll) {
                 pw.println("  Total persistent processes: " + numPers);
@@ -14724,13 +14819,13 @@ public final class ActivityManagerService extends ActivityManagerNative
             String oomAdj = ProcessList.makeOomAdjString(r.setAdj);
             char schedGroup;
             switch (r.setSchedGroup) {
-                case Process.THREAD_GROUP_BG_NONINTERACTIVE:
+                case ProcessList.SCHED_GROUP_BACKGROUND:
                     schedGroup = 'B';
                     break;
-                case Process.THREAD_GROUP_DEFAULT:
+                case ProcessList.SCHED_GROUP_DEFAULT:
                     schedGroup = 'F';
                     break;
-                case Process.THREAD_GROUP_TOP_APP:
+                case ProcessList.SCHED_GROUP_TOP_APP:
                     schedGroup = 'T';
                     break;
                 default:
@@ -15150,6 +15245,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         boolean dumpFullDetails = false;
         boolean dumpDalvik = false;
         boolean dumpSummaryOnly = false;
+        boolean dumpUnreachable = false;
         boolean oomOnly = false;
         boolean isCompact = false;
         boolean localOnly = false;
@@ -15178,6 +15274,8 @@ public final class ActivityManagerService extends ActivityManagerNative
                 dumpSummaryOnly = true;
             } else if ("-S".equals(opt)) {
                 dumpSwapPss = true;
+            } else if ("--unreachable".equals(opt)) {
+                dumpUnreachable = true;
             } else if ("--oom".equals(opt)) {
                 oomOnly = true;
             } else if ("--local".equals(opt)) {
@@ -15339,7 +15437,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                         try {
                             pw.flush();
                             thread.dumpMemInfo(fd, mi, isCheckinRequest, dumpFullDetails,
-                                    dumpDalvik, dumpSummaryOnly, innerArgs);
+                                    dumpDalvik, dumpSummaryOnly, dumpUnreachable, innerArgs);
                         } catch (RemoteException e) {
                             if (!isCheckinRequest) {
                                 pw.println("Got RemoteException!");
@@ -17135,10 +17233,11 @@ public final class ActivityManagerService extends ActivityManagerNative
                             String ssp;
                             if (data != null && (ssp=data.getSchemeSpecificPart()) != null) {
                                 boolean removed = Intent.ACTION_PACKAGE_REMOVED.equals(action);
-                                boolean fullUninstall = removed &&
-                                        !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
+                                final boolean replacing =
+                                        intent.getBooleanExtra(Intent.EXTRA_REPLACING, false);
                                 final boolean killProcess =
                                         !intent.getBooleanExtra(Intent.EXTRA_DONT_KILL_APP, false);
+                                final boolean fullUninstall = removed && !replacing;
                                 if (killProcess) {
                                     forceStopPackageLocked(ssp, UserHandle.getAppId(
                                             intent.getIntExtra(Intent.EXTRA_UID, -1)),
@@ -17146,7 +17245,10 @@ public final class ActivityManagerService extends ActivityManagerNative
                                             removed ? "pkg removed" : "pkg changed");
                                 }
                                 if (removed) {
-                                    sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
+                                    final int cmd = killProcess
+                                            ? IApplicationThread.PACKAGE_REMOVED
+                                            : IApplicationThread.PACKAGE_REMOVED_DONT_KILL;
+                                    sendPackageBroadcastLocked(cmd,
                                             new String[] {ssp}, userId);
                                     if (fullUninstall) {
                                         mAppOpsService.packageRemoved(
@@ -17181,7 +17283,23 @@ public final class ActivityManagerService extends ActivityManagerNative
                             break;
                     }
                     break;
+                case Intent.ACTION_PACKAGE_REPLACED:
+                {
+                    final Uri data = intent.getData();
+                    final String ssp;
+                    if (data != null && (ssp = data.getSchemeSpecificPart()) != null) {
+                        final ApplicationInfo aInfo =
+                                getPackageManagerInternalLocked().getApplicationInfo(
+                                        ssp,
+                                        userId);
+                        mStackSupervisor.updateActivityApplicationInfoLocked(aInfo);
+                        sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REPLACED,
+                                new String[] {ssp}, userId);
+                    }
+                    break;
+                }
                 case Intent.ACTION_PACKAGE_ADDED:
+                {
                     // Special case for adding a package: by default turn on compatibility mode.
                     Uri data = intent.getData();
                     String ssp;
@@ -17199,6 +17317,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                         }
                     }
                     break;
+                }
                 case Intent.ACTION_TIMEZONE_CHANGED:
                     // If this is the time zone changed action, queue up a message that will reset
                     // the timezone of all currently running processes. This message will get
@@ -18040,7 +18159,8 @@ public final class ActivityManagerService extends ActivityManagerNative
 
                 final boolean isDensityChange = (changes & ActivityInfo.CONFIG_DENSITY) != 0;
                 if (isDensityChange) {
-                    killAllBackgroundProcesses(Build.VERSION_CODES.N);
+                    killAllBackgroundProcessesExcept(Build.VERSION_CODES.N,
+                            ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE);
                 }
 
                 for (int i=mLruProcesses.size()-1; i>=0; i--) {
@@ -18261,7 +18381,7 @@ public final class ActivityManagerService extends ActivityManagerNative
 
         if (app.thread == null) {
             app.adjSeq = mAdjSeq;
-            app.curSchedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+            app.curSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
             app.curProcState = ActivityManager.PROCESS_STATE_CACHED_EMPTY;
             return (app.curAdj=app.curRawAdj=ProcessList.CACHED_APP_MAX_ADJ);
         }
@@ -18281,7 +18401,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             app.adjSeq = mAdjSeq;
             app.curRawAdj = app.maxAdj;
             app.foregroundActivities = false;
-            app.curSchedGroup = Process.THREAD_GROUP_DEFAULT;
+            app.curSchedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             app.curProcState = ActivityManager.PROCESS_STATE_PERSISTENT;
             // System processes can do UI, and when they do we want to have
             // them trim their memory after the user leaves the UI.  To
@@ -18318,14 +18438,14 @@ public final class ActivityManagerService extends ActivityManagerNative
         if (app == TOP_APP) {
             // The last app on the list is the foreground app.
             adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = Process.THREAD_GROUP_TOP_APP;
+            schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
             app.adjType = "top-activity";
             foregroundActivities = true;
             procState = PROCESS_STATE_CUR_TOP;
         } else if (app.instrumentationClass != null) {
             // Don't want to kill running instrumentation.
             adj = ProcessList.FOREGROUND_APP_ADJ;
-            schedGroup = Process.THREAD_GROUP_DEFAULT;
+            schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             app.adjType = "instrumentation";
             procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
         } else if ((queue = isReceivingBroadcast(app)) != null) {
@@ -18335,7 +18455,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             // broadcast as reflected by which queue it's active in.
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = (queue == mFgBroadcastQueue)
-                    ? Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                    ? ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
             app.adjType = "broadcast";
             procState = ActivityManager.PROCESS_STATE_RECEIVER;
         } else if (app.executingServices.size() > 0) {
@@ -18343,13 +18463,13 @@ public final class ActivityManagerService extends ActivityManagerNative
             // counts as being in the foreground.
             adj = ProcessList.FOREGROUND_APP_ADJ;
             schedGroup = app.execServicesFg ?
-                    Process.THREAD_GROUP_DEFAULT : Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                    ProcessList.SCHED_GROUP_DEFAULT : ProcessList.SCHED_GROUP_BACKGROUND;
             app.adjType = "exec-service";
             procState = ActivityManager.PROCESS_STATE_SERVICE;
             //Slog.i(TAG, "EXEC " + (app.execServicesFg ? "FG" : "BG") + ": " + app);
         } else {
             // As far as we know the process is empty.  We may change our mind later.
-            schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+            schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
             // At this point we don't actually know the adjustment.  Use the cached adj
             // value that the caller wants us to.
             adj = cachedAdj;
@@ -18378,7 +18498,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                     if (procState > PROCESS_STATE_CUR_TOP) {
                         procState = PROCESS_STATE_CUR_TOP;
                     }
-                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                     app.cached = false;
                     app.empty = false;
                     foregroundActivities = true;
@@ -18397,7 +18517,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                     if (procState > PROCESS_STATE_CUR_TOP) {
                         procState = PROCESS_STATE_CUR_TOP;
                     }
-                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                     app.cached = false;
                     app.empty = false;
                     foregroundActivities = true;
@@ -18441,7 +18561,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 procState = ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
                 app.cached = false;
                 app.adjType = "fg-service";
-                schedGroup = Process.THREAD_GROUP_DEFAULT;
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             } else if (app.forcingToForeground != null) {
                 // The user is aware of this app, so make it visible.
                 adj = ProcessList.PERCEPTIBLE_APP_ADJ;
@@ -18449,7 +18569,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 app.cached = false;
                 app.adjType = "force-fg";
                 app.adjSource = app.forcingToForeground;
-                schedGroup = Process.THREAD_GROUP_DEFAULT;
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             }
         }
 
@@ -18457,7 +18577,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             if (adj > ProcessList.HEAVY_WEIGHT_APP_ADJ) {
                 // We don't want to kill the current heavy-weight process.
                 adj = ProcessList.HEAVY_WEIGHT_APP_ADJ;
-                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                 app.cached = false;
                 app.adjType = "heavy";
             }
@@ -18471,7 +18591,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 // This process is hosting what we currently consider to be the
                 // home app, so we don't want to let it go into the background.
                 adj = ProcessList.HOME_APP_ADJ;
-                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                 app.cached = false;
                 app.adjType = "home";
             }
@@ -18486,7 +18606,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 // We want to try to keep it around more aggressively, to give
                 // a good experience around switching between two apps.
                 adj = ProcessList.PREVIOUS_APP_ADJ;
-                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                 app.cached = false;
                 app.adjType = "previous";
             }
@@ -18526,7 +18646,7 @@ public final class ActivityManagerService extends ActivityManagerNative
 
         for (int is = app.services.size()-1;
                 is >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                        || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                         || procState > ActivityManager.PROCESS_STATE_TOP);
                 is--) {
             ServiceRecord s = app.services.valueAt(is);
@@ -18564,13 +18684,13 @@ public final class ActivityManagerService extends ActivityManagerNative
             }
             for (int conni = s.connections.size()-1;
                     conni >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                            || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                             || procState > ActivityManager.PROCESS_STATE_TOP);
                     conni--) {
                 ArrayList<ConnectionRecord> clist = s.connections.valueAt(conni);
                 for (int i = 0;
                         i < clist.size() && (adj > ProcessList.FOREGROUND_APP_ADJ
-                                || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                                || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                                 || procState > ActivityManager.PROCESS_STATE_TOP);
                         i++) {
                     // XXX should compute this based on the max of
@@ -18662,7 +18782,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                                 if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
                                     schedGroup = client.curSchedGroup;
                                 } else {
-                                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                                 }
                             }
                             if (clientProcState <= ActivityManager.PROCESS_STATE_TOP) {
@@ -18732,9 +18852,9 @@ public final class ActivityManagerService extends ActivityManagerNative
                             adj = ProcessList.FOREGROUND_APP_ADJ;
                             if ((cr.flags&Context.BIND_NOT_FOREGROUND) == 0) {
                                 if ((cr.flags&Context.BIND_IMPORTANT) != 0) {
-                                    schedGroup = Process.THREAD_GROUP_TOP_APP;
+                                    schedGroup = ProcessList.SCHED_GROUP_TOP_APP;
                                 } else {
-                                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                                 }
                             }
                             app.cached = false;
@@ -18752,13 +18872,13 @@ public final class ActivityManagerService extends ActivityManagerNative
 
         for (int provi = app.pubProviders.size()-1;
                 provi >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                        || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                        || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                         || procState > ActivityManager.PROCESS_STATE_TOP);
                 provi--) {
             ContentProviderRecord cpr = app.pubProviders.valueAt(provi);
             for (int i = cpr.connections.size()-1;
                     i >= 0 && (adj > ProcessList.FOREGROUND_APP_ADJ
-                            || schedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE
+                            || schedGroup == ProcessList.SCHED_GROUP_BACKGROUND
                             || procState > ActivityManager.PROCESS_STATE_TOP);
                     i--) {
                 ContentProviderConnection conn = cpr.connections.get(i);
@@ -18816,7 +18936,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                     procState = clientProcState;
                 }
                 if (client.curSchedGroup > schedGroup) {
-                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                 }
             }
             // If the provider has external (non-framework) process
@@ -18825,7 +18945,7 @@ public final class ActivityManagerService extends ActivityManagerNative
             if (cpr.hasExternalProcessHandles()) {
                 if (adj > ProcessList.FOREGROUND_APP_ADJ) {
                     adj = ProcessList.FOREGROUND_APP_ADJ;
-                    schedGroup = Process.THREAD_GROUP_DEFAULT;
+                    schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
                     app.cached = false;
                     app.adjType = "provider";
                     app.adjTarget = cpr.name;
@@ -18839,7 +18959,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         if (app.lastProviderTime > 0 && (app.lastProviderTime+CONTENT_PROVIDER_RETAIN_TIME) > now) {
             if (adj > ProcessList.PREVIOUS_APP_ADJ) {
                 adj = ProcessList.PREVIOUS_APP_ADJ;
-                schedGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                schedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
                 app.cached = false;
                 app.adjType = "provider";
             }
@@ -18918,7 +19038,7 @@ public final class ActivityManagerService extends ActivityManagerNative
         if (adj > app.maxAdj) {
             adj = app.maxAdj;
             if (app.maxAdj <= ProcessList.PERCEPTIBLE_APP_ADJ) {
-                schedGroup = Process.THREAD_GROUP_DEFAULT;
+                schedGroup = ProcessList.SCHED_GROUP_DEFAULT;
             }
         }
 
@@ -19334,17 +19454,29 @@ public final class ActivityManagerService extends ActivityManagerNative
         if (app.setSchedGroup != app.curSchedGroup) {
             app.setSchedGroup = app.curSchedGroup;
             if (DEBUG_SWITCH || DEBUG_OOM_ADJ) Slog.v(TAG_OOM_ADJ,
-                    "Setting process group of " + app.processName
+                    "Setting sched group of " + app.processName
                     + " to " + app.curSchedGroup);
             if (app.waitingToKill != null && app.curReceiver == null
-                    && app.setSchedGroup == Process.THREAD_GROUP_BG_NONINTERACTIVE) {
+                    && app.setSchedGroup == ProcessList.SCHED_GROUP_BACKGROUND) {
                 app.kill(app.waitingToKill, true);
                 success = false;
             } else {
+                int processGroup;
+                switch (app.curSchedGroup) {
+                    case ProcessList.SCHED_GROUP_BACKGROUND:
+                        processGroup = Process.THREAD_GROUP_BG_NONINTERACTIVE;
+                        break;
+                    case ProcessList.SCHED_GROUP_TOP_APP:
+                        processGroup = Process.THREAD_GROUP_TOP_APP;
+                        break;
+                    default:
+                        processGroup = Process.THREAD_GROUP_DEFAULT;
+                        break;
+                }
                 if (true) {
                     long oldId = Binder.clearCallingIdentity();
                     try {
-                        Process.setProcessGroup(app.pid, app.curSchedGroup);
+                        Process.setProcessGroup(app.pid, processGroup);
                     } catch (Exception e) {
                         Slog.w(TAG, "Failed setting process group of " + app.pid
                                 + " to " + app.curSchedGroup);
@@ -19355,7 +19487,7 @@ public final class ActivityManagerService extends ActivityManagerNative
                 } else {
                     if (app.thread != null) {
                         try {
-                            app.thread.setSchedulingGroup(app.curSchedGroup);
+                            app.thread.setSchedulingGroup(processGroup);
                         } catch (RemoteException e) {
                         }
                     }
index d5e40cf..e430dad 100755 (executable)
@@ -76,6 +76,7 @@ import java.io.IOException;
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Objects;
 
@@ -252,6 +253,10 @@ final class ActivityRecord {
                 pw.print(prefix); pw.print("resDir="); pw.println(appInfo.publicSourceDir);
             }
             pw.print(prefix); pw.print("dataDir="); pw.println(appInfo.dataDir);
+            if (appInfo.splitSourceDirs != null) {
+                pw.print(prefix); pw.print("splitDir=");
+                        pw.println(Arrays.toString(appInfo.splitSourceDirs));
+            }
         }
         pw.print(prefix); pw.print("stateNotNeeded="); pw.print(stateNotNeeded);
                 pw.print(" componentSpecified="); pw.print(componentSpecified);
index 5491b4f..d1e1d27 100644 (file)
@@ -65,6 +65,8 @@ import android.app.ActivityManager.RunningTaskInfo;
 import android.content.ComponentName;
 import android.content.Intent;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.content.res.Configuration;
 import android.graphics.Bitmap;
 import android.net.Uri;
@@ -184,7 +186,7 @@ final class ActivityStack {
      * The back history of all previous (and possibly still
      * running) activities.  It contains #TaskRecord objects.
      */
-    private ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
+    private final ArrayList<TaskRecord> mTaskHistory = new ArrayList<>();
 
     /**
      * Used for validating app tokens with window manager.
@@ -839,6 +841,18 @@ final class ActivityStack {
         }
     }
 
+    void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) {
+        final String packageName = aInfo.packageName;
+        for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
+            final List<ActivityRecord> activities = mTaskHistory.get(taskNdx).mActivities;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                if (packageName.equals(activities.get(activityNdx).packageName)) {
+                    activities.get(activityNdx).info.applicationInfo = aInfo;
+                }
+            }
+        }
+    }
+
     /**
      * @return true if something must be done before going to sleep.
      */
@@ -1101,7 +1115,7 @@ final class ActivityStack {
             r.stopped = true;
             r.state = ActivityState.STOPPED;
 
-            mWindowManager.notifyAppStopped(r.appToken);
+            mWindowManager.notifyAppStopped(r.appToken, true);
 
             if (getVisibleBehindActivity() == r) {
                 mStackSupervisor.requestVisibleBehindLocked(r, false);
@@ -2233,6 +2247,10 @@ final class ActivityStack {
                     next.app.thread.scheduleNewIntent(next.newIntents, next.appToken);
                 }
 
+                // Well the app will no longer be stopped.
+                // Clear app token stopped state in window manager if needed.
+                mWindowManager.notifyAppStopped(next.appToken, false);
+
                 EventLog.writeEvent(EventLogTags.AM_RESUME_ACTIVITY, next.userId,
                         System.identityHashCode(next), next.task.taskId, next.shortComponentName);
 
@@ -3005,6 +3023,8 @@ final class ActivityStack {
                 if (!r.visible) {
                     mWindowManager.setAppVisibility(r.appToken, false);
                 }
+                EventLogTags.writeAmStopActivity(
+                        r.userId, System.identityHashCode(r), r.shortComponentName);
                 r.app.thread.scheduleStopActivity(r.appToken, r.visible, r.configChangeFlags);
                 if (mService.isSleepingOrShuttingDown()) {
                     r.setSleeping(true);
index 20f8285..48f31f9 100644 (file)
@@ -1700,6 +1700,15 @@ public final class ActivityStackSupervisor implements DisplayListener {
         return false;
     }
 
+    void updateActivityApplicationInfoLocked(ApplicationInfo aInfo) {
+        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
+            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
+            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
+                stacks.get(stackNdx).updateActivityApplicationInfoLocked(aInfo);
+            }
+        }
+    }
+
     TaskRecord finishTopRunningActivityLocked(ProcessRecord app, String reason) {
         TaskRecord finishedTask = null;
         ActivityStack focusedStack = getFocusedStack();
@@ -2034,6 +2043,25 @@ public final class ActivityStackSupervisor implements DisplayListener {
                 || tempOtherTaskInsetBounds != null);
     }
 
+    void resizePinnedStackLocked(Rect pinnedBounds, Rect tempPinnedTaskBounds) {
+        final ActivityStack stack = getStack(PINNED_STACK_ID);
+        if (stack == null) {
+            Slog.w(TAG, "resizePinnedStackLocked: pinned stack not found");
+            return;
+        }
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizePinnedStack");
+        mWindowManager.deferSurfaceLayout();
+        try {
+            ActivityRecord r = stack.topRunningActivityLocked();
+            resizeStackUncheckedLocked(stack, pinnedBounds, tempPinnedTaskBounds,
+                    null);
+            ensureConfigurationAndResume(stack, r, false);
+        } finally {
+            mWindowManager.continueSurfaceLayout();
+            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+        }
+    }
+
     boolean resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
         if (!task.isResizeable()) {
             Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
@@ -2174,6 +2202,12 @@ public final class ActivityStackSupervisor implements DisplayListener {
      */
     ActivityStack moveTaskToStackUncheckedLocked(
             TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
+
+        if (StackId.isMultiWindowStack(stackId) && !mService.mSupportsMultiWindow) {
+            throw new IllegalStateException("moveTaskToStackUncheckedLocked: Device doesn't "
+                    + "support multi-window task=" + task + " to stackId=" + stackId);
+        }
+
         final ActivityRecord r = task.getTopActivity();
         final ActivityStack prevStack = task.stack;
         final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
@@ -2184,9 +2218,7 @@ public final class ActivityStackSupervisor implements DisplayListener {
         final boolean wasFront = isFrontStack(prevStack)
                 && (prevStack.topRunningActivityLocked() == r);
 
-        final int resizeMode = task.mResizeMode;
-
-        if (stackId == DOCKED_STACK_ID && resizeMode == RESIZE_MODE_UNRESIZEABLE) {
+        if (stackId == DOCKED_STACK_ID && !task.isResizeable()) {
             // We don't allow moving a unresizeable task to the docked stack since the docked
             // stack is used for split-screen mode and will cause things like the docked divider to
             // show up. We instead leave the task in its current stack or move it to the fullscreen
@@ -2213,18 +2245,18 @@ public final class ActivityStackSupervisor implements DisplayListener {
         return stack;
     }
 
-    void moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
+    boolean moveTaskToStackLocked(int taskId, int stackId, boolean toTop, boolean forceFocus,
             String reason, boolean animate) {
         final TaskRecord task = anyTaskForIdLocked(taskId);
         if (task == null) {
             Slog.w(TAG, "moveTaskToStack: no task for id=" + taskId);
-            return;
+            return false;
         }
 
         if (task.stack != null && task.stack.mStackId == stackId) {
             // You are already in the right stack silly...
             Slog.i(TAG, "moveTaskToStack: taskId=" + taskId + " already in stackId=" + stackId);
-            return;
+            return true;
         }
 
         if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
@@ -2293,6 +2325,8 @@ public final class ActivityStackSupervisor implements DisplayListener {
         resumeFocusedStackTopActivityLocked();
 
         showNonResizeableDockToastIfNeeded(task, preferredLaunchStackId, stackId);
+
+        return (preferredLaunchStackId == stackId);
     }
 
     boolean moveTopStackActivityToPinnedStackLocked(int stackId, Rect bounds) {
index 0181640..46389e2 100644 (file)
@@ -1416,7 +1416,7 @@ class ActivityStarter {
                 }
                 intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
                         mStartActivity.launchedFromPackage);
-            } else if (!mStartActivity.intent.filterEquals(intentActivity.intent)) {
+            } else if (!intentActivity.task.isSameIntentResolution(mStartActivity)) {
                 // In this case we are launching the root activity of the task, but with a
                 // different intent. We should start a new instance on top.
                 mAddingToTask = true;
@@ -1772,12 +1772,13 @@ class ActivityStarter {
             return false;
         }
 
-        if (stackId == DOCKED_STACK_ID && r.canGoInDockedStack()) {
-            return true;
+        if (stackId != FULLSCREEN_WORKSPACE_STACK_ID
+                && (!mService.mSupportsMultiWindow || !r.isResizeableOrForced())) {
+            return false;
         }
 
-        if (stackId != FULLSCREEN_WORKSPACE_STACK_ID && !r.isResizeableOrForced()) {
-            return false;
+        if (stackId == DOCKED_STACK_ID && r.canGoInDockedStack()) {
+            return true;
         }
 
         if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
index 86cdbcc..ddfab4d 100644 (file)
@@ -25,6 +25,7 @@ import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.text.BidiFormatter;
 import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -68,18 +69,21 @@ final class AppErrorDialog extends BaseErrorDialog implements View.OnClickListen
         mProc = data.proc;
         mResult = data.result;
         mRepeating = data.repeating;
+        BidiFormatter bidi = BidiFormatter.getInstance();
+
         if ((mProc.pkgList.size() == 1) &&
                 (mName = context.getPackageManager().getApplicationLabel(mProc.info)) != null) {
             setTitle(res.getString(
                     mRepeating ? com.android.internal.R.string.aerr_application_repeated
                             : com.android.internal.R.string.aerr_application,
-                    mName.toString(), mProc.info.processName));
+                    bidi.unicodeWrap(mName.toString()),
+                    bidi.unicodeWrap(mProc.info.processName)));
         } else {
             mName = mProc.processName;
             setTitle(res.getString(
                     mRepeating ? com.android.internal.R.string.aerr_process_repeated
                             : com.android.internal.R.string.aerr_process,
-                    mName.toString()));
+                    bidi.unicodeWrap(mName.toString())));
         }
 
         setCancelable(false);
index 055935d..6cd7561 100644 (file)
@@ -61,6 +61,7 @@ import java.util.HashMap;
 import java.util.concurrent.Semaphore;
 
 import static com.android.server.Watchdog.NATIVE_STACKS_OF_INTEREST;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ANR;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.am.ActivityManagerService.MY_PID;
@@ -806,8 +807,10 @@ class AppErrors {
                     if (pid > 0 && pid != app.pid && pid != parentPid && pid != MY_PID) {
                         if (r.persistent) {
                             firstPids.add(pid);
+                            if (DEBUG_ANR) Slog.i(TAG, "Adding persistent proc: " + r);
                         } else {
                             lastPids.put(pid, Boolean.TRUE);
+                            if (DEBUG_ANR) Slog.i(TAG, "Adding ANR proc: " + r);
                         }
                     }
                 }
index 6d1d9f3..c6befd7 100644 (file)
@@ -27,6 +27,7 @@ import android.content.res.Resources;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
+import android.text.BidiFormatter;
 import android.util.Slog;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -84,9 +85,11 @@ final class AppNotRespondingDialog extends BaseErrorDialog implements View.OnCli
             }
         }
 
+        BidiFormatter bidi = BidiFormatter.getInstance();
+
         setTitle(name2 != null
-                ? res.getString(resid, name1.toString(), name2.toString())
-                : res.getString(resid, name1.toString()));
+                ? res.getString(resid, bidi.unicodeWrap(name1.toString()), bidi.unicodeWrap(name2.toString()))
+                : res.getString(resid, bidi.unicodeWrap(name1.toString())));
 
         if (aboveSystem) {
             getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ERROR);
index 37b0af1..45e3a76 100644 (file)
@@ -654,7 +654,7 @@ public final class BroadcastQueue {
         }
 
         final boolean callerForeground = receiverRecord.callerApp != null
-                ? receiverRecord.callerApp.setSchedGroup != Process.THREAD_GROUP_BG_NONINTERACTIVE
+                ? receiverRecord.callerApp.setSchedGroup != ProcessList.SCHED_GROUP_BACKGROUND
                 : true;
 
         // Show a permission review UI only for explicit broadcast from a foreground app
index f2e8d09..2329b2f 100644 (file)
@@ -54,9 +54,9 @@ option java_package com.android.server.am
 # An activity has been relaunched:
 30020 am_relaunch_activity (User|1|5),(Token|1|5),(Task ID|1|5),(Component Name|3)
 # The activity's onPause has been called.
-30021 am_on_paused_called (User|1|5),(Component Name|3)
+30021 am_on_paused_called (User|1|5),(Component Name|3),(Reason|3)
 # The activity's onResume has been called.
-30022 am_on_resume_called (User|1|5),(Component Name|3)
+30022 am_on_resume_called (User|1|5),(Component Name|3),(Reason|3)
 # Kill a process to reclaim memory.
 30023 am_kill (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(Reason|3)
 # Discard an undelivered serialized broadcast (timeout/ANR/crash)
@@ -103,3 +103,8 @@ option java_package com.android.server.am
 30046 am_meminfo (Cached|2|2),(Free|2|2),(Zram|2|2),(Kernel|2|2),(Native|2|2)
 # Report collection of memory used by a process
 30047 am_pss (Pid|1|5),(UID|1|5),(Process Name|3),(Pss|2|2),(Uss|2|2),(SwapPss|2|2)
+
+# Attempting to stop an activity
+30048 am_stop_activity (User|1|5),(Token|1|5),(Component Name|3)
+# The activity's onStop has been called.
+30049 am_on_stop_called (User|1|5),(Component Name|3),(Reason|3)
index b49370b..f073e5c 100644 (file)
@@ -124,6 +124,13 @@ final class ProcessList {
     // Memory pages are 4K.
     static final int PAGE_SIZE = 4*1024;
 
+    // Activity manager's version of Process.THREAD_GROUP_BG_NONINTERACTIVE
+    static final int SCHED_GROUP_BACKGROUND = 0;
+    // Activity manager's version of Process.THREAD_GROUP_DEFAULT
+    static final int SCHED_GROUP_DEFAULT = 1;
+    // Activity manager's version of Process.THREAD_GROUP_TOP_APP
+    static final int SCHED_GROUP_TOP_APP = 2;
+
     // The minimum number of cached apps we want to be able to keep around,
     // without empty apps being able to push them out of memory.
     static final int MIN_CACHED_APPS = 2;
index 37a549a..62275a9 100644 (file)
@@ -469,6 +469,19 @@ final class TaskRecord {
         setLockTaskAuth();
     }
 
+    /**
+     * Return true if the input activity has the same intent resolution as the intent this task
+     * record is based on (normally the root activity intent).
+     */
+    boolean isSameIntentResolution(ActivityRecord r) {
+        final Intent intent = new Intent(r.intent);
+        // Correct the activity intent for aliasing. The task record intent will always be based on
+        // the real activity that will be launched not the alias, so we need to use an intent with
+        // the component name pointing to the real activity not the alias in the activity record.
+        intent.setComponent(r.realActivity);
+        return this.intent.filterEquals(intent);
+    }
+
     void setTaskToReturnTo(int taskToReturnTo) {
         mTaskToReturnTo = (taskToReturnTo == RECENTS_ACTIVITY_TYPE)
                 ? HOME_ACTIVITY_TYPE : taskToReturnTo;
index a3100c8..f2a9c2c 100644 (file)
@@ -849,6 +849,7 @@ public class AudioService extends IAudioService.Stub {
             AudioSystem.setForceUse(AudioSystem.FOR_DOCK,
                     mDockAudioMediaEnabled ?
                             AudioSystem.FORCE_ANALOG_DOCK : AudioSystem.FORCE_NONE);
+            sendEncodedSurroundMode(mContentResolver);
         }
         if (mHdmiManager != null) {
             synchronized (mHdmiManager) {
@@ -1011,6 +1012,7 @@ public class AudioService extends IAudioService.Stub {
                 0);
     }
 
+
     private void updateMasterMono(ContentResolver cr)
     {
         final boolean masterMono = System.getIntForUser(
@@ -1021,6 +1023,44 @@ public class AudioService extends IAudioService.Stub {
         AudioSystem.setMasterMono(masterMono);
     }
 
+    private void sendEncodedSurroundMode(ContentResolver cr)
+    {
+        int encodedSurroundMode = Settings.Global.getInt(
+                cr, Settings.Global.ENCODED_SURROUND_OUTPUT,
+                Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
+        sendEncodedSurroundMode(encodedSurroundMode);
+    }
+
+    private void sendEncodedSurroundMode(int encodedSurroundMode)
+    {
+        // initialize to guaranteed bad value
+        int forceSetting = AudioSystem.NUM_FORCE_CONFIG;
+        switch (encodedSurroundMode) {
+            case Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO:
+                forceSetting = AudioSystem.FORCE_NONE;
+                break;
+            case Settings.Global.ENCODED_SURROUND_OUTPUT_NEVER:
+                forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_NEVER;
+                break;
+            case Settings.Global.ENCODED_SURROUND_OUTPUT_ALWAYS:
+                forceSetting = AudioSystem.FORCE_ENCODED_SURROUND_ALWAYS;
+                break;
+            default:
+                Log.e(TAG, "updateSurroundSoundSettings: illegal value "
+                        + encodedSurroundMode);
+                break;
+        }
+        if (forceSetting != AudioSystem.NUM_FORCE_CONFIG) {
+            sendMsg(mAudioHandler,
+                    MSG_SET_FORCE_USE,
+                    SENDMSG_QUEUE,
+                    AudioSystem.FOR_ENCODED_SURROUND,
+                    forceSetting,
+                    null,
+                    0);
+        }
+    }
+
     private void readPersistedSettings() {
         final ContentResolver cr = mContentResolver;
 
@@ -1062,6 +1102,7 @@ public class AudioService extends IAudioService.Stub {
 
             updateRingerModeAffectedStreams();
             readDockAudioSettings(cr);
+            sendEncodedSurroundMode(cr);
         }
 
         mMuteAffectedStreams = System.getIntForUser(cr,
@@ -4601,6 +4642,8 @@ public class AudioService extends IAudioService.Stub {
 
     private class SettingsObserver extends ContentObserver {
 
+        private int mEncodedSurroundMode;
+
         SettingsObserver() {
             super(new Handler());
             mContentResolver.registerContentObserver(Settings.System.getUriFor(
@@ -4609,6 +4652,12 @@ public class AudioService extends IAudioService.Stub {
                 Settings.Global.DOCK_AUDIO_MEDIA_ENABLED), false, this);
             mContentResolver.registerContentObserver(Settings.System.getUriFor(
                     Settings.System.MASTER_MONO), false, this);
+
+            mEncodedSurroundMode = Settings.Global.getInt(
+                    mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
+                    Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
+            mContentResolver.registerContentObserver(Settings.Global.getUriFor(
+                    Settings.Global.ENCODED_SURROUND_OUTPUT), false, this);
         }
 
         @Override
@@ -4628,6 +4677,33 @@ public class AudioService extends IAudioService.Stub {
                 }
                 readDockAudioSettings(mContentResolver);
                 updateMasterMono(mContentResolver);
+                updateEncodedSurroundOutput();
+            }
+        }
+
+        private void updateEncodedSurroundOutput() {
+            int newSurroundMode = Settings.Global.getInt(
+                mContentResolver, Settings.Global.ENCODED_SURROUND_OUTPUT,
+                Settings.Global.ENCODED_SURROUND_OUTPUT_AUTO);
+            // Did it change?
+            if (mEncodedSurroundMode != newSurroundMode) {
+                // Send to AudioPolicyManager
+                sendEncodedSurroundMode(newSurroundMode);
+                synchronized(mConnectedDevices) {
+                    // Is HDMI connected?
+                    String key = makeDeviceListKey(AudioSystem.DEVICE_OUT_HDMI, "");
+                    DeviceListSpec deviceSpec = mConnectedDevices.get(key);
+                    if (deviceSpec != null) {
+                        // Toggle HDMI to retrigger broadcast with proper formats.
+                        setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
+                                AudioSystem.DEVICE_STATE_UNAVAILABLE, "", "",
+                                "android"); // disconnect
+                        setWiredDeviceConnectionState(AudioSystem.DEVICE_OUT_HDMI,
+                                AudioSystem.DEVICE_STATE_AVAILABLE, "", "",
+                                "android"); // reconnect
+                    }
+                }
+                mEncodedSurroundMode = newSurroundMode;
             }
         }
     }
@@ -6315,4 +6391,4 @@ public class AudioService extends IAudioService.Stub {
             if (DEBUG_VOL) Log.d(TAG, "Reloaded controller service: " + this);
         }
     }
-}
\ No newline at end of file
+}
index 7e76ac4..86dcd0f 100644 (file)
@@ -54,12 +54,15 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
         if (MediaRecorder.isSystemOnlyAudioSource(source)) {
             return;
         }
-        if (updateSnapshot(event, session, source, recordingInfo)) {
-            final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
+        final AudioRecordConfiguration[] configs =
+                updateSnapshot(event, session, source, recordingInfo);
+        if (configs != null){
             synchronized(mClients) {
+                final Iterator<RecMonitorClient> clientIterator = mClients.iterator();
                 while (clientIterator.hasNext()) {
                     try {
-                        clientIterator.next().mDispatcherCb.dispatchRecordingConfigChange();
+                        clientIterator.next().mDispatcherCb.dispatchRecordingConfigChange(
+                                configs);
                     } catch (RemoteException e) {
                         Log.w(TAG, "Could not call dispatchRecordingConfigChange() on client", e);
                     }
@@ -115,14 +118,19 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
      * @param recordingFormat see
      *     {@link AudioSystem.AudioRecordingCallback#onRecordingConfigurationChanged(int, int, int, int[])}
      *     for the definition of the contents of the array
-     * @return true if the list of active recording sessions has been modified, false otherwise.
+     * @return null if the list of active recording sessions has not been modified, an array
+     *     with the current active configurations otherwise.
      */
-    private boolean updateSnapshot(int event, int session, int source, int[] recordingInfo) {
+    private AudioRecordConfiguration[] updateSnapshot(int event, int session, int source,
+            int[] recordingInfo) {
+        final boolean configChanged;
+        final AudioRecordConfiguration[] configs;
         synchronized(mRecordConfigs) {
             switch (event) {
             case AudioManager.RECORD_CONFIG_EVENT_STOP:
                 // return failure if an unknown recording session stopped
-                return (mRecordConfigs.remove(new Integer(session)) != null);
+                configChanged = (mRecordConfigs.remove(new Integer(session)) != null);
+                break;
             case AudioManager.RECORD_CONFIG_EVENT_START:
                 final AudioFormat clientFormat = new AudioFormat.Builder()
                         .setEncoding(recordingInfo[0])
@@ -143,25 +151,32 @@ public final class RecordingActivityMonitor implements AudioSystem.AudioRecordin
                             new AudioRecordConfiguration(session, source,
                                     clientFormat, deviceFormat, patchHandle);
                     if (updatedConfig.equals(mRecordConfigs.get(sessionKey))) {
-                        return false;
+                        configChanged = false;
                     } else {
                         // config exists but has been modified
                         mRecordConfigs.remove(sessionKey);
                         mRecordConfigs.put(sessionKey, updatedConfig);
-                        return true;
+                        configChanged = true;
                     }
                 } else {
                     mRecordConfigs.put(sessionKey,
                             new AudioRecordConfiguration(session, source,
                                     clientFormat, deviceFormat, patchHandle));
-                    return true;
+                    configChanged = true;
                 }
+                break;
             default:
                 Log.e(TAG, String.format("Unknown event %d for session %d, source %d",
                         event, session, source));
-                return false;
+                configChanged = false;
+            }
+            if (configChanged) {
+                configs = mRecordConfigs.values().toArray(new AudioRecordConfiguration[0]);
+            } else {
+                configs = null;
             }
         }
+        return configs;
     }
 
     /**
index f82454a..cd8eb4e 100644 (file)
@@ -60,10 +60,6 @@ public class CameraService extends SystemService
 
     public static final String CAMERA_SERVICE_PROXY_BINDER_NAME = "media.camera.proxy";
 
-    // Event arguments to use with the camera service notifySystemEvent call:
-    public static final int NO_EVENT = 0; // NOOP
-    public static final int USER_SWITCHED = 1; // User changed, argument is the new user handle
-
     // State arguments to use with the notifyCameraState call from camera service:
     public static final int CAMERA_STATE_OPEN = 0;
     public static final int CAMERA_STATE_ACTIVE = 1;
@@ -224,7 +220,7 @@ public class CameraService extends SystemService
         if (mEnabledCameraUsers == null || !mEnabledCameraUsers.equals(currentUserHandles)) {
             // Some user handles have been added or removed, update mediaserver.
             mEnabledCameraUsers = currentUserHandles;
-            notifyMediaserverLocked(USER_SWITCHED, currentUserHandles);
+            notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, currentUserHandles);
         }
     }
 
@@ -244,7 +240,7 @@ public class CameraService extends SystemService
             if (mEnabledCameraUsers == null) {
                 return;
             }
-            if (notifyMediaserverLocked(USER_SWITCHED, mEnabledCameraUsers)) {
+            if (notifyMediaserverLocked(ICameraService.EVENT_USER_SWITCHED, mEnabledCameraUsers)) {
                 retries = 0;
             }
         }
diff --git a/services/core/java/com/android/server/connectivity/ApfFilter.java b/services/core/java/com/android/server/connectivity/ApfFilter.java
new file mode 100644 (file)
index 0000000..25c84e1
--- /dev/null
@@ -0,0 +1,499 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.connectivity;
+
+import static android.system.OsConstants.*;
+
+import android.net.NetworkUtils;
+import android.net.apf.ApfGenerator;
+import android.net.apf.ApfGenerator.IllegalInstructionException;
+import android.net.apf.ApfGenerator.Register;
+import android.system.ErrnoException;
+import android.system.Os;
+import android.system.PacketSocketAddress;
+import android.util.Log;
+import android.util.Pair;
+
+import com.android.internal.util.HexDump;
+import com.android.server.ConnectivityService;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.lang.Thread;
+import java.net.NetworkInterface;
+import java.net.SocketException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import libcore.io.IoBridge;
+
+/**
+ * For networks that support packet filtering via APF programs, {@code ApfFilter}
+ * listens for IPv6 ICMPv6 router advertisements (RAs) and generates APF programs to
+ * filter out redundant duplicate ones.
+ *
+ * @hide
+ */
+public class ApfFilter {
+    // Thread to listen for RAs.
+    private class ReceiveThread extends Thread {
+        private final byte[] mPacket = new byte[1514];
+        private final FileDescriptor mSocket;
+        private volatile boolean mStopped;
+
+        public ReceiveThread(FileDescriptor socket) {
+            mSocket = socket;
+        }
+
+        public void halt() {
+            mStopped = true;
+            try {
+                // Interrupts the read() call the thread is blocked in.
+                IoBridge.closeAndSignalBlockedThreads(mSocket);
+            } catch (IOException ignored) {}
+        }
+
+        @Override
+        public void run() {
+            log("begin monitoring");
+            while (!mStopped) {
+                try {
+                    int length = Os.read(mSocket, mPacket, 0, mPacket.length);
+                    processRa(mPacket, length);
+                } catch (IOException|ErrnoException e) {
+                    if (!mStopped) {
+                        Log.e(TAG, "Read error", e);
+                    }
+                }
+            }
+        }
+    }
+
+    private static final String TAG = "ApfFilter";
+
+    private final ConnectivityService mConnectivityService;
+    private final NetworkAgentInfo mNai;
+    private ReceiveThread mReceiveThread;
+    private String mIfaceName;
+    private long mUniqueCounter;
+
+    private ApfFilter(ConnectivityService connectivityService, NetworkAgentInfo nai) {
+        mConnectivityService = connectivityService;
+        mNai = nai;
+        maybeStartFilter();
+    }
+
+    private void log(String s) {
+        Log.d(TAG, "(" + mNai.network.netId + "): " + s);
+    }
+
+    private long getUniqueNumber() {
+        return mUniqueCounter++;
+    }
+
+    /**
+     * Attempt to start listening for RAs and, if RAs are received, generating and installing
+     * filters to ignore useless RAs.
+     */
+    private void maybeStartFilter() {
+        mIfaceName = mNai.linkProperties.getInterfaceName();
+        if (mIfaceName == null) return;
+        FileDescriptor socket;
+        try {
+            socket = Os.socket(AF_PACKET, SOCK_RAW, ETH_P_IPV6);
+            PacketSocketAddress addr = new PacketSocketAddress((short) ETH_P_IPV6,
+                    NetworkInterface.getByName(mIfaceName).getIndex());
+            Os.bind(socket, addr);
+            NetworkUtils.attachRaFilter(socket, mNai.networkMisc.apfPacketFormat);
+        } catch(SocketException|ErrnoException e) {
+            Log.e(TAG, "Error filtering raw socket", e);
+            return;
+        }
+        mReceiveThread = new ReceiveThread(socket);
+        mReceiveThread.start();
+    }
+
+    /**
+     * mNai's LinkProperties may have changed, take appropriate action.
+     */
+    public void updateFilter() {
+        // If we're not listening for RAs, try starting.
+        if (mReceiveThread == null) {
+            maybeStartFilter();
+        // If interface name has changed, restart.
+        } else if (!mIfaceName.equals(mNai.linkProperties.getInterfaceName())) {
+            shutdown();
+            maybeStartFilter();
+        }
+    }
+
+    // Returns seconds since Unix Epoch.
+    private static long curTime() {
+        return System.currentTimeMillis() / 1000L;
+    }
+
+    // A class to hold information about an RA.
+    private class Ra {
+        private static final int ETH_HEADER_LEN = 14;
+
+        private static final int IPV6_HEADER_LEN = 40;
+
+        // From RFC4861:
+        private static final int ICMP6_RA_HEADER_LEN = 16;
+        private static final int ICMP6_RA_OPTION_OFFSET =
+                ETH_HEADER_LEN + IPV6_HEADER_LEN + ICMP6_RA_HEADER_LEN;
+        private static final int ICMP6_RA_ROUTER_LIFETIME_OFFSET =
+                ETH_HEADER_LEN + IPV6_HEADER_LEN + 6;
+        private static final int ICMP6_RA_ROUTER_LIFETIME_LEN = 2;
+        // Prefix information option.
+        private static final int ICMP6_PREFIX_OPTION_TYPE = 3;
+        private static final int ICMP6_PREFIX_OPTION_LEN = 32;
+        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET = 4;
+        private static final int ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN = 4;
+        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET = 8;
+        private static final int ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN = 4;
+
+        // From RFC6106: Recursive DNS Server option
+        private static final int ICMP6_RDNSS_OPTION_TYPE = 25;
+        // From RFC6106: DNS Search List option
+        private static final int ICMP6_DNSSL_OPTION_TYPE = 31;
+
+        // From RFC4191: Route Information option
+        private static final int ICMP6_ROUTE_INFO_OPTION_TYPE = 24;
+        // Above three options all have the same format:
+        private static final int ICMP6_4_BYTE_LIFETIME_OFFSET = 4;
+        private static final int ICMP6_4_BYTE_LIFETIME_LEN = 4;
+
+        private final ByteBuffer mPacket;
+        // List of binary ranges that include the whole packet except the lifetimes.
+        // Pairs consist of offset and length.
+        private final ArrayList<Pair<Integer, Integer>> mNonLifetimes =
+                new ArrayList<Pair<Integer, Integer>>();
+        // Minimum lifetime in packet
+        long mMinLifetime;
+        // When the packet was last captured, in seconds since Unix Epoch
+        long mLastSeen;
+
+        /**
+         * Add a binary range of the packet that does not include a lifetime to mNonLifetimes.
+         * Assumes mPacket.position() is as far as we've parsed the packet.
+         * @param lastNonLifetimeStart offset within packet of where the last binary range of
+         *                             data not including a lifetime.
+         * @param lifetimeOffset offset from mPacket.position() to the next lifetime data.
+         * @param lifetimeLength length of the next lifetime data.
+         * @return offset within packet of where the next binary range of data not including
+         *         a lifetime.  This can be passed into the next invocation of this function
+         *         via {@code lastNonLifetimeStart}.
+         */
+        private int addNonLifetime(int lastNonLifetimeStart, int lifetimeOffset,
+                int lifetimeLength) {
+            lifetimeOffset += mPacket.position();
+            mNonLifetimes.add(new Pair<Integer, Integer>(lastNonLifetimeStart,
+                    lifetimeOffset - lastNonLifetimeStart));
+            return lifetimeOffset + lifetimeLength;
+        }
+
+        // Note that this parses RA and may throw IllegalArgumentException (from
+        // Buffer.position(int) ) or IndexOutOfBoundsException (from ByteBuffer.get(int) ) if
+        // parsing encounters something non-compliant with specifications.
+        Ra(byte[] packet, int length) {
+            mPacket = ByteBuffer.allocate(length).put(ByteBuffer.wrap(packet, 0, length));
+            mPacket.clear();
+            mLastSeen = curTime();
+
+            // Parse router lifetime
+            int lastNonLifetimeStart = addNonLifetime(0, ICMP6_RA_ROUTER_LIFETIME_OFFSET,
+                    ICMP6_RA_ROUTER_LIFETIME_LEN);
+            // Parse ICMP6 options
+            mPacket.position(ICMP6_RA_OPTION_OFFSET);
+            while (mPacket.hasRemaining()) {
+                int optionType = ((int)mPacket.get(mPacket.position())) & 0xff;
+                int optionLength = (((int)mPacket.get(mPacket.position() + 1)) & 0xff) * 8;
+                switch (optionType) {
+                    case ICMP6_PREFIX_OPTION_TYPE:
+                        // Parse valid lifetime
+                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_OFFSET,
+                                ICMP6_PREFIX_OPTION_VALID_LIFETIME_LEN);
+                        // Parse preferred lifetime
+                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_OFFSET,
+                                ICMP6_PREFIX_OPTION_PREFERRED_LIFETIME_LEN);
+                        break;
+                    // These three options have the same lifetime offset and size, so process
+                    // together:
+                    case ICMP6_ROUTE_INFO_OPTION_TYPE:
+                    case ICMP6_RDNSS_OPTION_TYPE:
+                    case ICMP6_DNSSL_OPTION_TYPE:
+                        // Parse lifetime
+                        lastNonLifetimeStart = addNonLifetime(lastNonLifetimeStart,
+                                ICMP6_4_BYTE_LIFETIME_OFFSET,
+                                ICMP6_4_BYTE_LIFETIME_LEN);
+                        break;
+                    default:
+                        // RFC4861 section 4.2 dictates we ignore unknown options for fowards
+                        // compatibility.
+                        break;
+                }
+                mPacket.position(mPacket.position() + optionLength);
+            }
+            // Mark non-lifetime bytes since last lifetime.
+            addNonLifetime(lastNonLifetimeStart, 0, 0);
+            mMinLifetime = minLifetime(packet, length);
+        }
+
+        // Ignoring lifetimes (which may change) does {@code packet} match this RA?
+        boolean matches(byte[] packet, int length) {
+            if (length != mPacket.limit()) return false;
+            ByteBuffer a = ByteBuffer.wrap(packet);
+            ByteBuffer b = mPacket;
+            for (Pair<Integer, Integer> nonLifetime : mNonLifetimes) {
+                a.clear();
+                b.clear();
+                a.position(nonLifetime.first);
+                b.position(nonLifetime.first);
+                a.limit(nonLifetime.first + nonLifetime.second);
+                b.limit(nonLifetime.first + nonLifetime.second);
+                if (a.compareTo(b) != 0) return false;
+            }
+            return true;
+        }
+
+        // What is the minimum of all lifetimes within {@code packet} in seconds?
+        // Precondition: matches(packet, length) already returned true.
+        long minLifetime(byte[] packet, int length) {
+            long minLifetime = Long.MAX_VALUE;
+            // Wrap packet in ByteBuffer so we can read big-endian values easily
+            ByteBuffer byteBuffer = ByteBuffer.wrap(packet);
+            for (int i = 0; (i + 1) < mNonLifetimes.size(); i++) {
+                int offset = mNonLifetimes.get(i).first + mNonLifetimes.get(i).second;
+                int lifetimeLength = mNonLifetimes.get(i+1).first - offset;
+                long val;
+                switch (lifetimeLength) {
+                    case 2: val = byteBuffer.getShort(offset); break;
+                    case 4: val = byteBuffer.getInt(offset); break;
+                    default: throw new IllegalStateException("bogus lifetime size " + length);
+                }
+                // Mask to size, converting signed to unsigned
+                val &= (1L << (lifetimeLength * 8)) - 1;
+                minLifetime = Math.min(minLifetime, val);
+            }
+            return minLifetime;
+        }
+
+        // How many seconds does this RA's have to live, taking into account the fact
+        // that we might have seen it a while ago.
+        long currentLifetime() {
+            return mMinLifetime - (curTime() - mLastSeen);
+        }
+
+        boolean isExpired() {
+            return currentLifetime() < 0;
+        }
+
+        // Append a filter for this RA to {@code gen}. Jump to DROP_LABEL if it should be dropped.
+        // Jump to the next filter if packet doesn't match this RA.
+        long generateFilter(ApfGenerator gen) throws IllegalInstructionException {
+            String nextFilterLabel = "Ra" + getUniqueNumber();
+            // Skip if packet is not the right size
+            gen.addLoadFromMemory(Register.R0, gen.PACKET_SIZE_MEMORY_SLOT);
+            gen.addJumpIfR0NotEquals(mPacket.limit(), nextFilterLabel);
+            int filterLifetime = (int)(currentLifetime() / FRACTION_OF_LIFETIME_TO_FILTER);
+            // Skip filter if expired
+            gen.addLoadFromMemory(Register.R0, gen.FILTER_AGE_MEMORY_SLOT);
+            gen.addJumpIfR0GreaterThan(filterLifetime, nextFilterLabel);
+            for (int i = 0; i < mNonLifetimes.size(); i++) {
+                // Generate code to match the packet bytes
+                Pair<Integer, Integer> nonLifetime = mNonLifetimes.get(i);
+                gen.addLoadImmediate(Register.R0, nonLifetime.first);
+                gen.addJumpIfBytesNotEqual(Register.R0,
+                        Arrays.copyOfRange(mPacket.array(), nonLifetime.first,
+                                           nonLifetime.first + nonLifetime.second),
+                        nextFilterLabel);
+                // Generate code to test the lifetimes haven't gone down too far
+                if ((i + 1) < mNonLifetimes.size()) {
+                    Pair<Integer, Integer> nextNonLifetime = mNonLifetimes.get(i + 1);
+                    int offset = nonLifetime.first + nonLifetime.second;
+                    int length = nextNonLifetime.first - offset;
+                    switch (length) {
+                        case 4: gen.addLoad32(Register.R0, offset); break;
+                        case 2: gen.addLoad16(Register.R0, offset); break;
+                        default: throw new IllegalStateException("bogus lifetime size " + length);
+                    }
+                    gen.addJumpIfR0LessThan(filterLifetime, nextFilterLabel);
+                }
+            }
+            gen.addJump(gen.DROP_LABEL);
+            gen.defineLabel(nextFilterLabel);
+            return filterLifetime;
+        }
+    }
+
+    // Maximum number of RAs to filter for.
+    private static final int MAX_RAS = 10;
+    private ArrayList<Ra> mRas = new ArrayList<Ra>();
+
+    // There is always some marginal benefit to updating the installed APF program when an RA is
+    // seen because we can extend the program's lifetime slightly, but there is some cost to
+    // updating the program, so don't bother unless the program is going to expire soon. This
+    // constant defines "soon" in seconds.
+    private static final long MAX_PROGRAM_LIFETIME_WORTH_REFRESHING = 30;
+    // We don't want to filter an RA for it's whole lifetime as it'll be expired by the time we ever
+    // see a refresh.  Using half the lifetime might be a good idea except for the fact that
+    // packets may be dropped, so let's use 6.
+    private static final int FRACTION_OF_LIFETIME_TO_FILTER = 6;
+
+    // When did we last install a filter program? In seconds since Unix Epoch.
+    private long mLastTimeInstalledProgram;
+    // How long should the last installed filter program live for? In seconds.
+    private long mLastInstalledProgramMinLifetime;
+
+    private void installNewProgram() {
+        if (mRas.size() == 0) return;
+        final byte[] program;
+        long programMinLifetime = Long.MAX_VALUE;
+        try {
+            ApfGenerator gen = new ApfGenerator();
+            // This is guaranteed to return true because of the check in maybeInstall.
+            gen.setApfVersion(mNai.networkMisc.apfVersionSupported);
+            // Step 1: Determine how many RA filters we can fit in the program.
+            int ras = 0;
+            for (Ra ra : mRas) {
+                if (ra.isExpired()) continue;
+                ra.generateFilter(gen);
+                if (gen.programLengthOverEstimate() > mNai.networkMisc.maximumApfProgramSize) {
+                    // We went too far.  Use prior number of RAs in "ras".
+                    break;
+                } else {
+                    // Yay! this RA filter fits, increment "ras".
+                    ras++;
+                }
+            }
+            // Step 2: Generate RA filters
+            gen = new ApfGenerator();
+            // This is guaranteed to return true because of the check in maybeInstall.
+            gen.setApfVersion(mNai.networkMisc.apfVersionSupported);
+            for (Ra ra : mRas) {
+                if (ras-- == 0) break;
+                if (ra.isExpired()) continue;
+                programMinLifetime = Math.min(programMinLifetime, ra.generateFilter(gen));
+            }
+            // Execution will reach the end of the program if no filters match, which will pass the
+            // packet to the AP.
+            program = gen.generate();
+        } catch (IllegalInstructionException e) {
+            Log.e(TAG, "Program failed to generate: ", e);
+            return;
+        }
+        mLastTimeInstalledProgram = curTime();
+        mLastInstalledProgramMinLifetime = programMinLifetime;
+        hexDump("Installing filter: ", program, program.length);
+        mConnectivityService.pushApfProgramToNetwork(mNai, program);
+    }
+
+    // Install a new filter program if the last installed one will die soon.
+    private void maybeInstallNewProgram() {
+        if (mRas.size() == 0) return;
+        // If the current program doesn't expire for a while, don't bother updating.
+        long expiry = mLastTimeInstalledProgram + mLastInstalledProgramMinLifetime;
+        if (expiry < curTime() + MAX_PROGRAM_LIFETIME_WORTH_REFRESHING) {
+            installNewProgram();
+        }
+    }
+
+    private void hexDump(String msg, byte[] packet, int length) {
+        log(msg + HexDump.toHexString(packet, 0, length));
+    }
+
+    private void processRa(byte[] packet, int length) {
+        hexDump("Read packet = ", packet, length);
+
+        // Have we seen this RA before?
+        for (int i = 0; i < mRas.size(); i++) {
+            Ra ra = mRas.get(i);
+            if (ra.matches(packet, length)) {
+                log("matched RA");
+                // Update lifetimes.
+                ra.mLastSeen = curTime();
+                ra.mMinLifetime = ra.minLifetime(packet, length);
+
+                // Keep mRas in LRU order so as to prioritize generating filters for recently seen
+                // RAs. LRU prioritizes this because RA filters are generated in order from mRas
+                // until the filter program exceeds the maximum filter program size allowed by the
+                // chipset, so RAs appearing earlier in mRas are more likely to make it into the
+                // filter program.
+                // TODO: consider sorting the RAs in order of increasing expiry time as well.
+                // Swap to front of array.
+                mRas.add(0, mRas.remove(i));
+
+                maybeInstallNewProgram();
+                return;
+            }
+        }
+        // Purge expired RAs.
+        for (int i = 0; i < mRas.size();) {
+            if (mRas.get(i).isExpired()) {
+                log("expired RA");
+                mRas.remove(i);
+            } else {
+                i++;
+            }
+        }
+        // TODO: figure out how to proceed when we've received more then MAX_RAS RAs.
+        if (mRas.size() >= MAX_RAS) return;
+        try {
+            log("adding RA");
+            mRas.add(new Ra(packet, length));
+        } catch (Exception e) {
+            Log.e(TAG, "Error parsing RA: " + e);
+            return;
+        }
+        installNewProgram();
+    }
+
+    /**
+     * Install an {@link ApfFilter} on {@code nai} if {@code nai} supports packet
+     * filtering using APF programs.
+     */
+    public static void maybeInstall(ConnectivityService connectivityService, NetworkAgentInfo nai) {
+        if (nai.networkMisc == null) return;
+        if (nai.networkMisc.apfVersionSupported == 0) return;
+        if (nai.networkMisc.maximumApfProgramSize < 200) {
+            Log.e(TAG, "Uselessly small APF size limit: " + nai.networkMisc.maximumApfProgramSize);
+            return;
+        }
+        // For now only support generating programs for Ethernet frames. If this restriction is
+        // lifted:
+        //   1. the program generator will need its offsets adjusted.
+        //   2. the packet filter attached to our packet socket will need its offset adjusted.
+        if (nai.networkMisc.apfPacketFormat != ARPHRD_ETHER) return;
+        if (!new ApfGenerator().setApfVersion(nai.networkMisc.apfVersionSupported)) {
+            Log.e(TAG, "Unsupported APF version: " + nai.networkMisc.apfVersionSupported);
+            return;
+        }
+        nai.apfFilter = new ApfFilter(connectivityService, nai);
+    }
+
+    public void shutdown() {
+        if (mReceiveThread != null) {
+            log("shuting down");
+            mReceiveThread.halt();  // Also closes socket.
+            mReceiveThread = null;
+        }
+    }
+}
index 90c9ddf..9e1f6b8 100644 (file)
@@ -60,7 +60,7 @@ import static android.net.NetworkAgent.EVENT_PACKET_KEEPALIVE;
 public class KeepaliveTracker {
 
     private static final String TAG = "KeepaliveTracker";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     public static final String PERMISSION = android.Manifest.permission.PACKET_KEEPALIVE_OFFLOAD;
 
index a9eaeee..b390884 100644 (file)
 
 package com.android.server.connectivity;
 
-import static android.net.ConnectivityManager.TYPE_MOBILE;
-import static android.net.ConnectivityManager.TYPE_WIFI;
-
 import java.net.Inet4Address;
 
 import android.content.Context;
 import android.net.InterfaceConfiguration;
+import android.net.ConnectivityManager;
 import android.net.LinkAddress;
 import android.net.LinkProperties;
 import android.net.NetworkAgent;
@@ -34,6 +32,7 @@ import android.os.RemoteException;
 import android.util.Slog;
 
 import com.android.server.net.BaseNetworkObserver;
+import com.android.internal.util.ArrayUtils;
 
 /**
  * @hide
@@ -46,6 +45,13 @@ public class Nat464Xlat extends BaseNetworkObserver {
     // This must match the interface prefix in clatd.c.
     private static final String CLAT_PREFIX = "v4-";
 
+    // The network types we will start clatd on.
+    private static final int[] NETWORK_TYPES = {
+            ConnectivityManager.TYPE_MOBILE,
+            ConnectivityManager.TYPE_WIFI,
+            ConnectivityManager.TYPE_ETHERNET,
+    };
+
     private final INetworkManagementService mNMService;
 
     // ConnectivityService Handler for LinkProperties updates.
@@ -90,7 +96,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
                 (nai.linkProperties != null) ? nai.linkProperties.hasIPv4Address() : false;
         // Only support clat on mobile and wifi for now, because these are the only IPv6-only
         // networks we can connect to.
-        return connected && !hasIPv4Address && (netType == TYPE_MOBILE || netType == TYPE_WIFI);
+        return connected && !hasIPv4Address && ArrayUtils.contains(NETWORK_TYPES, netType);
     }
 
     /**
@@ -221,7 +227,7 @@ public class Nat464Xlat extends BaseNetworkObserver {
     }
 
     private void maybeSetIpv6NdOffload(String iface, boolean on) {
-        if (mNetwork.networkInfo.getType() != TYPE_WIFI) {
+        if (mNetwork.networkInfo.getType() != ConnectivityManager.TYPE_WIFI) {
             return;
         }
         try {
index c5d38cb..b4c71c1 100644 (file)
@@ -32,6 +32,7 @@ import android.util.SparseArray;
 import com.android.internal.util.AsyncChannel;
 import com.android.server.ConnectivityService;
 import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.connectivity.ApfFilter;
 
 import java.util.ArrayList;
 import java.util.Comparator;
@@ -163,6 +164,8 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
     // Used by ConnectivityService to keep track of 464xlat.
     public Nat464Xlat clatd;
 
+    public ApfFilter apfFilter;
+
     public NetworkAgentInfo(Messenger messenger, AsyncChannel ac, Network net, NetworkInfo info,
             LinkProperties lp, NetworkCapabilities nc, int score, Context context, Handler handler,
             NetworkMisc misc, NetworkRequest defaultRequest, ConnectivityService connService) {
@@ -175,6 +178,7 @@ public class NetworkAgentInfo implements Comparable<NetworkAgentInfo> {
         currentScore = score;
         networkMonitor = connService.createNetworkMonitor(context, handler, this, defaultRequest);
         networkMisc = misc;
+        apfFilter.maybeInstall(connService, this);
     }
 
     /**
index 4504bdb..73da427 100644 (file)
@@ -76,7 +76,7 @@ import java.util.Random;
  * {@hide}
  */
 public class NetworkMonitor extends StateMachine {
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final String TAG = "NetworkMonitor";
     private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
     private static final int SOCKET_TIMEOUT_MS = 10000;
@@ -566,7 +566,7 @@ public class NetworkMonitor extends StateMachine {
         @Override
         public void enter() {
             final String cmdName = ACTION_LINGER_EXPIRED + "." + mNetworkAgentInfo.network.netId;
-            mWakeupMessage = new WakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED);
+            mWakeupMessage = makeWakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED);
             long wakeupTime = SystemClock.elapsedRealtime() + mLingerDelayMs;
             mWakeupMessage.schedule(wakeupTime);
         }
@@ -823,4 +823,9 @@ public class NetworkMonitor extends StateMachine {
         }
         DEFAULT_LINGER_DELAY_MS = time_ms;
     }
+
+    @VisibleForTesting
+    protected WakeupMessage makeWakeupMessage(Context c, Handler h, String s, int i) {
+        return new WakeupMessage(c, h, s, i);
+    }
 }
index debda14..22cefd1 100644 (file)
@@ -54,7 +54,7 @@ import java.util.Set;
  */
 public class PermissionMonitor {
     private static final String TAG = "PermissionMonitor";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean SYSTEM = true;
     private static final boolean NETWORK = false;
 
index 760b218..4eecc81 100644 (file)
@@ -90,7 +90,7 @@ public class Tethering extends BaseNetworkObserver {
 
     private Context mContext;
     private final static String TAG = "Tethering";
-    private final static boolean DBG = true;
+    private final static boolean DBG = false;
     private final static boolean VDBG = false;
 
     // TODO - remove both of these - should be part of interface inspection/selection stuff
index 5d81dae..7b134ca 100644 (file)
@@ -905,13 +905,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
 
             // Group ID is arbitrarily set to parent profile user ID. It just represents
             // the default fingerprints for the user.
-            final int effectiveGroupId = getEffectiveUserId(groupId);
+            if (!isCurrentUserOrProfile(groupId)) {
+                return;
+            }
 
             final boolean restricted = isRestricted();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    startEnrollment(token, cryptoClone, effectiveGroupId, receiver, flags, restricted);
+                    startEnrollment(token, cryptoClone, groupId, receiver, flags, restricted);
                 }
             });
         }
@@ -1011,15 +1013,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
         @Override // Binder call
         public void rename(final int fingerId, final int groupId, final String name) {
             checkPermission(MANAGE_FINGERPRINT);
-
-            // Group ID is arbitrarily set to parent profile user ID. It just represents
-            // the default fingerprints for the user.
-            final int effectiveGroupId = getEffectiveUserId(groupId);
+            if (!isCurrentUserOrProfile(groupId)) {
+                return;
+            }
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
                     mFingerprintUtils.renameFingerprintForUser(mContext, fingerId,
-                            effectiveGroupId, name);
+                            groupId, name);
                 }
             });
         }
@@ -1029,9 +1030,11 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
             if (!canUseFingerprint(opPackageName, false /* foregroundOnly */)) {
                 return Collections.emptyList();
             }
-            int effectiveUserId = getEffectiveUserId(userId);
+            if (!isCurrentUserOrProfile(userId)) {
+                return Collections.emptyList();
+            }
 
-            return FingerprintService.this.getEnrolledFingerprints(effectiveUserId);
+            return FingerprintService.this.getEnrolledFingerprints(userId);
         }
 
         @Override // Binder call
@@ -1040,8 +1043,10 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
                 return false;
             }
 
-            int effectiveUserId  = getEffectiveUserId(userId);
-            return FingerprintService.this.hasEnrolledFingerprints(effectiveUserId);
+            if (!isCurrentUserOrProfile(userId)) {
+                return false;
+            }
+            return FingerprintService.this.hasEnrolledFingerprints(userId);
         }
 
         @Override // Binder call
index bd888d8..fba7e7d 100644 (file)
@@ -92,7 +92,7 @@ public final class JobSchedulerService extends com.android.server.SystemService
     /** The maximum number of concurrent jobs we run at one time. */
     private static final int MAX_JOB_CONTEXTS_COUNT = 8;
     /** Enforce a per-app limit on scheduled jobs? */
-    private static final boolean ENFORCE_MAX_JOBS = false;
+    private static final boolean ENFORCE_MAX_JOBS = true;
     /** The maximum number of jobs that we allow an unprivileged app to schedule */
     private static final int MAX_JOBS_PER_APP = 100;
 
index 4268dab..9837a56 100644 (file)
@@ -543,7 +543,7 @@ public class JobStore {
                 return null;
             }
 
-            final String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");
+            String sourcePackageName = parser.getAttributeValue(null, "sourcePackageName");
 
             final String sourceTag = parser.getAttributeValue(null, "sourceTag");
 
@@ -660,6 +660,18 @@ public class JobStore {
             jobBuilder.setExtras(extras);
             parser.nextTag(); // Consume </extras>
 
+            // Migrate sync jobs forward from earlier, incomplete representation
+            if ("android".equals(sourcePackageName)
+                    && extras != null
+                    && extras.getBoolean("SyncManagerJob", false)) {
+                sourcePackageName = extras.getString("owningPackage", sourcePackageName);
+                if (DEBUG) {
+                    Slog.i(TAG, "Fixing up sync job source package name from 'android' to '"
+                            + sourcePackageName + "'");
+                }
+            }
+
+            // And now we're done
             JobStatus js = new JobStatus(
                     jobBuilder.build(), uid, sourcePackageName, sourceUserId, sourceTag,
                     elapsedRuntimes.first, elapsedRuntimes.second);
index ed68abe..e08fad4 100644 (file)
@@ -1559,11 +1559,11 @@ public class GnssLocationProvider implements LocationProviderInterface {
      * called from native code to update SV info
      */
     private void reportSvStatus() {
-        int svCount = native_read_sv_status(mSvidWithFlags, mSnrs, mSvElevations, mSvAzimuths);
+        int svCount = native_read_sv_status(mSvidWithFlags, mCn0s, mSvElevations, mSvAzimuths);
         mListenerHelper.onSvStatusChanged(
                 svCount,
                 mSvidWithFlags,
-                mSnrs,
+                mCn0s,
                 mSvElevations,
                 mSvAzimuths);
 
@@ -1578,7 +1578,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
             }
             if (VERBOSE) {
                 Log.v(TAG, "svid: " + (mSvidWithFlags[i] >> GnssStatus.SVID_SHIFT_WIDTH) +
-                        " snr: " + mSnrs[i]/10 +
+                        " cn0: " + mCn0s[i]/10 +
                         " elev: " + mSvElevations[i] +
                         " azimuth: " + mSvAzimuths[i] +
                         ((mSvidWithFlags[i] & GnssStatus.GNSS_SV_FLAGS_HAS_EPHEMERIS_DATA) == 0
@@ -2402,7 +2402,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
 
     // preallocated arrays, to avoid memory allocation in reportStatus()
     private int mSvidWithFlags[] = new int[MAX_SVS];
-    private float mSnrs[] = new float[MAX_SVS];
+    private float mCn0s[] = new float[MAX_SVS];
     private float mSvElevations[] = new float[MAX_SVS];
     private float mSvAzimuths[] = new float[MAX_SVS];
     private int mSvCount;
@@ -2424,7 +2424,7 @@ public class GnssLocationProvider implements LocationProviderInterface {
     private native void native_delete_aiding_data(int flags);
     // returns number of SVs
     // mask[0] is ephemeris mask and mask[1] is almanac mask
-    private native int native_read_sv_status(int[] prnWithFlags, float[] snrs, float[] elevations,
+    private native int native_read_sv_status(int[] prnWithFlags, float[] cn0s, float[] elevations,
             float[] azimuths);
     private native int native_read_nmea(byte[] buffer, int bufferSize);
     private native void native_inject_location(double latitude, double longitude, float accuracy);
index d9e8e91..734a8d4 100644 (file)
@@ -72,7 +72,7 @@ public abstract class GnssMeasurementsProvider
                 status = GnssMeasurementsEvent.STATUS_NOT_SUPPORTED;
                 break;
             case RESULT_GPS_LOCATION_DISABLED:
-                status = GnssMeasurementsEvent.STATUS_GPS_LOCATION_DISABLED;
+                status = GnssMeasurementsEvent.STATUS_GNSS_LOCATION_DISABLED;
                 break;
             case RESULT_UNKNOWN:
                 return null;
index 57bce4b..fdef31f 100644 (file)
@@ -73,7 +73,8 @@ public abstract class GnssNavigationMessageProvider
                 status = GnssNavigationMessageEvent.STATUS_NOT_SUPPORTED;
                 break;
             case RESULT_GPS_LOCATION_DISABLED:
-                status = GnssNavigationMessageEvent.STATUS_GPS_LOCATION_DISABLED;
+                status = GnssNavigationMessageEvent
+                        .STATUS_GNSS_LOCATION_DISABLED;
                 break;
             case RESULT_UNKNOWN:
                 return null;
index 0b3111c..d471e45 100644 (file)
@@ -75,7 +75,7 @@ abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatus
     public void onSvStatusChanged(
             final int svCount,
             final int[] prnWithFlags,
-            final float[] snrs,
+            final float[] cn0s,
             final float[] elevations,
             final float[] azimuths) {
         Operation operation = new Operation() {
@@ -84,7 +84,7 @@ abstract class GnssStatusListenerHelper extends RemoteListenerHelper<IGnssStatus
                 listener.onSvStatusChanged(
                         svCount,
                         prnWithFlags,
-                        snrs,
+                        cn0s,
                         elevations,
                         azimuths);
             }
index 9f1435a..2807ec8 100644 (file)
@@ -40,7 +40,7 @@ import java.net.Inet4Address;
 
 public class IpConfigStore {
     private static final String TAG = "IpConfigStore";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     protected final DelayedDiskWrite mWriter;
 
index 09b7a18..3acd2ca 100644 (file)
@@ -42,6 +42,7 @@ import static android.net.NetworkPolicy.SNOOZE_NEVER;
 import static android.net.NetworkPolicy.WARNING_DISABLED;
 import static android.net.NetworkPolicyManager.EXTRA_NETWORK_TEMPLATE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_DOZABLE;
+import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_POWERSAVE;
 import static android.net.NetworkPolicyManager.FIREWALL_CHAIN_STANDBY;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_ALLOW;
 import static android.net.NetworkPolicyManager.FIREWALL_RULE_DEFAULT;
@@ -68,6 +69,7 @@ import static android.net.wifi.WifiManager.EXTRA_NETWORK_INFO;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_CONFIGURATION;
 import static android.net.wifi.WifiManager.EXTRA_WIFI_INFO;
 import static android.text.format.DateUtils.DAY_IN_MILLIS;
+
 import static com.android.internal.util.ArrayUtils.appendInt;
 import static com.android.internal.util.Preconditions.checkNotNull;
 import static com.android.internal.util.XmlUtils.readBooleanAttribute;
@@ -294,6 +296,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
 
     final SparseIntArray mUidFirewallStandbyRules = new SparseIntArray();
     final SparseIntArray mUidFirewallDozableRules = new SparseIntArray();
+    final SparseIntArray mUidFirewallPowerSaveRules = new SparseIntArray();
 
     /** Set of states for the child firewall chains. True if the chain is active. */
     final SparseBooleanArray mFirewallChainStates = new SparseBooleanArray();
@@ -522,9 +525,11 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                     new PowerManagerInternal.LowPowerModeListener() {
                 @Override
                 public void onLowPowerModeChanged(boolean enabled) {
+                    if (LOGD) Slog.d(TAG, "onLowPowerModeChanged(" + enabled + ")");
                     synchronized (mRulesLock) {
                         if (mRestrictPower != enabled) {
                             mRestrictPower = enabled;
+                            updateRulesForRestrictPowerLocked();
                             updateRulesForGlobalChangeLocked(true);
                         }
                     }
@@ -1175,13 +1180,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             return;
         }
 
-        // If we are in restrict power mode, we want to treat all interfaces
-        // as metered, to restrict access to the network by uid.  However, we
-        // will not have a bandwidth limit.  Also only do this if restrict
-        // background data use is *not* enabled, since that takes precedence
-        // use over those networks can have a cost associated with it).
-        final boolean powerSave = mRestrictPower && !mRestrictBackground;
-
         // First, generate identities of all connected networks so we can
         // quickly compare them against all defined policies below.
         final ArrayList<Pair<String, NetworkIdentity>> connIdents = new ArrayList<>(states.length);
@@ -1193,9 +1191,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                 final String baseIface = state.linkProperties.getInterfaceName();
                 if (baseIface != null) {
                     connIdents.add(Pair.create(baseIface, ident));
-                    if (powerSave) {
-                        connIfaces.add(baseIface);
-                    }
                 }
 
                 // Stacked interfaces are considered to have same identity as
@@ -1205,9 +1200,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                     final String stackedIface = stackedLink.getInterfaceName();
                     if (stackedIface != null) {
                         connIdents.add(Pair.create(stackedIface, ident));
-                        if (powerSave) {
-                            connIfaces.add(stackedIface);
-                        }
                     }
                 }
             }
@@ -1254,8 +1246,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             }
 
             if (LOGD) {
-                Slog.d(TAG, "applying policy " + policy.toString() + " to ifaces "
-                        + Arrays.toString(ifaces));
+                Slog.d(TAG, "applying policy " + policy + " to ifaces " + Arrays.toString(ifaces));
             }
 
             final boolean hasWarning = policy.warningBytes != LIMIT_DISABLED;
@@ -1286,9 +1277,6 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                     removeInterfaceQuota(iface);
                     setInterfaceQuota(iface, quotaBytes);
                     newMeteredIfaces.add(iface);
-                    if (powerSave) {
-                        connIfaces.remove(iface);
-                    }
                 }
             }
 
@@ -1631,7 +1619,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             try {
                 final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
                 if (oldPolicy != policy) {
-                    setUidPolicyUncheckedLocked(uid, policy, true);
+                    setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -1651,7 +1639,7 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
             policy |= oldPolicy;
             if (oldPolicy != policy) {
-                setUidPolicyUncheckedLocked(uid, policy, true);
+                setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
             }
         }
     }
@@ -1668,11 +1656,22 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             final int oldPolicy = mUidPolicy.get(uid, POLICY_NONE);
             policy = oldPolicy & ~policy;
             if (oldPolicy != policy) {
-                setUidPolicyUncheckedLocked(uid, policy, true);
+                setUidPolicyUncheckedLocked(uid, oldPolicy, policy, true);
             }
         }
     }
 
+    private void setUidPolicyUncheckedLocked(int uid, int oldPolicy, int policy, boolean persist) {
+        setUidPolicyUncheckedLocked(uid, policy, persist);
+
+        // Checks if app was added or removed to the blacklist.
+        if ((oldPolicy == POLICY_NONE && policy == POLICY_REJECT_METERED_BACKGROUND)
+                || (oldPolicy == POLICY_REJECT_METERED_BACKGROUND && policy == POLICY_NONE)) {
+            mHandler.obtainMessage(MSG_RESTRICT_BACKGROUND_WHITELIST_CHANGED, uid, 0)
+                    .sendToTarget();
+        }
+    }
+
     private void setUidPolicyUncheckedLocked(int uid, int policy, boolean persist) {
         mUidPolicy.put(uid, policy);
 
@@ -2000,7 +1999,20 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
     public int getRestrictBackgroundByCaller() {
         mContext.enforceCallingOrSelfPermission(ACCESS_NETWORK_STATE, TAG);
         final int uid = Binder.getCallingUid();
+
         synchronized (mRulesLock) {
+            // Must clear identity because getUidPolicy() is restricted to system.
+            final long token = Binder.clearCallingIdentity();
+            final int policy;
+            try {
+                policy = getUidPolicy(uid);
+            } finally {
+                Binder.restoreCallingIdentity(token);
+            }
+            if (policy == POLICY_REJECT_METERED_BACKGROUND) {
+                // App is blacklisted.
+                return RESTRICT_BACKGROUND_STATUS_ENABLED;
+            }
             if (!mRestrictBackground) {
                 return RESTRICT_BACKGROUND_STATUS_DISABLED;
             }
@@ -2299,9 +2311,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             // state changed, push updated rules
             mUidState.put(uid, uidState);
             updateRulesForUidStateChangeLocked(uid, oldUidState, uidState);
-            if (mDeviceIdleMode && isProcStateAllowedWhileIdle(oldUidState)
-                    != isProcStateAllowedWhileIdle(uidState)) {
-                updateRuleForDeviceIdleLocked(uid);
+            if (isProcStateAllowedWhileIdleOrPowerSaveMode(oldUidState)
+                    != isProcStateAllowedWhileIdleOrPowerSaveMode(uidState) ) {
+                if (mDeviceIdleMode) {
+                    updateRuleForDeviceIdleLocked(uid);
+                }
+                if (mRestrictPower) {
+                    updateRulesForRestrictPowerLocked(uid);
+                }
             }
         }
     }
@@ -2317,6 +2334,9 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                 if (mDeviceIdleMode) {
                     updateRuleForDeviceIdleLocked(uid);
                 }
+                if (mRestrictPower) {
+                    updateRulesForRestrictPowerLocked(uid);
+                }
             }
         }
     }
@@ -2354,15 +2374,36 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
         }
     }
 
-    static boolean isProcStateAllowedWhileIdle(int procState) {
+    static boolean isProcStateAllowedWhileIdleOrPowerSaveMode(int procState) {
         return procState <= ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE;
     }
 
+    void updateRulesForRestrictPowerLocked() {
+        updateRulesForWhitelistedPowerSaveLocked(mRestrictPower, FIREWALL_CHAIN_POWERSAVE,
+                mUidFirewallPowerSaveRules);
+    }
+
+    void updateRulesForRestrictPowerLocked(int uid) {
+        updateRulesForWhitelistedPowerSaveLocked(uid, mRestrictPower, FIREWALL_CHAIN_POWERSAVE);
+    }
+
     void updateRulesForDeviceIdleLocked() {
-        if (mDeviceIdleMode) {
-            // sync the whitelists before enable dozable chain.  We don't care about the rules if
+        updateRulesForWhitelistedPowerSaveLocked(mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE,
+                mUidFirewallDozableRules);
+    }
+
+    void updateRuleForDeviceIdleLocked(int uid) {
+        updateRulesForWhitelistedPowerSaveLocked(uid, mDeviceIdleMode, FIREWALL_CHAIN_DOZABLE);
+    }
+
+    // NOTE: since both fw_dozable and fw_powersave uses the same map (mPowerSaveTempWhitelistAppIds)
+    // for whitelisting, we can reuse their logic in this method.
+    private void updateRulesForWhitelistedPowerSaveLocked(boolean enabled, int chain,
+            SparseIntArray rules) {
+        if (enabled) {
+            // Sync the whitelists before enabling the chain.  We don't care about the rules if
             // we are disabling the chain.
-            final SparseIntArray uidRules = mUidFirewallDozableRules;
+            final SparseIntArray uidRules = rules;
             uidRules.clear();
             final List<UserInfo> users = mUserManager.getUsers();
             for (int ui = users.size() - 1; ui >= 0; ui--) {
@@ -2381,24 +2422,26 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                 }
             }
             for (int i = mUidState.size() - 1; i >= 0; i--) {
-                if (isProcStateAllowedWhileIdle(mUidState.valueAt(i))) {
+                if (isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.valueAt(i))) {
                     uidRules.put(mUidState.keyAt(i), FIREWALL_RULE_ALLOW);
                 }
             }
-            setUidFirewallRules(FIREWALL_CHAIN_DOZABLE, uidRules);
+            setUidFirewallRules(chain, uidRules);
         }
 
-        enableFirewallChainLocked(FIREWALL_CHAIN_DOZABLE, mDeviceIdleMode);
+        enableFirewallChainLocked(chain, enabled);
     }
 
-    void updateRuleForDeviceIdleLocked(int uid) {
-        if (mDeviceIdleMode) {
+    // NOTE: since both fw_dozable and fw_powersave uses the same map (mPowerSaveTempWhitelistAppIds)
+    // for whitelisting, we can reuse their logic in this method.
+    private void updateRulesForWhitelistedPowerSaveLocked(int uid, boolean enabled, int chain) {
+        if (enabled) {
             int appId = UserHandle.getAppId(uid);
             if (mPowerSaveTempWhitelistAppIds.get(appId) || mPowerSaveWhitelistAppIds.get(appId)
-                    || isProcStateAllowedWhileIdle(mUidState.get(uid))) {
-                setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_ALLOW);
+                    || isProcStateAllowedWhileIdleOrPowerSaveMode(mUidState.get(uid))) {
+                setUidFirewallRule(chain, uid, FIREWALL_RULE_ALLOW);
             } else {
-                setUidFirewallRule(FIREWALL_CHAIN_DOZABLE, uid, FIREWALL_RULE_DEFAULT);
+                setUidFirewallRule(chain, uid, FIREWALL_RULE_DEFAULT);
             }
         }
 
@@ -2454,10 +2497,14 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
      * {@link #mRestrictPower}, or {@link #mDeviceIdleMode} value.
      */
     void updateRulesForGlobalChangeLocked(boolean restrictedNetworksChanged) {
+        long start;
+        if (LOGD) start = System.currentTimeMillis();
+
         final PackageManager pm = mContext.getPackageManager();
 
         updateRulesForDeviceIdleLocked();
         updateRulesForAppIdleLocked();
+        updateRulesForRestrictPowerLocked();
 
         // update rules for all installed applications
         final List<UserInfo> users = mUserManager.getUsers();
@@ -2465,8 +2512,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
                 PackageManager.GET_UNINSTALLED_PACKAGES | PackageManager.GET_DISABLED_COMPONENTS
                         | PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
 
-        for (UserInfo user : users) {
-            for (ApplicationInfo app : apps) {
+        final int usersSize = users.size();
+        final int appsSize = apps.size();
+        for (int i = 0; i < usersSize; i++) {
+            final UserInfo user = users.get(i);
+            for (int j = 0; j < appsSize; j++) {
+                final ApplicationInfo app = apps.get(j);
                 final int uid = UserHandle.getUid(user.id, app.uid);
                 updateRulesForUidLocked(uid);
             }
@@ -2481,16 +2532,23 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             normalizePoliciesLocked();
             updateNetworkRulesLocked();
         }
+        if (LOGD) {
+          final long delta = System.currentTimeMillis() - start;
+          Slog.d(TAG, "updateRulesForGlobalChangeLocked(" + restrictedNetworksChanged + ") took "
+                  + delta + "ms");
+        }
     }
 
     void updateRulesForTempWhitelistChangeLocked() {
         final List<UserInfo> users = mUserManager.getUsers();
-        for (UserInfo user : users) {
-            for (int i = mPowerSaveTempWhitelistAppIds.size() - 1; i >= 0; i--) {
-                int appId = mPowerSaveTempWhitelistAppIds.keyAt(i);
+        for (int i = 0; i < users.size(); i++) {
+            final UserInfo user = users.get(i);
+            for (int j = mPowerSaveTempWhitelistAppIds.size() - 1; j >= 0; j--) {
+                int appId = mPowerSaveTempWhitelistAppIds.keyAt(j);
                 int uid = UserHandle.getUid(user.id, appId);
                 updateRuleForAppIdleLocked(uid);
                 updateRuleForDeviceIdleLocked(uid);
+                updateRulesForRestrictPowerLocked(uid);
             }
         }
     }
@@ -2583,6 +2641,12 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             uidRules = RULE_REJECT_ALL;
         }
 
+        // Check powersave state, which is whitelist
+        if (mFirewallChainStates.get(FIREWALL_CHAIN_POWERSAVE)
+                && mUidFirewallPowerSaveRules.get(uid, FIREWALL_RULE_DEFAULT) != FIREWALL_RULE_ALLOW) {
+            uidRules = RULE_REJECT_ALL;
+        }
+
         // Check standby state, which is blacklist
         if (mFirewallChainStates.get(FIREWALL_CHAIN_STANDBY)
                 && mUidFirewallStandbyRules.get(uid, FIREWALL_RULE_DEFAULT) == FIREWALL_RULE_DENY) {
@@ -2810,6 +2874,8 @@ public class NetworkPolicyManagerService extends INetworkPolicyManager.Stub {
             mUidFirewallDozableRules.put(uid, rule);
         } else if (chain == FIREWALL_CHAIN_STANDBY) {
             mUidFirewallStandbyRules.put(uid, rule);
+        } else if (chain == FIREWALL_CHAIN_POWERSAVE) {
+            mUidFirewallPowerSaveRules.put(uid, rule);
         }
 
         try {
index a5dc008..a626b5b 100644 (file)
@@ -16,6 +16,8 @@
 
 package com.android.server.net;
 
+import static android.net.NetworkPolicyManager.POLICY_NONE;
+import static android.net.NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND;
 import static android.net.wifi.WifiInfo.removeDoubleQuotes;
 import static com.android.server.net.NetworkPolicyManagerService.newWifiPolicy;
 import static com.android.server.net.NetworkPolicyManagerService.TAG;
@@ -83,6 +85,8 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
         pw.println("");
         pw.println("  add restrict-background-whitelist UID");
         pw.println("    Adds a UID to the whitelist for restrict background usage.");
+        pw.println("  add restrict-background-blacklist UID");
+        pw.println("    Adds a UID to the blacklist for restrict background usage.");
         pw.println("  get metered-network ID");
         pw.println("    Checks whether the given non-mobile network is metered or not.");
         pw.println("  get restrict-background");
@@ -93,8 +97,12 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
         pw.println("    networks.");
         pw.println("  list restrict-background-whitelist");
         pw.println("    Lists UIDs that are whitelisted for restrict background usage.");
+        pw.println("  list restrict-background-blacklist");
+        pw.println("    Lists UIDs that are blacklisted for restrict background usage.");
         pw.println("  remove restrict-background-whitelist UID");
         pw.println("    Removes a UID from the whitelist for restrict background usage.");
+        pw.println("  remove restrict-background-blacklist UID");
+        pw.println("    Removes a UID from the blacklist for restrict background usage.");
         pw.println("  set metered-network ID BOOLEAN");
         pw.println("    Toggles whether the given non-mobile network is metered.");
         pw.println("  set restrict-background BOOLEAN");
@@ -147,6 +155,8 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
                 return listMeteredWifiNetworks();
             case "restrict-background-whitelist":
                 return listRestrictBackgroundWhitelist();
+            case "restrict-background-blacklist":
+                return listRestrictBackgroundBlacklist();
         }
         pw.println("Error: unknown list type '" + type + "'");
         return -1;
@@ -162,6 +172,8 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
         switch(type) {
             case "restrict-background-whitelist":
                 return addRestrictBackgroundWhitelist();
+            case "restrict-background-blacklist":
+                return addRestrictBackgroundBlacklist();
         }
         pw.println("Error: unknown add type '" + type + "'");
         return -1;
@@ -177,6 +189,8 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
         switch(type) {
             case "restrict-background-whitelist":
                 return removeRestrictBackgroundWhitelist();
+            case "restrict-background-blacklist":
+                return removeRestrictBackgroundBlacklist();
         }
         pw.println("Error: unknown remove type '" + type + "'");
         return -1;
@@ -199,6 +213,24 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
         return 0;
     }
 
+    private int listRestrictBackgroundBlacklist() throws RemoteException {
+        final PrintWriter pw = getOutPrintWriter();
+
+        final int[] uids = mInterface.getUidsWithPolicy(POLICY_REJECT_METERED_BACKGROUND);
+        pw.print("Restrict background blacklisted UIDs: ");
+        if (uids.length == 0) {
+            pw.println("none");
+        } else {
+            for (int i = 0; i < uids.length; i++) {
+                int uid = uids[i];
+                pw.print(uid);
+                pw.print(' ');
+            }
+        }
+        pw.println();
+        return 0;
+    }
+
     private int getRestrictBackground() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         pw.print("Restrict background status: ");
@@ -233,6 +265,24 @@ class NetworkPolicyManagerShellCommand extends ShellCommand {
         return 0;
     }
 
+    private int addRestrictBackgroundBlacklist() throws RemoteException {
+        final int uid = getUidFromNextArg();
+        if (uid < 0) {
+            return uid;
+        }
+        mInterface.setUidPolicy(uid, POLICY_REJECT_METERED_BACKGROUND);
+        return 0;
+    }
+
+    private int removeRestrictBackgroundBlacklist() throws RemoteException {
+        final int uid = getUidFromNextArg();
+        if (uid < 0) {
+            return uid;
+        }
+        mInterface.setUidPolicy(uid, POLICY_NONE);
+        return 0;
+    }
+
     private int listMeteredWifiNetworks() throws RemoteException {
         final PrintWriter pw = getOutPrintWriter();
         final String arg = getNextArg();
index 5e4703d..7dff2c1 100644 (file)
@@ -28,10 +28,11 @@ public class NotificationComparator
         final int leftImportance = left.getImportance();
         final int rightImportance = right.getImportance();
         if (leftImportance != rightImportance) {
-            // by priority, high to low
+            // by importance, high to low
             return -1 * Integer.compare(leftImportance, rightImportance);
         }
 
+        // Whether or not the notification can bypass DND.
         final int leftPackagePriority = left.getPackagePriority();
         final int rightPackagePriority = right.getPackagePriority();
         if (leftPackagePriority != rightPackagePriority) {
@@ -39,6 +40,13 @@ public class NotificationComparator
             return -1 * Integer.compare(leftPackagePriority, rightPackagePriority);
         }
 
+        final int leftPriority = left.sbn.getNotification().priority;
+        final int rightPriority = right.sbn.getNotification().priority;
+        if (leftPriority != rightPriority) {
+            // by priority, high to low
+            return -1 * Integer.compare(leftPriority, rightPriority);
+        }
+
         final float leftPeople = left.getContactAffinity();
         final float rightPeople = right.getContactAffinity();
         if (leftPeople != rightPeople) {
index b57cc75..bcdeb66 100644 (file)
@@ -23,7 +23,7 @@ import android.util.Log;
 import android.util.Slog;
 
 /**
- * This {@link com.android.server.notification.NotificationSignalExtractor} noticies noisy
+ * This {@link com.android.server.notification.NotificationSignalExtractor} notices noisy
  * notifications and marks them to get a temporary ranking bump.
  */
 public class NotificationIntrusivenessExtractor implements NotificationSignalExtractor {
@@ -44,9 +44,15 @@ public class NotificationIntrusivenessExtractor implements NotificationSignalExt
             return null;
         }
 
-        final Notification notification = record.getNotification();
-        if (record.getImportance() > NotificationListenerService.Ranking.IMPORTANCE_DEFAULT) {
-            record.setRecentlyIntrusive(true);
+        if (record.getImportance() >= NotificationListenerService.Ranking.IMPORTANCE_DEFAULT) {
+            final Notification notification = record.getNotification();
+            if ((notification.defaults & Notification.DEFAULT_VIBRATE) != 0 ||
+                    notification.vibrate != null ||
+                    (notification.defaults & Notification.DEFAULT_SOUND) != 0 ||
+                    notification.sound != null ||
+                    notification.fullScreenIntent != null) {
+                record.setRecentlyIntrusive(true);
+            }
         }
 
         return new RankingReconsideration(record.getKey(), HANG_TIME_MS) {
index e4c3c14..3855579 100644 (file)
@@ -1320,7 +1320,7 @@ public class NotificationManagerService extends SystemService {
 
         @Override
         public int getImportance(String pkg, int uid) {
-            checkCallerIsSystem();
+            enforceSystemOrSystemUI("Caller not system or systemui");
             return mRankingHelper.getImportance(pkg, uid);
         }
 
@@ -1698,9 +1698,9 @@ public class NotificationManagerService extends SystemService {
         }
 
         @Override
-        public List<AutomaticZenRule> getAutomaticZenRules() throws RemoteException {
+        public List<ZenModeConfig.ZenRule> getZenRules() throws RemoteException {
             enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
-            return mZenModeHelper.getAutomaticZenRules();
+            return mZenModeHelper.getZenRules();
         }
 
         @Override
@@ -1711,7 +1711,7 @@ public class NotificationManagerService extends SystemService {
         }
 
         @Override
-        public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule)
+        public String addAutomaticZenRule(AutomaticZenRule automaticZenRule)
                 throws RemoteException {
             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
@@ -1724,7 +1724,7 @@ public class NotificationManagerService extends SystemService {
         }
 
         @Override
-        public boolean updateAutomaticZenRule(AutomaticZenRule automaticZenRule)
+        public boolean updateAutomaticZenRule(String id, AutomaticZenRule automaticZenRule)
                 throws RemoteException {
             Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
             Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
@@ -1732,7 +1732,7 @@ public class NotificationManagerService extends SystemService {
             Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
             enforcePolicyAccess(Binder.getCallingUid(), "updateAutomaticZenRule");
 
-            return mZenModeHelper.updateAutomaticZenRule(automaticZenRule,
+            return mZenModeHelper.updateAutomaticZenRule(id, automaticZenRule,
                     "updateAutomaticZenRule");
         }
 
index 383c1ab..5c5c8f8 100644 (file)
@@ -238,13 +238,13 @@ public class ZenModeHelper {
         return mZenMode;
     }
 
-    public List<AutomaticZenRule> getAutomaticZenRules() {
-        List<AutomaticZenRule> rules = new ArrayList<>();
+    public List<ZenRule> getZenRules() {
+        List<ZenRule> rules = new ArrayList<>();
         synchronized (mConfig) {
             if (mConfig == null) return rules;
             for (ZenRule rule : mConfig.automaticRules.values()) {
                 if (canManageAutomaticZenRule(rule)) {
-                    rules.add(createAutomaticZenRule(rule));
+                    rules.add(rule);
                 }
             }
         }
@@ -264,18 +264,18 @@ public class ZenModeHelper {
         return null;
     }
 
-    public AutomaticZenRule addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
-        if (!TextUtils.isEmpty(automaticZenRule.getId())) {
-            throw new IllegalArgumentException("Rule already exists");
-        }
+    public String addAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
         if (!isSystemRule(automaticZenRule)) {
             ServiceInfo owner = getServiceInfo(automaticZenRule.getOwner());
             if (owner == null) {
                 throw new IllegalArgumentException("Owner is not a condition provider service");
             }
 
-            final int ruleInstanceLimit = owner.metaData.getInt(
-                    ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
+            int ruleInstanceLimit = -1;
+            if (owner.metaData != null) {
+                ruleInstanceLimit = owner.metaData.getInt(
+                        ConditionProviderService.META_DATA_RULE_INSTANCE_LIMIT, -1);
+            }
             if (ruleInstanceLimit > 0 && ruleInstanceLimit
                     < (getCurrentInstanceCount(automaticZenRule.getOwner()) + 1)) {
                 throw new IllegalArgumentException("Rule instance limit exceeded");
@@ -293,14 +293,15 @@ public class ZenModeHelper {
             populateZenRule(automaticZenRule, rule, true);
             newConfig.automaticRules.put(rule.id, rule);
             if (setConfigLocked(newConfig, reason, true)) {
-                return createAutomaticZenRule(rule);
+                return rule.id;
             } else {
                 return null;
             }
         }
     }
 
-    public boolean updateAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
+    public boolean updateAutomaticZenRule(String ruleId, AutomaticZenRule automaticZenRule,
+            String reason) {
         ZenModeConfig newConfig;
         synchronized (mConfig) {
             if (mConfig == null) return false;
@@ -309,7 +310,6 @@ public class ZenModeHelper {
                         + " reason=" + reason);
             }
             newConfig = mConfig.copy();
-            final String ruleId = automaticZenRule.getId();
             ZenModeConfig.ZenRule rule;
             if (ruleId == null) {
                 throw new IllegalArgumentException("Rule doesn't exist");
@@ -437,7 +437,7 @@ public class ZenModeHelper {
     private AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
         return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
                 NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled,
-                rule.id, rule.creationTime);
+                rule.creationTime);
     }
 
     public void setManualZenMode(int zenMode, Uri conditionId, String reason) {
index 9a5a183..d6b59f9 100644 (file)
@@ -788,7 +788,7 @@ final class DefaultPermissionGrantPolicy {
     }
 
     private void grantRuntimePermissionsLPw(PackageParser.Package pkg, Set<String> permissions,
-            boolean systemFixed, boolean overrideUserChoice,  int userId) {
+            boolean systemFixed, boolean isDefaultPhoneOrSms, int userId) {
         if (pkg.requestedPermissions.isEmpty()) {
             return;
         }
@@ -796,7 +796,13 @@ final class DefaultPermissionGrantPolicy {
         List<String> requestedPermissions = pkg.requestedPermissions;
         Set<String> grantablePermissions = null;
 
-        if (pkg.isUpdatedSystemApp()) {
+        // If this is the default Phone or SMS app we grant permissions regardless
+        // whether the version on the system image declares the permission as used since
+        // selecting the app as the default Phone or SMS the user makes a deliberate
+        // choice to grant this app the permissions needed to function. For all other
+        // apps, (default grants on first boot and user creation) we don't grant default
+        // permissions if the version on the system image does not declare them.
+        if (!isDefaultPhoneOrSms && pkg.isUpdatedSystemApp()) {
             PackageSetting sysPs = mService.mSettings.getDisabledSystemPkgLPr(pkg.packageName);
             if (sysPs != null) {
                 if (sysPs.pkg.requestedPermissions.isEmpty()) {
@@ -828,7 +834,7 @@ final class DefaultPermissionGrantPolicy {
                 // Unless the caller wants to override user choices. The override is
                 // to make sure we can grant the needed permission to the default
                 // sms and phone apps after the user chooses this in the UI.
-                if (flags == 0 || overrideUserChoice) {
+                if (flags == 0 || isDefaultPhoneOrSms) {
                     // Never clobber policy or system.
                     final int fixedFlags = PackageManager.FLAG_PERMISSION_SYSTEM_FIXED
                             | PackageManager.FLAG_PERMISSION_POLICY_FIXED;
index 8786350..389e0a1 100644 (file)
@@ -210,6 +210,9 @@ class EphemeralApplicationRegistry {
     }
 
     public void onPackageUninstalledLPw(PackageParser.Package pkg) {
+        if (pkg == null) {
+            return;
+        }
         PackageSetting ps = (PackageSetting) pkg.mExtras;
         if (ps == null) {
             return;
index 1476e6e..93dcc72 100644 (file)
@@ -203,6 +203,11 @@ public final class Installer extends SystemService {
         mInstaller.execute("linkfile", relativePath, fromBase, toBase);
     }
 
+    public void moveAb(String apkPath, String instructionSet, String outputPath)
+            throws InstallerException {
+        mInstaller.execute("move_ab", apkPath, instructionSet, outputPath);
+    }
+
     private static void assertValidInstructionSet(String instructionSet)
             throws InstallerException {
         for (String abi : Build.SUPPORTED_ABIS) {
index 94b3b2d..67aeed1 100644 (file)
 
 package com.android.server.pm;
 
-import android.app.AppGlobals;
+import static com.android.server.pm.Installer.DEXOPT_OTA;
+import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
+import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
+
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.IOtaDexopt;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.Package;
-import android.content.pm.ResolveInfo;
 import android.os.Environment;
 import android.os.RemoteException;
 import android.os.ResultReceiver;
 import android.os.ServiceManager;
-import android.os.UserHandle;
 import android.os.storage.StorageManager;
-import android.util.ArraySet;
 import android.util.Log;
+import android.util.Slog;
 
-import dalvik.system.DexFile;
+import com.android.internal.os.InstallerConnection.InstallerException;
 
 import java.io.File;
 import java.io.FileDescriptor;
-import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.LinkedList;
 import java.util.List;
-import java.util.Set;
-
-import static com.android.server.pm.Installer.DEXOPT_OTA;
 
 /**
  * A service for A/B OTA dexopting.
@@ -70,6 +62,9 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
         // Use the package manager install and install lock here for the OTA dex optimizer.
         mPackageDexOptimizer = new OTADexoptPackageDexOptimizer(packageManagerService.mInstaller,
                 packageManagerService.mInstallLock, context);
+
+        // Now it's time to check whether we need to move any A/B artifacts.
+        moveAbArtifacts(packageManagerService.mInstaller);
     }
 
     public static OtaDexoptService main(Context context,
@@ -150,20 +145,50 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
                 false /* extractOnly */);
     }
 
-    private ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) {
-        List<ResolveInfo> ris = null;
-        try {
-            ris = AppGlobals.getPackageManager().queryIntentReceivers(
-                    intent, null, 0, userId);
-        } catch (RemoteException e) {
+    private void moveAbArtifacts(Installer installer) {
+        if (mDexoptPackages != null) {
+            throw new IllegalStateException("Should not be ota-dexopting when trying to move.");
         }
-        ArraySet<String> pkgNames = new ArraySet<String>(ris == null ? 0 : ris.size());
-        if (ris != null) {
-            for (ResolveInfo ri : ris) {
-                pkgNames.add(ri.activityInfo.packageName);
+
+        // Look into all packages.
+        Collection<PackageParser.Package> pkgs = mPackageManagerService.getPackages();
+        for (PackageParser.Package pkg : pkgs) {
+            if (pkg == null) {
+                continue;
+            }
+
+            // Does the package have code? If not, there won't be any artifacts.
+            if (!PackageDexOptimizer.canOptimizePackage(pkg)) {
+                continue;
+            }
+            if (pkg.codePath == null) {
+                Slog.w(TAG, "Package " + pkg + " can be optimized but has null codePath");
+                continue;
+            }
+
+            // If the path is in /system or /vendor, ignore. It will have been ota-dexopted into
+            // /data/ota and moved into the dalvik-cache already.
+            if (pkg.codePath.startsWith("/system") || pkg.codePath.startsWith("/vendor")) {
+                continue;
+            }
+
+            final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
+            final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
+            final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+            for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+                for (String path : paths) {
+                    String oatDir = PackageDexOptimizer.getOatDir(new File(pkg.codePath)).
+                            getAbsolutePath();
+
+                    // TODO: Check first whether there is an artifact, to save the roundtrip time.
+
+                    try {
+                        installer.moveAb(path, dexCodeInstructionSet, oatDir);
+                    } catch (InstallerException e) {
+                    }
+                }
             }
         }
-        return pkgNames;
     }
 
     private static class OTADexoptPackageDexOptimizer extends
@@ -180,10 +205,5 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
             return dexoptFlags | DEXOPT_OTA;
         }
 
-        @Override
-        protected void recordSuccessfulDexopt(Package pkg, String instructionSet) {
-            // Never record the dexopt, as it's in the B partition.
-        }
-
     }
 }
index a3af561..c9613b4 100644 (file)
@@ -21,6 +21,7 @@ import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageParser;
 import android.content.pm.PackageParser.Package;
+import android.os.Environment;
 import android.os.PowerManager;
 import android.os.UserHandle;
 import android.os.WorkSource;
@@ -112,15 +113,6 @@ class PackageDexOptimizer {
     }
 
     /**
-     * Determine whether the package should be skipped for the given instruction set. A return
-     * value of true means the package will be skipped. A return value of false means that the
-     * package will be further investigated, and potentially compiled.
-     */
-    protected boolean shouldSkipBasedOnISA(PackageParser.Package pkg, String instructionSet) {
-        return pkg.mDexOptPerformed.contains(instructionSet);
-    }
-
-    /**
      * Adjust the given dexopt-needed value. Can be overridden to influence the decision to
      * optimize or not (and in what way).
      */
@@ -135,13 +127,6 @@ class PackageDexOptimizer {
         return dexoptFlags;
     }
 
-    /**
-     * Update the package status after a successful compilation.
-     */
-    protected void recordSuccessfulDexopt(PackageParser.Package pkg, String instructionSet) {
-        pkg.mDexOptPerformed.add(instructionSet);
-    }
-
     private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
             boolean useProfiles, boolean extractOnly) {
         final String[] instructionSets = targetInstructionSets != null ?
@@ -158,44 +143,52 @@ class PackageDexOptimizer {
         boolean performedDexOpt = false;
         final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
         for (String dexCodeInstructionSet : dexCodeInstructionSets) {
-            if (!useProfiles && shouldSkipBasedOnISA(pkg, dexCodeInstructionSet)) {
-                // Skip only if we do not use profiles since they might trigger a recompilation.
-                continue;
-            }
-
             for (String path : paths) {
+                if (useProfiles && isUsedByOtherApps(path)) {
+                    // We cannot use profile guided compilation if the apk was used by another app.
+                    useProfiles = false;
+                }
                 int dexoptNeeded;
 
                 try {
-                    dexoptNeeded = DexFile.getDexOptNeeded(path, pkg.packageName,
-                            dexCodeInstructionSet, /* defer */false);
+                    int compilationTypeMask = 0;
+                    if (extractOnly) {
+                        // For extract only, any type of compilation is good.
+                        compilationTypeMask = DexFile.COMPILATION_TYPE_FULL
+                            | DexFile.COMPILATION_TYPE_PROFILE_GUIDE
+                            | DexFile.COMPILATION_TYPE_EXTRACT_ONLY;
+                    } else {
+                        // Branch taken for profile guide and full compilation.
+                        // Profile guide compilation should only recompile a previous
+                        // profile compiled/extract only file and should not be attempted if the
+                        // apk is already fully compiled. So test against a full compilation type.
+                        compilationTypeMask = DexFile.COMPILATION_TYPE_FULL;
+                    }
+                    dexoptNeeded = DexFile.getDexOptNeeded(path,
+                            dexCodeInstructionSet, compilationTypeMask);
                 } catch (IOException ioe) {
                     Slog.w(TAG, "IOException reading apk: " + path, ioe);
                     return DEX_OPT_FAILED;
                 }
                 dexoptNeeded = adjustDexoptNeeded(dexoptNeeded);
 
-                if (dexoptNeeded == DexFile.NO_DEXOPT_NEEDED) {
-                    if (useProfiles) {
-                        // Profiles may trigger re-compilation. The final decision is taken in
-                        // installd.
-                        dexoptNeeded = DexFile.DEX2OAT_NEEDED;
-                    } else {
-                        // No dexopt needed and we don't use profiles. Nothing to do.
-                        continue;
-                    }
-                }
                 final String dexoptType;
                 String oatDir = null;
-                if (dexoptNeeded == DexFile.DEX2OAT_NEEDED) {
-                    dexoptType = "dex2oat";
-                    oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
-                } else if (dexoptNeeded == DexFile.PATCHOAT_NEEDED) {
-                    dexoptType = "patchoat";
-                } else if (dexoptNeeded == DexFile.SELF_PATCHOAT_NEEDED) {
-                    dexoptType = "self patchoat";
-                } else {
-                    throw new IllegalStateException("Invalid dexopt needed: " + dexoptNeeded);
+                switch (dexoptNeeded) {
+                    case DexFile.NO_DEXOPT_NEEDED:
+                        continue;
+                    case DexFile.DEX2OAT_NEEDED:
+                        dexoptType = "dex2oat";
+                        oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
+                        break;
+                    case DexFile.PATCHOAT_NEEDED:
+                        dexoptType = "patchoat";
+                        break;
+                    case DexFile.SELF_PATCHOAT_NEEDED:
+                        dexoptType = "self patchoat";
+                        break;
+                    default:
+                        throw new IllegalStateException("Invalid dexopt:" + dexoptNeeded);
                 }
 
 
@@ -204,8 +197,10 @@ class PackageDexOptimizer {
                         + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
                         + " extractOnly=" + extractOnly + " oatDir = " + oatDir);
                 final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+                // Profile guide compiled oat files should not be public.
+                final boolean isPublic = !pkg.isForwardLocked() && !useProfiles;
                 final int dexFlags = adjustDexoptFlags(
-                        (!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0)
+                        ( isPublic ? DEXOPT_PUBLIC : 0)
                         | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
                         | (debuggable ? DEXOPT_DEBUGGABLE : 0)
                         | (extractOnly ? DEXOPT_EXTRACTONLY : 0)
@@ -219,15 +214,6 @@ class PackageDexOptimizer {
                     Slog.w(TAG, "Failed to dexopt", e);
                 }
             }
-
-            if (!extractOnly) {
-                // At this point we haven't failed dexopt and we haven't deferred dexopt. We must
-                // either have either succeeded dexopt, or have had getDexOptNeeded tell us
-                // it isn't required. We therefore mark that this package doesn't need dexopt unless
-                // it's forced. performedDexOpt will tell us whether we performed dex-opt or skipped
-                // it.
-                recordSuccessfulDexopt(pkg, dexCodeInstructionSet);
-            }
         }
 
         // If we've gotten here, we're sure that no error occurred and that we haven't
@@ -275,6 +261,25 @@ class PackageDexOptimizer {
         mSystemReady = true;
     }
 
+    private boolean isUsedByOtherApps(String apkPath) {
+        try {
+            apkPath = new File(apkPath).getCanonicalPath();
+        } catch (IOException e) {
+            // Log an error but continue without it.
+            Slog.w(TAG, "Failed to get canonical path", e);
+        }
+        String useMarker = apkPath.replace('/', '@');
+        final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
+        for (int i = 0; i < currentUserIds.length; i++) {
+            File profileDir = Environment.getDataProfilesDeForeignDexDirectory(currentUserIds[i]);
+            File foreignUseMark = new File(profileDir, useMarker);
+            if (foreignUseMark.exists()) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * A specialized PackageDexOptimizer that overrides already-installed checks, forcing a
      * dexopt path.
@@ -291,12 +296,6 @@ class PackageDexOptimizer {
         }
 
         @Override
-        protected boolean shouldSkipBasedOnISA(Package pkg, String instructionSet) {
-            // Forced compilation, never skip.
-            return false;
-        }
-
-        @Override
         protected int adjustDexoptNeeded(int dexoptNeeded) {
             // Ensure compilation, no matter the current state.
             // TODO: The return value is wrong when patchoat is needed.
index 6cfa1c9..b2ee0b2 100644 (file)
@@ -62,7 +62,9 @@ import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATIO
 import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
 import static android.content.pm.PackageManager.MATCH_DISABLED_COMPONENTS;
+import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE;
 import static android.content.pm.PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
+import static android.content.pm.PackageManager.MATCH_ENCRYPTION_UNAWARE;
 import static android.content.pm.PackageManager.MATCH_SYSTEM_ONLY;
 import static android.content.pm.PackageManager.MATCH_UNINSTALLED_PACKAGES;
 import static android.content.pm.PackageManager.MOVE_FAILED_DEVICE_ADMIN;
@@ -101,6 +103,7 @@ import android.annotation.Nullable;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
+import android.app.admin.DevicePolicyManagerInternal;
 import android.app.admin.IDevicePolicyManager;
 import android.app.backup.IBackupManager;
 import android.content.BroadcastReceiver;
@@ -153,7 +156,6 @@ import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
 import android.content.pm.Signature;
 import android.content.pm.UserInfo;
-import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.pm.VerifierInfo;
 import android.content.res.Resources;
@@ -173,6 +175,7 @@ import android.os.Looper;
 import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.Parcelable;
 import android.os.Process;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -358,6 +361,7 @@ public class PackageManagerService extends IPackageManager.Stub {
     static final int SCAN_MOVE = 1<<13;
     static final int SCAN_INITIAL = 1<<14;
     static final int SCAN_CHECK_ONLY = 1<<15;
+    static final int SCAN_DONT_KILL_APP = 1<<17;
 
     static final int REMOVE_CHATTY = 1<<16;
 
@@ -497,6 +501,9 @@ public class PackageManagerService extends IPackageManager.Stub {
     final ArrayMap<String, PackageParser.Package> mPackages =
             new ArrayMap<String, PackageParser.Package>();
 
+    final ArrayMap<String, Set<String>> mKnownCodebase =
+            new ArrayMap<String, Set<String>>();
+
     // Tracks available target package names -> overlay package paths.
     final ArrayMap<String, ArrayMap<String, PackageParser.Package>> mOverlays =
         new ArrayMap<String, ArrayMap<String, PackageParser.Package>>();
@@ -637,9 +644,6 @@ public class PackageManagerService extends IPackageManager.Stub {
     // List of packages names to keep cached, even if they are uninstalled for all users
     private List<String> mKeepUninstalledPackages;
 
-    private boolean mUseJitProfiles =
-            SystemProperties.getBoolean("dalvik.vm.usejitprofiles", false);
-
     private static class IFVerificationParams {
         PackageParser.Package pkg;
         boolean replacing;
@@ -1426,19 +1430,21 @@ public class PackageManagerService extends IPackageManager.Stub {
 
                         final boolean grantPermissions = (args.installFlags
                                 & PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS) != 0;
+                        final boolean killApp = (args.installFlags
+                                & PackageManager.INSTALL_DONT_KILL_APP) == 0;
                         final String[] grantedPermissions = args.installGrantPermissions;
 
                         // Handle the parent package
-                        handlePackagePostInstall(parentRes, grantPermissions, grantedPermissions,
-                                args.observer);
+                        handlePackagePostInstall(parentRes, grantPermissions, killApp,
+                                grantedPermissions, args.observer);
 
                         // Handle the child packages
                         final int childCount = (parentRes.addedChildPackages != null)
                                 ? parentRes.addedChildPackages.size() : 0;
                         for (int i = 0; i < childCount; i++) {
                             PackageInstalledInfo childRes = parentRes.addedChildPackages.valueAt(i);
-                            handlePackagePostInstall(childRes, grantPermissions, grantedPermissions,
-                                    args.observer);
+                            handlePackagePostInstall(childRes, grantPermissions, killApp,
+                                    grantedPermissions, args.observer);
                         }
 
                         // Log tracing if needed
@@ -1633,11 +1639,12 @@ public class PackageManagerService extends IPackageManager.Stub {
     }
 
     private void handlePackagePostInstall(PackageInstalledInfo res, boolean grantPermissions,
-            String[] grantedPermissions, IPackageInstallObserver2 installObserver) {
+            boolean killApp, String[] grantedPermissions,
+            IPackageInstallObserver2 installObserver) {
         if (res.returnCode == PackageManager.INSTALL_SUCCEEDED) {
             // Send the removed broadcasts
             if (res.removedInfo != null) {
-                res.removedInfo.sendPackageRemovedBroadcasts();
+                res.removedInfo.sendPackageRemovedBroadcasts(killApp);
             }
 
             // Now that we successfully installed the package, grant runtime
@@ -2159,10 +2166,12 @@ public class PackageManagerService extends IPackageManager.Stub {
                         }
 
                         try {
-                            int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
+                            // Shared libraries do not have profiles so we perform a full
+                            // AOT compilation (if needed).
+                            int dexoptNeeded = DexFile.getDexOptNeeded(
+                                    lib, dexCodeInstructionSet,
+                                    DexFile.COMPILATION_TYPE_FULL);
                             if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
-                                // Shared libraries do not have profiles so we perform a full
-                                // AOT compilation.
                                 mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
                                         dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/,
                                         StorageManager.UUID_PRIVATE_INTERNAL,
@@ -2888,7 +2897,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     @Override
     public boolean isPackageAvailable(String packageName, int userId) {
         if (!sUserManager.exists(userId)) return false;
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "is package available");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "is package available");
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
             if (p != null) {
@@ -2908,7 +2918,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForPackage(flags, userId, packageName);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get package info");
         // reader
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
@@ -2954,7 +2965,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     public int getPackageUid(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return -1;
         flags = updateFlagsForPackage(flags, userId, packageName);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package uid");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get package uid");
 
         // reader
         synchronized (mPackages) {
@@ -2977,7 +2989,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     public int[] getPackageGids(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForPackage(flags, userId, packageName);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */,
                 "getPackageGids");
 
         // reader
@@ -3117,7 +3130,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForApplication(flags, userId, packageName);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get application info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get application info");
         // writer
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
@@ -3332,7 +3346,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get activity info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get activity info");
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
 
@@ -3377,7 +3392,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get receiver info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get receiver info");
         synchronized (mPackages) {
             PackageParser.Activity a = mReceivers.mActivities.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
@@ -3396,7 +3412,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get service info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get service info");
         synchronized (mPackages) {
             PackageParser.Service s = mServices.mServices.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
@@ -3415,7 +3432,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForComponent(flags, userId, component);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get provider info");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "get provider info");
         synchronized (mPackages) {
             PackageParser.Provider p = mProviders.mProviders.get(component);
             if (DEBUG_PACKAGE_INFO) Log.v(
@@ -3807,7 +3825,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                 android.Manifest.permission.GRANT_RUNTIME_PERMISSIONS,
                 "grantRuntimePermission");
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "grantRuntimePermission");
 
         final int uid;
@@ -3918,7 +3937,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                 android.Manifest.permission.REVOKE_RUNTIME_PERMISSIONS,
                 "revokeRuntimePermission");
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "revokeRuntimePermission");
 
         final int appId;
@@ -4022,7 +4042,8 @@ public class PackageManagerService extends IPackageManager.Stub {
 
         enforceGrantRevokeRuntimePermissionPermissions("getPermissionFlags");
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
                 "getPermissionFlags");
 
         synchronized (mPackages) {
@@ -4055,7 +4076,8 @@ public class PackageManagerService extends IPackageManager.Stub {
 
         enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlags");
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "updatePermissionFlags");
 
         // Only the system can change these flags and nothing else.
@@ -4112,7 +4134,8 @@ public class PackageManagerService extends IPackageManager.Stub {
 
         enforceGrantRevokeRuntimePermissionPermissions("updatePermissionFlagsForAllApps");
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "updatePermissionFlagsForAllApps");
 
         // Only the system can change system fixed flags.
@@ -4218,7 +4241,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                 // TODO: remove these terrible hacks
                 if (actionName.startsWith("android.net.netmon.lingerExpired")
                         || actionName.startsWith("com.android.server.sip.SipWakeupTimer")
-                        || actionName.startsWith("com.android.internal.telephony.data-reconnect")) {
+                        || actionName.startsWith("com.android.internal.telephony.data-reconnect")
+                        || actionName.startsWith("android.net.netmon.launchCaptivePortalApp")) {
                     return true;
                 }
             }
@@ -4545,7 +4569,8 @@ public class PackageManagerService extends IPackageManager.Stub {
             int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
         flags = updateFlagsForResolve(flags, userId, intent);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */, "resolve intent");
         List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
         final ResolveInfo bestChoice =
                 chooseBestActivity(intent, resolvedType, flags, query, userId);
@@ -5006,7 +5031,9 @@ public class PackageManagerService extends IPackageManager.Stub {
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
         flags = updateFlagsForResolve(flags, userId, intent);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */,
+                "query intent activities");
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5496,8 +5523,9 @@ public class PackageManagerService extends IPackageManager.Stub {
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
         flags = updateFlagsForResolve(flags, userId, intent);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
-                false, "query intent activity options");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                false /* requireFullPermission */, false /* checkShell */,
+                "query intent activity options");
         final String resultsAction = intent.getAction();
 
         List<ResolveInfo> results = queryIntentActivities(intent, resolvedType, flags
@@ -5798,7 +5826,9 @@ public class PackageManagerService extends IPackageManager.Stub {
         if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
         flags = updateFlagsForPackage(flags, userId, null);
         final boolean listUninstalled = (flags & MATCH_UNINSTALLED_PACKAGES) != 0;
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "get installed packages");
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
+                "get installed packages");
 
         // writer
         synchronized (mPackages) {
@@ -5950,7 +5980,8 @@ public class PackageManagerService extends IPackageManager.Stub {
 
         mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS,
                 "getEphemeralApplications");
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
                 "getEphemeralApplications");
         synchronized (mPackages) {
             List<EphemeralApplicationInfo> ephemeralApps = mEphemeralApplicationRegistry
@@ -5964,7 +5995,8 @@ public class PackageManagerService extends IPackageManager.Stub {
 
     @Override
     public boolean isEphemeralApplication(String packageName, int userId) {
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
                 "isEphemeral");
         if (DISABLE_EPHEMERAL_APPS) {
             return false;
@@ -5988,7 +6020,8 @@ public class PackageManagerService extends IPackageManager.Stub {
             return null;
         }
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
                 "getCookie");
         if (!isCallerSameApp(packageName)) {
             return null;
@@ -6005,7 +6038,8 @@ public class PackageManagerService extends IPackageManager.Stub {
             return true;
         }
 
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "setCookie");
         if (!isCallerSameApp(packageName)) {
             return false;
@@ -6024,7 +6058,8 @@ public class PackageManagerService extends IPackageManager.Stub {
 
         mContext.enforceCallingOrSelfPermission(Manifest.permission.ACCESS_EPHEMERAL_APPS,
                 "getEphemeralApplicationIcon");
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
                 "getEphemeralApplicationIcon");
         synchronized (mPackages) {
             return mEphemeralApplicationRegistry.getEphemeralApplicationIconLPw(
@@ -6047,9 +6082,16 @@ public class PackageManagerService extends IPackageManager.Stub {
             final int userId = UserHandle.getCallingUserId();
             while (i.hasNext()) {
                 final PackageParser.Package p = i.next();
-                if (p.applicationInfo != null
-                        && (p.applicationInfo.flags&ApplicationInfo.FLAG_PERSISTENT) != 0
-                        && (!mSafeMode || isSystemApp(p))) {
+                if (p.applicationInfo == null) continue;
+
+                final boolean matchesUnaware = ((flags & MATCH_ENCRYPTION_UNAWARE) != 0)
+                        && !p.applicationInfo.isEncryptionAware();
+                final boolean matchesAware = ((flags & MATCH_ENCRYPTION_AWARE) != 0)
+                        && p.applicationInfo.isEncryptionAware();
+
+                if ((p.applicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0
+                        && (!mSafeMode || isSystemApp(p))
+                        && (matchesUnaware || matchesAware)) {
                     PackageSetting ps = mSettings.mPackages.get(p.packageName);
                     if (ps != null) {
                         ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags,
@@ -6803,7 +6845,7 @@ public class PackageManagerService extends IPackageManager.Stub {
 
         // Extract pacakges only if profile-guided compilation is enabled because
         // otherwise BackgroundDexOptService will not dexopt them later.
-        if (!mUseJitProfiles || !isUpgrade()) {
+        if (!isUpgrade()) {
             return;
         }
 
@@ -6885,10 +6927,6 @@ public class PackageManagerService extends IPackageManager.Stub {
 
             targetInstructionSet = instructionSet != null ? instructionSet :
                     getPrimaryInstructionSet(p.applicationInfo);
-            if (!force && !useProfiles && p.mDexOptPerformed.contains(targetInstructionSet)) {
-                // Skip only if we do not use profiles since they might trigger a recompilation.
-                return false;
-            }
         }
         long callingId = Binder.clearCallingIdentity();
         try {
@@ -7869,13 +7907,17 @@ public class PackageManagerService extends IPackageManager.Stub {
         // Request the ActivityManager to kill the process(only for existing packages)
         // so that we do not end up in a confused state while the user is still using the older
         // version of the application while the new one gets installed.
-        if ((scanFlags & SCAN_REPLACING) != 0) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "killApplication");
+        final boolean isReplacing = (scanFlags & SCAN_REPLACING) != 0;
+        final boolean killApp = (scanFlags & SCAN_DONT_KILL_APP) == 0;
+        if (killApp) {
+            if (isReplacing) {
+                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "killApplication");
 
-            killApplication(pkg.applicationInfo.packageName,
-                        pkg.applicationInfo.uid, "replace pkg");
+                killApplication(pkg.applicationInfo.packageName,
+                            pkg.applicationInfo.uid, "replace pkg");
 
-            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            }
         }
 
         // Also need to kill any apps that are dependent on the library.
@@ -10376,21 +10418,13 @@ public class PackageManagerService extends IPackageManager.Stub {
     }
 
     @Override
-    public void installPackage(String originPath, IPackageInstallObserver2 observer,
-            int installFlags, String installerPackageName, VerificationParams verificationParams,
-            String packageAbiOverride) {
-        installPackageAsUser(originPath, observer, installFlags, installerPackageName,
-                verificationParams, packageAbiOverride, UserHandle.getCallingUserId());
-    }
-
-    @Override
     public void installPackageAsUser(String originPath, IPackageInstallObserver2 observer,
-            int installFlags, String installerPackageName, VerificationParams verificationParams,
-            String packageAbiOverride, int userId) {
+            int installFlags, String installerPackageName, int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES, null);
 
         final int callingUid = Binder.getCallingUid();
-        enforceCrossUserPermission(callingUid, userId, true, true, "installPackageAsUser");
+        enforceCrossUserPermission(callingUid, userId,
+                true /* requireFullPermission */, true /* checkShell */, "installPackageAsUser");
 
         if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
             try {
@@ -10429,14 +10463,15 @@ public class PackageManagerService extends IPackageManager.Stub {
                     + "to use the PackageManager.INSTALL_GRANT_RUNTIME_PERMISSIONS flag");
         }
 
-        verificationParams.setInstallerUid(callingUid);
-
         final File originFile = new File(originPath);
         final OriginInfo origin = OriginInfo.fromUntrustedFile(originFile);
 
         final Message msg = mHandler.obtainMessage(INIT_COPY);
-        final InstallParams params = new InstallParams(origin, null, observer, installFlags,
-                installerPackageName, null, verificationParams, user, packageAbiOverride, null);
+        final VerificationInfo verificationInfo = new VerificationInfo(
+                null /*originatingUri*/, null /*referrer*/, -1 /*originatingUid*/, callingUid);
+        final InstallParams params = new InstallParams(origin, null /*moveInfo*/, observer,
+                installFlags, installerPackageName, null /*volumeUuid*/, verificationInfo, user,
+                null /*packageAbiOverride*/, null /*grantedPermissions*/);
         params.setTraceMethod("installAsUser").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -10456,10 +10491,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                 Slog.d(TAG, "Ephemeral install of " + packageName);
             }
         }
-        final VerificationParams verifParams = new VerificationParams(
-                null, sessionParams.originatingUri, sessionParams.referrerUri,
-                sessionParams.originatingUid);
-        verifParams.setInstallerUid(installerUid);
+        final VerificationInfo verificationInfo = new VerificationInfo(
+                sessionParams.originatingUri, sessionParams.referrerUri,
+                sessionParams.originatingUid, installerUid);
 
         final OriginInfo origin;
         if (stagedDir != null) {
@@ -10471,7 +10505,7 @@ public class PackageManagerService extends IPackageManager.Stub {
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         final InstallParams params = new InstallParams(origin, null, observer,
                 sessionParams.installFlags, installerPackageName, sessionParams.volumeUuid,
-                verifParams, user, sessionParams.abiOverride,
+                verificationInfo, user, sessionParams.abiOverride,
                 sessionParams.grantedRuntimePermissions);
         params.setTraceMethod("installStage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
@@ -10521,7 +10555,8 @@ public class PackageManagerService extends IPackageManager.Stub {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
         PackageSetting pkgSetting;
         final int uid = Binder.getCallingUid();
-        enforceCrossUserPermission(uid, userId, true, true,
+        enforceCrossUserPermission(uid, userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "setApplicationHiddenSetting for user " + userId);
 
         if (hidden && isPackageDeviceAdmin(packageName, userId)) {
@@ -10571,7 +10606,7 @@ public class PackageManagerService extends IPackageManager.Stub {
         info.removedPackage = packageName;
         info.removedUsers = new int[] {userId};
         info.uid = UserHandle.getUid(userId, pkgSetting.appId);
-        info.sendPackageRemovedBroadcasts();
+        info.sendPackageRemovedBroadcasts(true /*killApp*/);
     }
 
     private void sendPackagesSuspendedForUser(String[] pkgList, int userId, boolean suspended) {
@@ -10594,8 +10629,9 @@ public class PackageManagerService extends IPackageManager.Stub {
     @Override
     public boolean getApplicationHiddenSettingAsUser(String packageName, int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true,
-                false, "getApplicationHidden for user " + userId);
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
+                "getApplicationHidden for user " + userId);
         PackageSetting pkgSetting;
         long callingId = Binder.clearCallingIdentity();
         try {
@@ -10621,8 +10657,9 @@ public class PackageManagerService extends IPackageManager.Stub {
                 null);
         PackageSetting pkgSetting;
         final int uid = Binder.getCallingUid();
-        enforceCrossUserPermission(uid, userId, true, true, "installExistingPackage for user "
-                + userId);
+        enforceCrossUserPermission(uid, userId,
+                true /* requireFullPermission */, true /* checkShell */,
+                "installExistingPackage for user " + userId);
         if (isUserRestricted(userId, UserManager.DISALLOW_INSTALL_APPS)) {
             return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
         }
@@ -10671,7 +10708,8 @@ public class PackageManagerService extends IPackageManager.Stub {
     public String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,
             int userId) {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, true,
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, true /* checkShell */,
                 "setPackagesSuspended for user " + userId);
 
         if (ArrayUtils.isEmpty(packageNames)) {
@@ -10729,8 +10767,9 @@ public class PackageManagerService extends IPackageManager.Stub {
 
     @Override
     public boolean isPackageSuspendedForUser(String packageName, int userId) {
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true,
-                false, "isPackageSuspendedForUser for user " + userId);
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */,
+                "isPackageSuspendedForUser for user " + userId);
         synchronized (mPackages) {
             final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
             return pkgSetting != null && pkgSetting.getSuspended(userId);
@@ -11506,6 +11545,30 @@ public class PackageManagerService extends IPackageManager.Stub {
         }
     }
 
+    static class VerificationInfo {
+        /** A constant used to indicate that a uid value is not present. */
+        public static final int NO_UID = -1;
+
+        /** URI referencing where the package was downloaded from. */
+        final Uri originatingUri;
+
+        /** HTTP referrer URI associated with the originatingURI. */
+        final Uri referrer;
+
+        /** UID of the application that the install request originated from. */
+        final int originatingUid;
+
+        /** UID of application requesting the install */
+        final int installerUid;
+
+        VerificationInfo(Uri originatingUri, Uri referrer, int originatingUid, int installerUid) {
+            this.originatingUri = originatingUri;
+            this.referrer = referrer;
+            this.originatingUid = originatingUid;
+            this.installerUid = installerUid;
+        }
+    }
+
     class InstallParams extends HandlerParams {
         final OriginInfo origin;
         final MoveInfo move;
@@ -11513,15 +11576,15 @@ public class PackageManagerService extends IPackageManager.Stub {
         int installFlags;
         final String installerPackageName;
         final String volumeUuid;
-        final VerificationParams verificationParams;
         private InstallArgs mArgs;
         private int mRet;
         final String packageAbiOverride;
         final String[] grantedRuntimePermissions;
+        final VerificationInfo verificationInfo;
 
         InstallParams(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, String installerPackageName, String volumeUuid,
-                VerificationParams verificationParams, UserHandle user, String packageAbiOverride,
+                VerificationInfo verificationInfo, UserHandle user, String packageAbiOverride,
                 String[] grantedPermissions) {
             super(user);
             this.origin = origin;
@@ -11530,7 +11593,7 @@ public class PackageManagerService extends IPackageManager.Stub {
             this.installFlags = installFlags;
             this.installerPackageName = installerPackageName;
             this.volumeUuid = volumeUuid;
-            this.verificationParams = verificationParams;
+            this.verificationInfo = verificationInfo;
             this.packageAbiOverride = packageAbiOverride;
             this.grantedRuntimePermissions = grantedPermissions;
         }
@@ -11794,26 +11857,22 @@ public class PackageManagerService extends IPackageManager.Stub {
                     verification.putExtra(PackageManager.EXTRA_VERIFICATION_VERSION_CODE,
                             pkgLite.versionCode);
 
-                    if (verificationParams != null) {
-                        if (verificationParams.getVerificationURI() != null) {
-                           verification.putExtra(PackageManager.EXTRA_VERIFICATION_URI,
-                                 verificationParams.getVerificationURI());
-                        }
-                        if (verificationParams.getOriginatingURI() != null) {
+                    if (verificationInfo != null) {
+                        if (verificationInfo.originatingUri != null) {
                             verification.putExtra(Intent.EXTRA_ORIGINATING_URI,
-                                  verificationParams.getOriginatingURI());
+                                    verificationInfo.originatingUri);
                         }
-                        if (verificationParams.getReferrer() != null) {
+                        if (verificationInfo.referrer != null) {
                             verification.putExtra(Intent.EXTRA_REFERRER,
-                                  verificationParams.getReferrer());
+                                    verificationInfo.referrer);
                         }
-                        if (verificationParams.getOriginatingUid() >= 0) {
+                        if (verificationInfo.originatingUid >= 0) {
                             verification.putExtra(Intent.EXTRA_ORIGINATING_UID,
-                                  verificationParams.getOriginatingUid());
+                                    verificationInfo.originatingUid);
                         }
-                        if (verificationParams.getInstallerUid() >= 0) {
+                        if (verificationInfo.installerUid >= 0) {
                             verification.putExtra(PackageManager.EXTRA_VERIFICATION_INSTALLER_UID,
-                                  verificationParams.getInstallerUid());
+                                    verificationInfo.installerUid);
                         }
                     }
 
@@ -13030,6 +13089,15 @@ public class PackageManagerService extends IPackageManager.Stub {
         }
     }
 
+    public List<String> getPreviousCodePaths(String packageName) {
+        final PackageSetting ps = mSettings.mPackages.get(packageName);
+        final List<String> result = new ArrayList<String>();
+        if (ps != null && ps.oldCodePaths != null) {
+            result.addAll(ps.oldCodePaths);
+        }
+        return result;
+    }
+
     private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
             PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
             int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
@@ -13039,12 +13107,16 @@ public class PackageManagerService extends IPackageManager.Stub {
         String pkgName = deletedPackage.packageName;
         boolean deletedPkg = true;
         boolean addedPkg = false;
+        boolean updatedSettings = false;
+        final boolean killApp = (scanFlags & SCAN_DONT_KILL_APP) == 0;
+        final int deleteFlags = PackageManager.DELETE_KEEP_DATA
+                | (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
 
         final long origUpdateTime = (pkg.mExtras != null)
                 ? ((PackageSetting)pkg.mExtras).lastUpdateTime : 0;
 
         // First delete the existing package while retaining the data directory
-        if (!deletePackageLI(pkgName, null, true, allUsers, PackageManager.DELETE_KEEP_DATA,
+        if (!deletePackageLI(pkgName, null, true, allUsers, deleteFlags,
                 res.removedInfo, true, pkg)) {
             // If the existing package wasn't successfully deleted
             res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE, "replaceNonSystemPackageLI");
@@ -13070,6 +13142,27 @@ public class PackageManagerService extends IPackageManager.Stub {
                 final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
                         scanFlags | SCAN_UPDATE_TIME, System.currentTimeMillis(), user);
                 updateSettingsLI(newPackage, installerPackageName, allUsers, res, user);
+
+                // Update the in-memory copy of the previous code paths.
+                PackageSetting ps = mSettings.mPackages.get(pkgName);
+                if (!killApp) {
+                    if (ps.oldCodePaths == null) {
+                        ps.oldCodePaths = new ArraySet<>();
+                    }
+                    Collections.addAll(ps.oldCodePaths, deletedPackage.baseCodePath);
+                    if (deletedPackage.splitCodePaths != null) {
+                        Collections.addAll(ps.oldCodePaths, deletedPackage.splitCodePaths);
+                    }
+                } else {
+                    ps.oldCodePaths = null;
+                }
+                if (ps.childPackageNames != null) {
+                    for (int i = ps.childPackageNames.size() - 1; i >= 0; --i) {
+                        final String childPkgName = ps.childPackageNames.get(i);
+                        final PackageSetting childPs = mSettings.mPackages.get(childPkgName);
+                        childPs.oldCodePaths = ps.oldCodePaths;
+                    }
+                }
                 prepareAppDataAfterInstall(newPackage);
                 addedPkg = true;
             } catch (PackageManagerException e) {
@@ -13082,7 +13175,7 @@ public class PackageManagerService extends IPackageManager.Stub {
 
             // Revert all internal state mutations and added folders for the failed install
             if (addedPkg) {
-                deletePackageLI(pkgName, null, true, allUsers, PackageManager.DELETE_KEEP_DATA,
+                deletePackageLI(pkgName, null, true, allUsers, deleteFlags,
                         res.removedInfo, true, null);
             }
 
@@ -13303,18 +13396,21 @@ public class PackageManagerService extends IPackageManager.Stub {
         return null;
     }
 
-    private void removeNativeBinariesLI(PackageParser.Package pkg) {
+    private void removeNativeBinariesLI(PackageSetting ps) {
         // Remove the lib path for the parent package
-        PackageSetting ps = (PackageSetting) pkg.mExtras;
         if (ps != null) {
             NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
-        }
-        // Remove the lib path for the child packages
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
-        for (int i = 0; i < childCount; i++) {
-            ps = (PackageSetting) pkg.childPackages.get(i).mExtras;
-            if (ps != null) {
-                NativeLibraryHelper.removeNativeBinariesLI(ps.legacyNativeLibraryPathString);
+            // Remove the lib path for the child packages
+            final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
+            for (int i = 0; i < childCount; i++) {
+                PackageSetting childPs = null;
+                synchronized (mPackages) {
+                    childPs = mSettings.peekPackageLPr(ps.childPackageNames.get(i));
+                }
+                if (childPs != null) {
+                    NativeLibraryHelper.removeNativeBinariesLI(childPs
+                            .legacyNativeLibraryPathString);
+                }
             }
         }
     }
@@ -13532,6 +13628,9 @@ public class PackageManagerService extends IPackageManager.Stub {
             // moving a complete application; perform an initial scan on the new install location
             scanFlags |= SCAN_INITIAL;
         }
+        if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+            scanFlags |= SCAN_DONT_KILL_APP;
+        }
 
         // Result object to be returned
         res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
@@ -13798,21 +13897,17 @@ public class PackageManagerService extends IPackageManager.Stub {
                 return;
             }
 
-            // Extract package to save the VM unzipping the APK in memory during
-            // launch. Only do this if profile-guided compilation is enabled because
-            // otherwise BackgroundDexOptService will not dexopt the package later.
-            if (mUseJitProfiles) {
-                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
-                // Do not run PackageDexOptimizer through the local performDexOpt
-                // method because `pkg` is not in `mPackages` yet.
-                int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
-                        false /* useProfiles */, true /* extractOnly */);
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-                if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
-                    String msg = "Extracking package failed for " + pkgName;
-                    res.setError(INSTALL_FAILED_DEXOPT, msg);
-                    return;
-                }
+
+            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "dexopt");
+            // Do not run PackageDexOptimizer through the local performDexOpt
+            // method because `pkg` is not in `mPackages` yet.
+            int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instructionSets */,
+                    false /* useProfiles */, true /* extractOnly */);
+            Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
+            if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
+                String msg = "Extracking package failed for " + pkgName;
+                res.setError(INSTALL_FAILED_DEXOPT, msg);
+                return;
             }
         }
 
@@ -14099,25 +14194,48 @@ public class PackageManagerService extends IPackageManager.Stub {
             return;
         }
 
-        for (int currentUserId : users) {
-            if (getBlockUninstallForUser(packageName, currentUserId)) {
-                try {
-                    observer.onPackageDeleted(packageName,
-                            PackageManager.DELETE_FAILED_OWNER_BLOCKED, null);
-                } catch (RemoteException re) {
-                }
-                return;
+        if (!deleteAllUsers && getBlockUninstallForUser(packageName, userId)) {
+            try {
+                observer.onPackageDeleted(packageName,
+                        PackageManager.DELETE_FAILED_OWNER_BLOCKED, null);
+            } catch (RemoteException re) {
             }
+            return;
         }
 
         if (DEBUG_REMOVE) {
-            Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId);
+            Slog.d(TAG, "deletePackageAsUser: pkg=" + packageName + " user=" + userId
+                    + " deleteAllUsers: " + deleteAllUsers );
         }
         // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(new Runnable() {
             public void run() {
                 mHandler.removeCallbacks(this);
-                final int returnCode = deletePackageX(packageName, userId, flags);
+                int returnCode;
+                if (!deleteAllUsers) {
+                    returnCode = deletePackageX(packageName, userId, flags);
+                } else {
+                    int[] blockUninstallUserIds = getBlockUninstallForUsers(packageName, users);
+                    // If nobody is blocking uninstall, proceed with delete for all users
+                    if (ArrayUtils.isEmpty(blockUninstallUserIds)) {
+                        returnCode = deletePackageX(packageName, userId, flags);
+                    } else {
+                        // Otherwise uninstall individually for users with blockUninstalls=false
+                        final int userFlags = flags & ~PackageManager.DELETE_ALL_USERS;
+                        for (int userId : users) {
+                            if (!ArrayUtils.contains(blockUninstallUserIds, userId)) {
+                                returnCode = deletePackageX(packageName, userId, userFlags);
+                                if (returnCode != PackageManager.DELETE_SUCCEEDED) {
+                                    Slog.w(TAG, "Package delete failed for user " + userId
+                                            + ", returnCode " + returnCode);
+                                }
+                            }
+                        }
+                        // The app has only been marked uninstalled for certain users.
+                        // We still need to report that delete was blocked
+                        returnCode = PackageManager.DELETE_FAILED_OWNER_BLOCKED;
+                    }
+                }
                 try {
                     observer.onPackageDeleted(packageName, returnCode, null);
                 } catch (RemoteException e) {
@@ -14127,6 +14245,16 @@ public class PackageManagerService extends IPackageManager.Stub {
         });
     }
 
+    private int[] getBlockUninstallForUsers(String packageName, int[] userIds) {
+        int[] result = EMPTY_INT_ARRAY;
+        for (int userId : userIds) {
+            if (getBlockUninstallForUser(packageName, userId)) {
+                result = ArrayUtils.appendInt(result, userId);
+            }
+        }
+        return result;
+    }
+
     @Override
     public boolean isPackageDeviceAdminOnAnyUser(String packageName) {
         return isPackageDeviceAdmin(packageName, UserHandle.USER_ALL);
@@ -14223,7 +14351,8 @@ public class PackageManagerService extends IPackageManager.Stub {
         }
 
         if (res) {
-            info.sendPackageRemovedBroadcasts();
+            final boolean killApp = (flags & PackageManager.INSTALL_DONT_KILL_APP) == 0;
+            info.sendPackageRemovedBroadcasts(killApp);
             info.sendSystemPackageUpdatedBroadcasts();
             info.sendSystemPackageAppearedBroadcasts();
         }
@@ -14255,12 +14384,12 @@ public class PackageManagerService extends IPackageManager.Stub {
         ArrayMap<String, PackageRemovedInfo> removedChildPackages;
         ArrayMap<String, PackageInstalledInfo> appearedChildPackages;
 
-        void sendPackageRemovedBroadcasts() {
-            sendPackageRemovedBroadcastInternal();
+        void sendPackageRemovedBroadcasts(boolean killApp) {
+            sendPackageRemovedBroadcastInternal(killApp);
             final int childCount = removedChildPackages != null ? removedChildPackages.size() : 0;
             for (int i = 0; i < childCount; i++) {
                 PackageRemovedInfo childInfo = removedChildPackages.valueAt(i);
-                childInfo.sendPackageRemovedBroadcastInternal();
+                childInfo.sendPackageRemovedBroadcastInternal(killApp);
             }
         }
 
@@ -14302,10 +14431,11 @@ public class PackageManagerService extends IPackageManager.Stub {
                     null, 0, removedPackage, null, null);
         }
 
-        private void sendPackageRemovedBroadcastInternal() {
+        private void sendPackageRemovedBroadcastInternal(boolean killApp) {
             Bundle extras = new Bundle(2);
             extras.putInt(Intent.EXTRA_UID, removedAppId >= 0  ? removedAppId : uid);
             extras.putBoolean(Intent.EXTRA_DATA_REMOVED, dataRemoved);
+            extras.putBoolean(Intent.EXTRA_DONT_KILL_APP, !killApp);
             if (isUpdate || isRemovedPackageSystemUpdate) {
                 extras.putBoolean(Intent.EXTRA_REPLACING, true);
             }
@@ -14437,7 +14567,7 @@ public class PackageManagerService extends IPackageManager.Stub {
     private boolean deleteSystemPackageLI(PackageParser.Package deletedPkg,
             PackageSetting deletedPs, int[] allUserHandles, int flags, PackageRemovedInfo outInfo,
             boolean writeSettings) {
-        if (deletedPkg.parentPackage != null) {
+        if (deletedPs.parentPackageName != null) {
             Slog.w(TAG, "Attempt to delete child system package " + deletedPkg.packageName);
             return false;
         }
@@ -14450,7 +14580,7 @@ public class PackageManagerService extends IPackageManager.Stub {
         // the system pkg from system partition
         // reader
         synchronized (mPackages) {
-            disabledPs = mSettings.getDisabledSystemPkgLPr(deletedPkg.packageName);
+            disabledPs = mSettings.getDisabledSystemPkgLPr(deletedPs.name);
         }
 
         if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName
@@ -14476,10 +14606,10 @@ public class PackageManagerService extends IPackageManager.Stub {
         // Delete the updated package
         outInfo.isRemovedPackageSystemUpdate = true;
         if (outInfo.removedChildPackages != null) {
-            final int childCount = (deletedPkg.childPackages != null)
-                    ? deletedPkg.childPackages.size() : 0;
+            final int childCount = (deletedPs.childPackageNames != null)
+                    ? deletedPs.childPackageNames.size() : 0;
             for (int i = 0; i < childCount; i++) {
-                String childPackageName = deletedPkg.childPackages.get(i).packageName;
+                String childPackageName = deletedPs.childPackageNames.get(i);
                 if (disabledPs.childPackageNames != null && disabledPs.childPackageNames
                         .contains(childPackageName)) {
                     PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
@@ -14499,7 +14629,7 @@ public class PackageManagerService extends IPackageManager.Stub {
             flags |= PackageManager.DELETE_KEEP_DATA;
         }
 
-        boolean ret = deleteInstalledPackageLI(deletedPkg, true, flags, allUserHandles,
+        boolean ret = deleteInstalledPackageLI(deletedPs, true, flags, allUserHandles,
                 outInfo, writeSettings, disabledPs.pkg);
         if (!ret) {
             return false;
@@ -14510,7 +14640,7 @@ public class PackageManagerService extends IPackageManager.Stub {
             // Reinstate the old system package
             enableSystemPackageLPw(disabledPs.pkg);
             // Remove any native libraries from the upgraded package.
-            removeNativeBinariesLI(deletedPkg);
+            removeNativeBinariesLI(deletedPs);
         }
 
         // Install the system package
@@ -14567,29 +14697,18 @@ public class PackageManagerService extends IPackageManager.Stub {
         return true;
     }
 
-    private boolean deleteInstalledPackageLI(PackageParser.Package pkg,
+    private boolean deleteInstalledPackageLI(PackageSetting ps,
             boolean deleteCodeAndResources, int flags, int[] allUserHandles,
             PackageRemovedInfo outInfo, boolean writeSettings,
             PackageParser.Package replacingPackage) {
-        PackageSetting ps = null;
-
         synchronized (mPackages) {
-            pkg = mPackages.get(pkg.packageName);
-            if (pkg == null) {
-                return false;
-            }
-
-            ps = mSettings.mPackages.get(pkg.packageName);
-            if (ps == null) {
-                return false;
-            }
-
             if (outInfo != null) {
                 outInfo.uid = ps.appId;
             }
 
             if (outInfo != null && outInfo.removedChildPackages != null) {
-                final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+                final int childCount = (ps.childPackageNames != null)
+                        ? ps.childPackageNames.size() : 0;
                 for (int i = 0; i < childCount; i++) {
                     String childPackageName = ps.childPackageNames.get(i);
                     PackageSetting childPs = mSettings.mPackages.get(childPackageName);
@@ -14609,11 +14728,11 @@ public class PackageManagerService extends IPackageManager.Stub {
         removePackageDataLI(ps, allUserHandles, outInfo, flags, writeSettings);
 
         // Delete the child packages data
-        final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
+        final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
         for (int i = 0; i < childCount; i++) {
             PackageSetting childPs;
             synchronized (mPackages) {
-                childPs = mSettings.peekPackageLPr(pkg.childPackages.get(i).packageName);
+                childPs = mSettings.peekPackageLPr(ps.childPackageNames.get(i));
             }
             if (childPs != null) {
                 PackageRemovedInfo childOutInfo = (outInfo != null
@@ -14629,7 +14748,7 @@ public class PackageManagerService extends IPackageManager.Stub {
         }
 
         // Delete application code and resources only for parent packages
-        if (ps.pkg.parentPackage == null) {
+        if (ps.parentPackageName == null) {
             if (deleteCodeAndResources && (outInfo != null)) {
                 outInfo.args = createInstallArgsForExisting(packageFlagsToInstallFlags(ps),
                         ps.codePathString, ps.resourcePathString, getAppDexInstructionSets(ps));
@@ -14720,7 +14839,7 @@ public class PackageManagerService extends IPackageManager.Stub {
                 return false;
             }
 
-            if (ps.pkg != null && ps.pkg.parentPackage != null && (!isSystemApp(ps)
+            if (ps.parentPackageName != null && (!isSystemApp(ps)
                     || (flags & PackageManager.DELETE_SYSTEM_APP) != 0)) {
                 if (DEBUG_REMOVE) {
                     Slog.d(TAG, "Uninstalled child package:" + packageName + " for user:"
@@ -14807,8 +14926,11 @@ public class PackageManagerService extends IPackageManager.Stub {
         } else {
             if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
             // Kill application pre-emptively especially for apps on sd.
-            killApplication(packageName, ps.appId, "uninstall pkg");
-            ret = deleteInstalledPackageLI(ps.pkg, deleteCodeAndResources, flags, allUserHandles,
+            final boolean killApp = (flags & PackageManager.DELETE_DONT_KILL_APP) == 0;
+            if (killApp) {
+                killApplication(packageName, ps.appId, "uninstall pkg");
+            }
+            ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, allUserHandles,
                     outInfo, writeSettings, replacingPackage);
         }
 
@@ -14989,7 +15111,15 @@ public class PackageManagerService extends IPackageManager.Stub {
             final IPackageDataObserver observer, final int userId) {
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.CLEAR_APP_USER_DATA, null);
-        enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "clear application data");
+
+        enforceCrossUserPermission(Binder.getCallingUid(), userId,
+                true /* requireFullPermission */, false /* checkShell */, "clear application data");
+
+        final DevicePolicyManagerInternal dpmi = LocalServices
+                .getService(DevicePolicyManagerInternal.class);
+        if (dpmi != null && dpmi.hasDeviceOwnerOrProfileOwner(packageName, userId)) {
+            throw new SecurityException("Cannot clear data for a device owner or a profile owner");
+        }
         // Queue up an async operation since the package deletion may take a little while.
         mHandler.post(new Runnable() {
             public void run() {
@@ -15001,8 +15131,8 @@ public class PackageManagerService extends IPackageManager.Stub {
                 clearExternalStorageDataSync(packageName, userId, true);
                 if (succeeded) {
                     // invoke DeviceStorageMonitor's update method to clear any notifications
-                    DeviceStorageMonitorInternal
-                            dsm = LocalServices.getService(DeviceStorageMonitorInternal.class);
+                    DeviceStorageMonitorInternal dsm = LocalServices
+                            .getService(DeviceStorageMonitorInternal.class);
                     if (dsm != null) {
                         dsm.checkMemory();
                     }
@@ -15452,7 +15582,8 @@ public class PackageManagerService extends IPackageManager.Stub {
             String opname) {
         // writer
         int callingUid = Binder.getCallingUid();
-        enforceCrossUserPermission(callingUid, userId, true, false, "add preferred activity");
+        enforceCrossUserPermission(callingUid, userId,
+                true /* requireFullPermission */, false /* checkShell */, "add preferred activity");
         if (filter.countActions() == 0) {
             Slog.w(TAG, "Cannot set a preferred activity with no filter actions");
             return;
@@ -15497,7 +15628,9 @@ public class PackageManagerService extends IPackageManager.Stub {
         }
 
         final int callingUid = Binder.getCallingUid();
-        enforceCrossUserPermission(callingUid, userId, true, false, "replace preferred activity");
+        enforceCrossUserPermission(callingUid, userId,
+                true /* requireFullPermission */, false /* checkShell */,
+                "replace preferred activity");
         synchronized (mPackages) {
             if (mContext.checkCallingOrSelfPermission(
                     android.Manifest.permission.SET_PREFERRED_APPLICATIONS)
@@ -16315,7 +16448,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
         final int uid = Binder.getCallingUid();
         final int permission = mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
-        enforceCrossUserPermission(uid, userId, false, true, "set enabled");
+        enforceCrossUserPermission(uid, userId,
+                false /* requireFullPermission */, true /* checkShell */, "set enabled");
         final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
         boolean sendNow = false;
         boolean isApp = (className == null);
@@ -16454,7 +16588,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
         final int permission = mContext.checkCallingOrSelfPermission(
                 android.Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);
         final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
-        enforceCrossUserPermission(uid, userId, true, true, "stop package");
+        enforceCrossUserPermission(uid, userId,
+                true /* requireFullPermission */, true /* checkShell */, "stop package");
         // writer
         synchronized (mPackages) {
             if (mSettings.setPackageStoppedStateLPw(this, packageName, stopped,
@@ -16476,7 +16611,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
     public int getApplicationEnabledSetting(String packageName, int userId) {
         if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int uid = Binder.getCallingUid();
-        enforceCrossUserPermission(uid, userId, false, false, "get enabled");
+        enforceCrossUserPermission(uid, userId,
+                false /* requireFullPermission */, false /* checkShell */, "get enabled");
         // reader
         synchronized (mPackages) {
             return mSettings.getApplicationEnabledSettingLPr(packageName, userId);
@@ -16487,7 +16623,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
     public int getComponentEnabledSetting(ComponentName componentName, int userId) {
         if (!sUserManager.exists(userId)) return COMPONENT_ENABLED_STATE_DISABLED;
         int uid = Binder.getCallingUid();
-        enforceCrossUserPermission(uid, userId, false, false, "get component enabled");
+        enforceCrossUserPermission(uid, userId,
+                false /* requireFullPermission */, false /* checkShell */, "get component enabled");
         // reader
         synchronized (mPackages) {
             return mSettings.getComponentEnabledSettingLPr(componentName, userId);
@@ -18392,7 +18529,8 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
         final Message msg = mHandler.obtainMessage(INIT_COPY);
         final OriginInfo origin = OriginInfo.fromExistingFile(codeFile);
         final InstallParams params = new InstallParams(origin, move, installObserver, installFlags,
-                installerPackageName, volumeUuid, null, user, packageAbiOverride, null);
+                installerPackageName, volumeUuid, null /*verificationInfo*/, user,
+                packageAbiOverride, null);
         params.setTraceMethod("movePackage").setTraceCookie(System.identityHashCode(params));
         msg.obj = params;
 
@@ -19047,6 +19185,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
                 return permissionsState.isPermissionReviewRequired(userId);
             }
         }
+
+        @Override
+        public ApplicationInfo getApplicationInfo(String packageName, int userId) {
+            return PackageManagerService.this.getApplicationInfo(packageName, 0 /*flags*/, userId);
+        }
     }
 
     @Override
@@ -19074,4 +19217,14 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName());
     boolean isHistoricalPackageUsageAvailable() {
         return mPackageUsage.isHistoricalPackageUsageAvailable();
     }
+
+    /**
+     * Return a <b>copy</b> of the collection of packages known to the package manager.
+     * @return A copy of the values of mPackages.
+     */
+    Collection<PackageParser.Package> getPackages() {
+        synchronized (mPackages) {
+            return new ArrayList<>(mPackages.values());
+        }
+    }
 }
index e5eec7e..1434718 100644 (file)
@@ -30,6 +30,7 @@ import android.util.SparseArray;
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Set;
 
 /**
  * Settings base class for pending and resolved classes.
@@ -118,7 +119,14 @@ abstract class PackageSettingBase extends SettingBase {
      * platform will refuse to launch packages in a frozen state.
      */
     boolean frozen = false;
-
+    /**
+     * Non-persisted value. During an "upgrade without restart", we need the set
+     * of all previous code paths so we can surgically add the new APKs to the
+     * active classloader. If at any point an application is upgraded with a
+     * restart, this field will be cleared since the classloader would be created
+     * using the full set of code paths when the package's process is started.
+     */
+    Set<String> oldCodePaths;
     PackageSettingBase origPackage;
 
     /** Package name of the app that installed this package */
index 1652185..bf5a8f6 100644 (file)
@@ -2604,7 +2604,6 @@ final class Settings {
         if (pkg.volumeUuid != null) {
             serializer.attribute(null, "volumeUuid", pkg.volumeUuid);
         }
-
         if (pkg.parentPackageName != null) {
             serializer.attribute(null, "parentPackageName", pkg.parentPackageName);
         }
@@ -3049,7 +3048,7 @@ final class Settings {
             tmpPa.dump(new LogPrinter(Log.DEBUG, TAG), "  ");
         }
         Intent intent = new Intent();
-        int flags = 0;
+        int flags = PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
         intent.setAction(tmpPa.getAction(0));
         for (int i=0; i<tmpPa.countCategories(); i++) {
             String cat = tmpPa.getCategory(i);
@@ -4171,9 +4170,19 @@ final class Settings {
     };
 
     static final Object[] PRIVATE_FLAG_DUMP_SPEC = new Object[] {
-        ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
-        ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+        ApplicationInfo.PRIVATE_FLAG_HIDDEN, "HIDDEN",
         ApplicationInfo.PRIVATE_FLAG_CANT_SAVE_STATE, "CANT_SAVE_STATE",
+        ApplicationInfo.PRIVATE_FLAG_FORWARD_LOCK, "FORWARD_LOCK",
+        ApplicationInfo.PRIVATE_FLAG_PRIVILEGED, "PRIVILEGED",
+        ApplicationInfo.PRIVATE_FLAG_HAS_DOMAIN_URLS, "HAS_DOMAIN_URLS",
+        ApplicationInfo.PRIVATE_FLAG_FORCE_DEVICE_ENCRYPTED, "FORCE_DEVICE_ENCRYPTED",
+        ApplicationInfo.PRIVATE_FLAG_ENCRYPTION_AWARE, "ENCRYPTION_AWARE",
+        ApplicationInfo.PRIVATE_FLAG_AUTOPLAY, "AUTOPLAY",
+        ApplicationInfo.PRIVATE_FLAG_PARTIALLY_ENCRYPTION_AWARE, "PARTIALLY_ENCRYPTION_AWARE",
+        ApplicationInfo.PRIVATE_FLAG_EPHEMERAL, "EPHEMERAL",
+        ApplicationInfo.PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER, "REQUIRED_FOR_SYSTEM_USER",
+        ApplicationInfo.PRIVATE_FLAG_RESIZEABLE_ACTIVITIES, "RESIZEABLE_ACTIVITIES",
+        ApplicationInfo.PRIVATE_FLAG_BACKUP_IN_FOREGROUND, "BACKUP_IN_FOREGROUND",
     };
 
     void dumpVersionLPr(IndentingPrintWriter pw) {
@@ -4316,6 +4325,10 @@ final class Settings {
             }
             pw.print(prefix); pw.print("  versionName="); pw.println(ps.pkg.mVersionName);
             pw.print(prefix); pw.print("  splits="); dumpSplitNames(pw, ps.pkg); pw.println();
+            final int apkSigningVersion = PackageParser.getApkSigningVersion(ps.pkg);
+            if (apkSigningVersion != PackageParser.APK_SIGNING_UNKNOWN) {
+                pw.print(prefix); pw.print("  apkSigningVersion="); pw.println(apkSigningVersion);
+            }
             pw.print(prefix); pw.print("  applicationInfo=");
                 pw.println(ps.pkg.applicationInfo.toString());
             pw.print(prefix); pw.print("  flags="); printFlags(pw, ps.pkg.applicationInfo.flags,
index ff7c790..e51a2e1 100644 (file)
@@ -537,6 +537,7 @@ public class PhoneWindowManager implements WindowManagerPolicy {
     boolean mForceStatusBar;
     boolean mForceStatusBarFromKeyguard;
     private boolean mForceStatusBarTransparent;
+    boolean mForceNavBarOpaque;
     boolean mHideLockScreen;
     boolean mForcingShowNavBar;
     int mForcingShowNavBarLayer;
@@ -1717,6 +1718,9 @@ public class PhoneWindowManager implements WindowManagerPolicy {
         if (mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
             mShortPressWindowBehavior = SHORT_PRESS_WINDOW_PICTURE_IN_PICTURE;
         }
+
+        mForceNavBarOpaque = res.getBoolean(
+                com.android.internal.R.bool.config_forceNavBarAlwaysOpaque);
     }
 
     @Override
@@ -7093,6 +7097,10 @@ public class PhoneWindowManager implements WindowManagerPolicy {
                     | View.SYSTEM_UI_TRANSPARENT);
         }
 
+        if (mForceNavBarOpaque) {
+            vis &= ~(View.NAVIGATION_BAR_TRANSLUCENT | View.NAVIGATION_BAR_TRANSPARENT);
+        }
+
         if (mForceWindowDrawsStatusBarBackground) {
             vis |= View.STATUS_BAR_TRANSPARENT;
             vis &= ~View.STATUS_BAR_TRANSLUCENT;
index 9284442..57ae523 100644 (file)
@@ -138,14 +138,16 @@ class ShortcutManager {
                     ComponentName componentName = new ComponentName(packageName, className);
                     try {
                         info = packageManager.getActivityInfo(componentName,
-                                PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+                                PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE
+                                | PackageManager.MATCH_UNINSTALLED_PACKAGES);
                     } catch (PackageManager.NameNotFoundException e) {
                         String[] packages = packageManager.canonicalToCurrentPackageNames(
                                 new String[] { packageName });
                         componentName = new ComponentName(packages[0], className);
                         try {
                             info = packageManager.getActivityInfo(componentName,
-                                    PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE);
+                                    PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE
+                                    | PackageManager.MATCH_UNINSTALLED_PACKAGES);
                         } catch (PackageManager.NameNotFoundException e1) {
                             Log.w(TAG, "Unable to add bookmark: " + packageName
                                     + "/" + className, e);
index f901f95..6218c4e 100644 (file)
@@ -60,6 +60,7 @@ import android.view.WindowManagerPolicy;
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.app.IBatteryStats;
 import com.android.internal.os.BackgroundThread;
+import com.android.internal.util.ArrayUtils;
 import com.android.server.EventLogTags;
 import com.android.server.ServiceThread;
 import com.android.server.SystemService;
@@ -254,6 +255,9 @@ public final class PowerManagerService extends SystemService
     // True if boot completed occurred.  We keep the screen on until this happens.
     private boolean mBootCompleted;
 
+    // Runnables that should be triggered on boot completed
+    private Runnable[] mBootCompletedRunnables;
+
     // True if auto-suspend mode is enabled.
     // Refer to autosuspend.h.
     private boolean mHalAutoSuspendModeEnabled;
@@ -525,6 +529,14 @@ public final class PowerManagerService extends SystemService
                 userActivityNoUpdateLocked(
                         now, PowerManager.USER_ACTIVITY_EVENT_OTHER, 0, Process.SYSTEM_UID);
                 updatePowerStateLocked();
+
+                if (!ArrayUtils.isEmpty(mBootCompletedRunnables)) {
+                    Slog.d(TAG, "Posting " + mBootCompletedRunnables.length + " delayed runnables");
+                    for (Runnable r : mBootCompletedRunnables) {
+                        BackgroundThread.getHandler().post(r);
+                    }
+                }
+                mBootCompletedRunnables = null;
             }
         }
     }
@@ -750,6 +762,16 @@ public final class PowerManagerService extends SystemService
         mDirty |= DIRTY_SETTINGS;
     }
 
+    private void postAfterBootCompleted(Runnable r) {
+        if (mBootCompleted) {
+            BackgroundThread.getHandler().post(r);
+        } else {
+            Slog.d(TAG, "Delaying runnable until system is booted");
+            mBootCompletedRunnables = ArrayUtils.appendElement(Runnable.class,
+                    mBootCompletedRunnables, r);
+        }
+    }
+
     void updateLowPowerModeLocked() {
         if (mIsPowered && mLowPowerModeSetting) {
             if (DEBUG_SPEW) {
@@ -767,7 +789,7 @@ public final class PowerManagerService extends SystemService
         if (mLowPowerModeEnabled != lowPowerModeEnabled) {
             mLowPowerModeEnabled = lowPowerModeEnabled;
             powerHintInternal(POWER_HINT_LOW_POWER, lowPowerModeEnabled ? 1 : 0);
-            BackgroundThread.getHandler().post(new Runnable() {
+            postAfterBootCompleted(new Runnable() {
                 @Override
                 public void run() {
                     Intent intent = new Intent(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)
index 8a2729e..49aaa4a 100644 (file)
@@ -2512,7 +2512,7 @@ public final class TvInputManagerService extends SystemService {
 
         // For the recording session only
         @Override
-        public void onTuned() {
+        public void onTuned(Uri channelUri) {
             synchronized (mLock) {
                 if (DEBUG) {
                     Slog.d(TAG, "onTuned()");
@@ -2521,7 +2521,7 @@ public final class TvInputManagerService extends SystemService {
                     return;
                 }
                 try {
-                    mSessionState.client.onTuned(mSessionState.seq);
+                    mSessionState.client.onTuned(mSessionState.seq, channelUri);
                 } catch (RemoteException e) {
                     Slog.e(TAG, "error in onTuned", e);
                 }
index 2f076d1..7611527 100644 (file)
  */
 package com.android.server.vr;
 
+import android.app.AppOpsManager;
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.Slog;
@@ -40,6 +43,9 @@ public class VrManagerService extends SystemService {
     private static native void setVrModeNative(boolean enabled);
 
     private final Object mLock = new Object();
+
+    private final IBinder mOverlayToken = new Binder();
+
     private boolean mVrModeEnabled = false;
     private ArraySet<VrStateListener> mListeners = new ArraySet<>();
 
@@ -97,11 +103,25 @@ public class VrManagerService extends SystemService {
                 // Log mode change event.
                 Slog.i(TAG, "VR mode " + ((mVrModeEnabled) ? "enabled" : "disabled"));
                 setVrModeNative(mVrModeEnabled);
+                updateOverlayStateLocked();
                 onVrModeChangedLocked();
             }
         }
     }
 
+    private void updateOverlayStateLocked() {
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+            if (appOpsManager != null) {
+                appOpsManager.setUserRestriction(AppOpsManager.OP_SYSTEM_ALERT_WINDOW,
+                        mVrModeEnabled, mOverlayToken);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
+    }
+
     private boolean getVrMode() {
         synchronized (mLock) {
             return mVrModeEnabled;
index ba0d340..a0a971a 100644 (file)
@@ -882,6 +882,9 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
             wallpaper = mLockWallpaperMap.get(userId);
             if (wallpaper == null) {
                 // It's already gone; we're done.
+                if (DEBUG) {
+                    Slog.i(TAG, "Lock wallpaper already cleared");
+                }
                 return;
             }
         } else {
@@ -902,14 +905,19 @@ public class WallpaperManagerService extends IWallpaperManager.Stub {
                 wallpaper.wallpaperFile.delete();
                 wallpaper.cropFile.delete();
                 if (which == FLAG_SET_LOCK) {
+                    mLockWallpaperMap.remove(userId);
                     final IWallpaperManagerCallback cb = mKeyguardListener;
                     if (cb != null) {
+                        if (DEBUG) {
+                            Slog.i(TAG, "Notifying keyguard of lock wallpaper clear");
+                        }
                         try {
                             cb.onWallpaperChanged();
                         } catch (RemoteException e) {
                             // Oh well it went away; no big deal
                         }
                     }
+                    saveSettingsLocked(userId);
                     return;
                 }
             }
index f9e258d..2731f42 100644 (file)
@@ -354,6 +354,11 @@ class AppWindowToken extends WindowToken {
                 continue;
             }
 
+            if (DEBUG_ADD_REMOVE) Slog.e(TAG_WM, "win=" + win
+                    + " destroySurfaces: mAppStopped=" + mAppStopped
+                    + " win.mWindowRemovalAllowed=" + win.mWindowRemovalAllowed
+                    + " win.mRemoveOnExit=" + win.mRemoveOnExit);
+
             win.destroyOrSaveSurface();
             if (win.mRemoveOnExit) {
                 win.mAnimatingExit = false;
@@ -372,14 +377,19 @@ class AppWindowToken extends WindowToken {
         }
     }
 
-    // The application has stopped, so destroy any surfaces which were keeping alive
-    // in case they were still being used.
-    void notifyAppStopped() {
-        mAppStopped = true;
-        destroySurfaces();
+    /**
+     * If the application has stopped it is okay to destroy any surfaces which were keeping alive
+     * in case they were still being used.
+     */
+    void notifyAppStopped(boolean stopped) {
+        if (DEBUG_ADD_REMOVE) Slog.v(TAG, "notifyAppStopped: stopped=" + stopped + " " + this);
+        mAppStopped = stopped;
 
-        // Remove any starting window that was added for this app if they are still around.
-        mTask.mService.scheduleRemoveStartingWindowLocked(this);
+        if (stopped) {
+            destroySurfaces();
+            // Remove any starting window that was added for this app if they are still around.
+            mTask.mService.scheduleRemoveStartingWindowLocked(this);
+        }
     }
 
     /**
@@ -472,7 +482,7 @@ class AppWindowToken extends WindowToken {
                 winNdx = Math.min(winNdx - 1, allAppWindows.size() - 1)) {
             WindowState win = allAppWindows.get(winNdx);
             if (win.mAppDied) {
-                if (DEBUG_WINDOW_MOVEMENT) {
+                if (DEBUG_WINDOW_MOVEMENT || DEBUG_ADD_REMOVE) {
                     Slog.w(TAG, "removeAllDeadWindows: " + win);
                 }
                 // Set mDestroying, we don't want any animation or delayed removal here.
index f0efebe..79d3d84 100644 (file)
@@ -54,7 +54,8 @@ public class BoundsAnimationController {
         private final AnimateBoundsUser mTarget;
         private final Rect mFrom;
         private final Rect mTo;
-        private final Rect mTmpRect;
+        private final Rect mTmpRect = new Rect();
+        private final Rect mTmpTaskBounds = new Rect();
         private final boolean mMoveToFullScreen;
         // True if this this animation was cancelled and will be replaced the another animation from
         // the same {@link #AnimateBoundsUser} target.
@@ -63,17 +64,40 @@ public class BoundsAnimationController {
         // {@link #AnimateBoundsUser} target.
         private final boolean mReplacement;
 
+        // Depending on whether we are animating from
+        // a smaller to a larger size
+        private final int mFrozenTaskWidth;
+        private final int mFrozenTaskHeight;
+
         BoundsAnimator(AnimateBoundsUser target, Rect from, Rect to,
                 boolean moveToFullScreen, boolean replacement) {
             super();
             mTarget = target;
             mFrom = from;
             mTo = to;
-            mTmpRect = new Rect();
             mMoveToFullScreen = moveToFullScreen;
             mReplacement = replacement;
             addUpdateListener(this);
             addListener(this);
+
+            // If we are animating from smaller to larger, we want to change the task bounds
+            // to their final size immediately so we can use scaling to make the window
+            // larger. Likewise if we are going from bigger to smaller, we want to wait until
+            // the end so we don't have to upscale from the smaller finished size.
+            if (animatingToLargerSize()) {
+                mFrozenTaskWidth = mTo.width();
+                mFrozenTaskHeight = mTo.height();
+            } else {
+                mFrozenTaskWidth = mFrom.width();
+                mFrozenTaskHeight = mFrom.height();
+            }
+        }
+
+        boolean animatingToLargerSize() {
+            if (mFrom.width() * mFrom.height() > mTo.width() * mTo.height()) {
+                return false;
+            }
+            return true;
         }
 
         @Override
@@ -87,7 +111,13 @@ public class BoundsAnimationController {
             if (DEBUG) Slog.d(TAG, "animateUpdate: mTarget=" + mTarget + " mBounds="
                     + mTmpRect + " from=" + mFrom + " mTo=" + mTo + " value=" + value
                     + " remains=" + remains);
-            if (!mTarget.setSize(mTmpRect)) {
+
+            if (remains != 0) {
+                mTmpTaskBounds.set(mTmpRect.left, mTmpRect.top,
+                        mTmpRect.left + mFrozenTaskWidth, mTmpRect.top + mFrozenTaskHeight);
+            }
+
+            if (!mTarget.setPinnedStackSize(mTmpRect, remains != 0 ? mTmpTaskBounds : null)) {
                 // Whoops, the target doesn't feel like animating anymore. Let's immediately finish
                 // any further animation.
                 animation.cancel();
@@ -99,6 +129,10 @@ public class BoundsAnimationController {
         public void onAnimationStart(Animator animation) {
             if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
                     + " mReplacement=" + mReplacement);
+            if (animatingToLargerSize()) {
+                mTarget.setPinnedStackSize(mFrom, mTo);
+            }
+
             if (!mReplacement) {
                 mTarget.onAnimationStart();
             }
@@ -108,6 +142,7 @@ public class BoundsAnimationController {
         public void onAnimationEnd(Animator animation) {
             if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
                     + " mMoveToFullScreen=" + mMoveToFullScreen + " mWillReplace=" + mWillReplace);
+
             finishAnimation();
             if (mMoveToFullScreen && !mWillReplace) {
                 mTarget.moveToFullscreen();
@@ -159,6 +194,12 @@ public class BoundsAnimationController {
          * from the hierarchy and is not valid anymore.
          */
         boolean setSize(Rect bounds);
+        /**
+         * Behaves as setSize, but freezes the bounds of any tasks in the target at taskBounds,
+         * to allow for more flexibility during resizing. Only
+         * works for the pinned stack at the moment.
+         */
+        boolean setPinnedStackSize(Rect bounds, Rect taskBounds);
 
         void onAnimationStart();
 
index c7b5599..f097eb2 100644 (file)
@@ -19,6 +19,7 @@ package com.android.server.wm;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_FORCE_RESIZEABLE;
 import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
@@ -685,6 +686,10 @@ class Task implements DimLayer.DimLayerUser {
                 && mStack != null && StackId.isTaskResizeableByDockedStack(mStack.mStackId);
     }
 
+    boolean isFloating() {
+        return StackId.tasksAreFloating(mStack.mStackId);
+    }
+
     /**
      * Whether the task should be treated as if it's docked. Returns true if the task
      * is currently in docked workspace, or it's side-by-side to a docked task.
index 07a6514..86327f7 100644 (file)
@@ -111,6 +111,17 @@ public class TaskStack implements DimLayer.DimLayerUser,
     private float mMinimizeAmount;
     private final int mDockedStackMinimizeThickness;
 
+    // If this is true, the task will be down or upscaled
+    // to perfectly fit the region it would have been cropped
+    // to.
+    private boolean mForceScaleToCrop = false;
+    // By default, movement animations are applied to all
+    // window movement. If this is true, animations will not
+    // be applied within this stack. This is useful for example
+    // if the windows are moving as the result of a stack animation,
+    // in which case a second window animation would cause jitter.
+    private boolean mFreezeMovementAnimations = false;
+
     TaskStack(WindowManagerService service, int stackId) {
         mService = service;
         mStackId = stackId;
@@ -1128,17 +1139,38 @@ public class TaskStack implements DimLayer.DimLayerUser,
         return true;
     }
 
+    public boolean setPinnedStackSize(Rect bounds, Rect tempTaskBounds) {
+        synchronized (mService.mWindowMap) {
+            if (mDisplayContent == null) {
+                return false;
+            }
+            if (mStackId != PINNED_STACK_ID) {
+                Slog.w(TAG_WM, "Attempt to use pinned stack resize animation helper on"
+                        + "non pinned stack");
+                return false;
+            }
+        }
+        try {
+            mService.mActivityManager.resizePinnedStack(bounds, tempTaskBounds);
+        } catch (RemoteException e) {
+            // I don't believe you.
+        }
+        return true;
+    }
+
     @Override  // AnimatesBounds
     public void onAnimationStart() {
         synchronized (mService.mWindowMap) {
-            setDragResizingLocked(true);
+            mFreezeMovementAnimations = true;
+            mForceScaleToCrop = true;
         }
     }
 
     @Override  // AnimatesBounds
     public void onAnimationEnd() {
         synchronized (mService.mWindowMap) {
-            setDragResizingLocked(false);
+            mFreezeMovementAnimations = false;
+            mForceScaleToCrop = false;
             mService.requestTraversal();
         }
         if (mStackId == PINNED_STACK_ID) {
@@ -1163,4 +1195,12 @@ public class TaskStack implements DimLayer.DimLayerUser,
     public void getFullScreenBounds(Rect bounds) {
         getDisplayContent().getContentRect(bounds);
     }
+
+    public boolean getFreezeMovementAnimations() {
+        return mFreezeMovementAnimations;
+    }
+
+    public boolean getForceScaleToCrop() {
+        return mForceScaleToCrop;
+    }
 }
index 0979cd3..ccba88d 100644 (file)
@@ -35,7 +35,7 @@ public class WindowManagerDebugConfig {
 
     static final boolean DEBUG_RESIZE = false;
     static final boolean DEBUG = false;
-    static final boolean DEBUG_ADD_REMOVE = false;
+    static final boolean DEBUG_ADD_REMOVE = true;
     static final boolean DEBUG_FOCUS = false;
     static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
     static final boolean DEBUG_ANIM = false;
index 69d2d20..b64aaa8 100644 (file)
@@ -2147,12 +2147,15 @@ public class WindowManagerService extends IWindowManager.Stub
 
     void removeWindowLocked(WindowState win) {
         win.mWindowRemovalAllowed = true;
+        if (DEBUG_ADD_REMOVE) Slog.v(TAG,
+                "removeWindowLocked: " + win + " callers=" + Debug.getCallers(4));
+
         final boolean startingWindow = win.mAttrs.type == TYPE_APPLICATION_STARTING;
         if (startingWindow) {
             if (DEBUG_STARTING_WINDOW) Slog.d(TAG_WM, "Starting window removed " + win);
         }
 
-        if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win==mCurrentFocus) Slog.v(
+        if (localLOGV || DEBUG_FOCUS || DEBUG_FOCUS_LIGHT && win == mCurrentFocus) Slog.v(
                 TAG_WM, "Remove " + win + " client="
                 + Integer.toHexString(System.identityHashCode(win.mClient.asBinder()))
                 + ", surfaceController=" + win.mWinAnimator.mSurfaceController + " Callers="
@@ -4194,7 +4197,7 @@ public class WindowManagerService extends IWindowManager.Stub
     }
 
     @Override
-    public void notifyAppStopped(IBinder token) {
+    public void notifyAppStopped(IBinder token, boolean stopped) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "notifyAppStopped()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -4207,7 +4210,7 @@ public class WindowManagerService extends IWindowManager.Stub
                 Slog.w(TAG_WM, "Attempted to set visibility of non-existing app token: " + token);
                 return;
             }
-            wtoken.notifyAppStopped();
+            wtoken.notifyAppStopped(stopped);
         }
     }
 
@@ -4244,6 +4247,8 @@ public class WindowManagerService extends IWindowManager.Stub
                 wtoken.appDied = false;
                 wtoken.removeAllWindows();
             } else if (visible) {
+                if (DEBUG_ADD_REMOVE) Slog.v(
+                        TAG_WM, "No longer Stopped: " + wtoken);
                 wtoken.mAppStopped = false;
                 wtoken.setWindowsExiting(false);
             }
@@ -8777,10 +8782,10 @@ public class WindowManagerService extends IWindowManager.Stub
         i -= lastBelow;
         if (i != numRemoved) {
             displayContent.layoutNeeded = true;
-            Slog.w(TAG_WM, "On display=" + displayContent.getDisplayId() + " Rebuild removed " +
-                    numRemoved + " windows but added " + i,
-                    new RuntimeException("here").fillInStackTrace());
-            for (i=0; i<numRemoved; i++) {
+            Slog.w(TAG_WM, "On display=" + displayContent.getDisplayId() + " Rebuild removed "
+                    + numRemoved + " windows but added " + i + " rebuildAppWindowListLocked() "
+                    + " callers=" + Debug.getCallers(10));
+            for (i = 0; i < numRemoved; i++) {
                 WindowState ws = mRebuildTmp[i];
                 if (ws.mRebuilding) {
                     StringWriter sw = new StringWriter();
index 40b6b50..4ad021e 100644 (file)
@@ -184,6 +184,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
 
     private Configuration mConfiguration = Configuration.EMPTY;
     private Configuration mOverrideConfig = Configuration.EMPTY;
+    // Represents the changes from our override configuration applied
+    // to the global configuration. This is the only form of configuration
+    // which is suitable for delivery to the client.
+    private Configuration mMergedConfiguration = new Configuration();
     // Sticky answer to isConfigChanged(), remains true until new Configuration is assigned.
     // Used only on {@link #TYPE_KEYGUARD}.
     private boolean mConfigHasChanged;
@@ -434,9 +438,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
     // If not null, the window that will be used to replace the old one. This is being set when
     // the window is added and unset when this window reports its first draw.
     WindowState mReplacingWindow = null;
-
     // Whether this window is being moved via the resize API
     boolean mMovedByResize;
+
     /**
      * Wake lock for drawing.
      * Even though it's slightly more expensive to do so, we will use a separate wake lock
@@ -635,7 +639,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
 
         final Task task = getTask();
         final boolean fullscreenTask = task == null || task.isFullscreen();
-        final boolean freeformWorkspace = task != null && task.inFreeformWorkspace();
+        final boolean windowsAreFloating = task != null && task.isFloating();
 
         if (fullscreenTask || (isChildWindow()
                 && (mAttrs.privateFlags & PRIVATE_FLAG_LAYOUT_CHILD_WINDOW_IN_PARENT_FRAME) != 0)) {
@@ -661,10 +665,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
                 mContainingFrame.top -= mContainingFrame.bottom - cf.bottom;
             }
 
-            if (freeformWorkspace) {
-                // In free form mode we have only to set the rectangle if it wasn't set already. No
-                // need to intersect it with the (visible) "content frame" since it is allowed to
-                // be outside the visible desktop.
+            if (windowsAreFloating) {
+                // In floating modes (e.g. freeform, pinned) we have only to set the rectangle 
+                // if it wasn't set already. No need to intersect it with the (visible) 
+                // "content frame" since it is allowed to be outside the visible desktop.
                 if (mContainingFrame.isEmpty()) {
                     mContainingFrame.set(cf);
                 }
@@ -720,7 +724,7 @@ final class WindowState implements WindowManagerPolicy.WindowState {
 
         // Make sure the content and visible frames are inside of the
         // final window frame.
-        if (freeformWorkspace && !mFrame.isEmpty()) {
+        if (windowsAreFloating && !mFrame.isEmpty()) {
             // Keep the frame out of the blocked system area, limit it in size to the content area
             // and make sure that there is always a minimum visible so that the user can drag it
             // into a usable area..
@@ -772,9 +776,9 @@ final class WindowState implements WindowManagerPolicy.WindowState {
                     Math.min(mStableFrame.bottom, frame.bottom));
         }
 
-        if (!inFreeformWorkspace()) {
-            // Freeform windows can be positioned outside of the display frame, but that is not a
-            // reason to provide them with overscan insets.
+        if (!windowsAreFloating) {
+            // Windows from floating tasks (e.g. freeform, pinned) may be positioned outside
+            // of the display frame, but that is not a reason to provide them with overscan insets.
             mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
                     Math.max(mOverscanFrame.top - frame.top, 0),
                     Math.max(frame.right - mOverscanFrame.right, 0),
@@ -1355,6 +1359,11 @@ final class WindowState implements WindowManagerPolicy.WindowState {
         mConfiguration = newConfig;
         mOverrideConfig = newOverrideConfig;
         mConfigHasChanged = false;
+
+        mMergedConfiguration.setTo(newConfig);
+        if (newOverrideConfig != null && newOverrideConfig != Configuration.EMPTY) {
+            mMergedConfiguration.updateFrom(newOverrideConfig);
+        }
     }
 
     void setHasSurface(boolean hasSurface) {
@@ -1616,9 +1625,10 @@ final class WindowState implements WindowManagerPolicy.WindowState {
             mTurnOnScreen = true;
         }
         if (isConfigChanged()) {
+            final Configuration newConfig = updateConfiguration();
             if (DEBUG_CONFIGURATION) Slog.i(TAG, "Window " + this + " visible with new config: "
-                    + mService.mCurConfiguration);
-            outConfig.setTo(mService.mCurConfiguration);
+                    + newConfig);
+            outConfig.setTo(newConfig);
         }
     }
 
@@ -1902,6 +1912,12 @@ final class WindowState implements WindowManagerPolicy.WindowState {
             mWinAnimator.hide("saved surface");
             mWinAnimator.mDrawState = WindowStateAnimator.NO_SURFACE;
             setHasSurface(false);
+            // The client should have disconnected at this point, but if it doesn't,
+            // we need to make sure it's disconnected. Otherwise when we reuse the surface
+            // the client can't reconnect to the buffer queue, and rendering will fail.
+            if (mWinAnimator.mSurfaceController != null) {
+                mWinAnimator.mSurfaceController.disconnectInTransaction();
+            }
         } else {
             mWinAnimator.destroySurfaceLocked();
         }
@@ -2055,21 +2071,30 @@ final class WindowState implements WindowManagerPolicy.WindowState {
         }
     }
 
+    /**
+     * Update our current configurations, based on task configuration.
+     *
+     * @return A configuration suitable for sending to the client.
+     */
+    private Configuration updateConfiguration() {
+        final Task task = getTask();
+        final Configuration overrideConfig =
+            (task != null) ? task.mOverrideConfig : Configuration.EMPTY;
+        final boolean configChanged = isConfigChanged();
+        if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
+            Slog.i(TAG, "Sending new config to window " + this + ": " +
+                    " / config=" + mService.mCurConfiguration + " overrideConfig=" + overrideConfig);
+        }
+        setConfiguration(mService.mCurConfiguration, overrideConfig);
+        return mMergedConfiguration;
+    }
+
     void reportResized() {
         Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
         try {
             if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
                     + ": " + mCompatFrame);
-            final boolean configChanged = isConfigChanged();
-            final Task task = getTask();
-            final Configuration overrideConfig =
-                    (task != null) ? task.mOverrideConfig : Configuration.EMPTY;
-            if ((DEBUG_RESIZE || DEBUG_ORIENTATION || DEBUG_CONFIGURATION) && configChanged) {
-                Slog.i(TAG, "Sending new config to window " + this + ": "
-                        + " / config="
-                        + mService.mCurConfiguration + " overrideConfig=" + overrideConfig);
-            }
-            setConfiguration(mService.mCurConfiguration, overrideConfig);
+            final Configuration newConfig = isConfigChanged() ? updateConfiguration() : null;
             if (DEBUG_ORIENTATION && mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING)
                 Slog.i(TAG, "Resizing " + this + " WITH DRAW PENDING");
 
@@ -2080,7 +2105,6 @@ final class WindowState implements WindowManagerPolicy.WindowState {
             final Rect stableInsets = mLastStableInsets;
             final Rect outsets = mLastOutsets;
             final boolean reportDraw = mWinAnimator.mDrawState == WindowStateAnimator.DRAW_PENDING;
-            final Configuration newConfig = configChanged ? mConfiguration : null;
             if (mAttrs.type != WindowManager.LayoutParams.TYPE_APPLICATION_STARTING
                     && mClient instanceof IWindow.Stub) {
                 // To prevent deadlock simulate one-way call if win.mClient is a local object.
@@ -2479,7 +2503,8 @@ final class WindowState implements WindowManagerPolicy.WindowState {
         final int ph = mContainingFrame.height();
         final Task task = getTask();
         final boolean nonFullscreenTask = task != null && !task.isFullscreen();
-
+        final boolean fitToDisplay = task != null &&
+            !task.isFloating();
         float x, y;
         int w,h;
 
@@ -2536,7 +2561,17 @@ final class WindowState implements WindowManagerPolicy.WindowState {
                 (int) (y + mAttrs.verticalMargin * ph), mFrame);
 
         // Now make sure the window fits in the overall display frame.
-        Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame);
+        if (fitToDisplay) {
+            Gravity.applyDisplay(mAttrs.gravity, mDisplayFrame, mFrame);
+        }
+
+        // We need to make sure we update the CompatFrame as it is used for
+        // cropping decisions, etc, on systems where we lack a decor layer.
+        mCompatFrame.set(mFrame);
+        if (mEnforceSizeCompat) {
+            // See comparable block in computeFrameLw.
+            mCompatFrame.scale(mInvGlobalScale);
+        }
     }
 
     boolean isChildWindow() {
index 02f9aa1..c1ff96e 100644 (file)
@@ -20,6 +20,7 @@ import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
@@ -467,9 +468,8 @@ class WindowStateAnimator {
             return;
         }
 
-        if (WindowManagerService.localLOGV) Slog.v(
-                TAG, "Exit animation finished in " + this
-                + ": remove=" + mWin.mRemoveOnExit);
+        if (WindowManagerService.localLOGV || DEBUG_ADD_REMOVE) Slog.v(TAG,
+                "Exit animation finished in " + this + ": remove=" + mWin.mRemoveOnExit);
 
 
         mWin.mDestroying = true;
@@ -1115,11 +1115,11 @@ class WindowStateAnimator {
         }
     }
 
-    void updateSurfaceWindowCrop(final boolean recoveringMemory) {
+    Rect calculateSurfaceWindowCrop() {
         final WindowState w = mWin;
         final DisplayContent displayContent = w.getDisplayContent();
         if (displayContent == null) {
-            return;
+            return null;
         }
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
         if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop for window: " + w + ", " + "mLastCrop=" +
@@ -1187,7 +1187,7 @@ class WindowStateAnimator {
         clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
 
         adjustCropToStackBounds(w, clipRect, isFreeformResizing);
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + mClipRect);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + clipRect);
 
         w.transformFromScreenToSurfaceSpace(clipRect);
 
@@ -1196,6 +1196,10 @@ class WindowStateAnimator {
             clipRect.setEmpty();
         }
 
+        return clipRect;
+    }
+
+    void updateSurfaceWindowCrop(Rect clipRect, boolean recoveringMemory) {
         if (!clipRect.equals(mLastClipRect)) {
             mLastClipRect.set(clipRect);
             mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
@@ -1237,6 +1241,7 @@ class WindowStateAnimator {
                 w.mFrame.left + mWin.mXOffset - w.getAttrs().surfaceInsets.left;
         final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
                 w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;
+
         // We need to do some acrobatics with surface position, because their clip region is
         // relative to the inside of the surface, but the stack bounds aren't.
         clipRect.left = Math.max(0,
@@ -1251,14 +1256,44 @@ class WindowStateAnimator {
 
     void setSurfaceBoundariesLocked(final boolean recoveringMemory) {
         final WindowState w = mWin;
+        final Task task = w.getTask();
 
         mTmpSize.set(w.mShownPosition.x, w.mShownPosition.y, 0, 0);
         calculateSurfaceBounds(w, w.getAttrs());
 
-        mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top, recoveringMemory);
+        float extraHScale = (float) 1.0;
+        float extraVScale = (float) 1.0;
+
+        final Rect crop = calculateSurfaceWindowCrop();
+        if (task != null && task.mStack.getForceScaleToCrop()) {
+            extraHScale = crop.width() / (float)mTmpSize.width();
+            extraVScale = crop.height() / (float)mTmpSize.height();
+
+            // In the case of ForceScaleToCrop we scale entire tasks together,
+            // and so we need to scale our offsets relative to the task bounds
+            // or parent and child windows would fall out of alignment.
+            int posX = (int) (mTmpSize.left - w.mAttrs.x * (1 - extraHScale));
+            int posY = (int) (mTmpSize.top - w.mAttrs.y * (1 - extraVScale));
+            posX += w.getAttrs().surfaceInsets.left * (1 - extraHScale);
+            posY += w.getAttrs().surfaceInsets.top * (1 - extraVScale);
+            mSurfaceController.setPositionInTransaction(posX, posY, recoveringMemory);
+
+            // Since we are scaled to fit in our previously desired crop, we can now
+            // expose the whole window in buffer space, and not risk extending
+            // past where the system would have cropped us
+            crop.set(0, 0, mTmpSize.width(), mTmpSize.height());
+            updateSurfaceWindowCrop(crop, recoveringMemory);
+        } else {
+            mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
+                    recoveringMemory);
+            updateSurfaceWindowCrop(crop, recoveringMemory);
+        }
+
 
-        mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale, mDtDx * w.mVScale,
-                mDsDy * w.mHScale, mDtDy * w.mVScale, recoveringMemory);
+        mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * extraHScale,
+                mDtDx * w.mVScale * extraVScale,
+                mDsDy * w.mHScale * extraHScale,
+                mDtDy * w.mVScale * extraVScale, recoveringMemory);
         mSurfaceResized = mSurfaceController.setSizeInTransaction(
                 mTmpSize.width(), mTmpSize.height(),
                 recoveringMemory);
@@ -1270,7 +1305,6 @@ class WindowStateAnimator {
             w.applyDimLayerIfNeeded();
         }
 
-        updateSurfaceWindowCrop(recoveringMemory);
     }
 
     void prepareSurfaceLocked(final boolean recoveringMemory) {
@@ -1409,7 +1443,7 @@ class WindowStateAnimator {
             SurfaceControl.openTransaction();
             mSurfaceController.setPositionInTransaction(mWin.mFrame.left + left,
                     mWin.mFrame.top + top, false);
-            updateSurfaceWindowCrop(false);
+            updateSurfaceWindowCrop(calculateSurfaceWindowCrop(), false);
         } catch (RuntimeException e) {
             Slog.w(TAG, "Error positioning surface of " + mWin
                     + " pos=(" + left + "," + top + ")", e);
index 2972a24..fb07512 100644 (file)
@@ -138,7 +138,7 @@ class WindowSurfaceController {
 
     void destroyInTransaction() {
         //        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
-        Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(4));
+        Slog.i(TAG, "Destroying surface " + this + " called by " + Debug.getCallers(8));
         //        }
         try {
             if (mSurfaceControl != null) {
@@ -152,6 +152,20 @@ class WindowSurfaceController {
         }
     }
 
+    void disconnectInTransaction() {
+        if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
+            Slog.i(TAG, "Disconnecting client: " + this);
+        }
+
+        try {
+            if (mSurfaceControl != null) {
+                mSurfaceControl.disconnect();
+            }
+        } catch (RuntimeException e) {
+            Slog.w(TAG, "Error disconnecting surface in: " + this, e);
+        }
+    }
+
     void setCropInTransaction(Rect clipRect, boolean recoveringMemory) {
         if (SHOW_TRANSACTIONS) logSurface(
                 "CROP " + clipRect.toShortString(), null);
index 856d30a..e3955fe 100644 (file)
@@ -651,6 +651,7 @@ class WindowSurfacePlacer {
 
             for (int i = windows.size() - 1; i >= 0; i--) {
                 WindowState w = windows.get(i);
+                final Task task = w.getTask();
                 final boolean obscuredChanged = w.mObscured != mObscured;
 
                 // Update effect.
@@ -683,7 +684,8 @@ class WindowSurfacePlacer {
                     final boolean adjustedForMinimizedDockedStack = w.getTask() != null &&
                             w.getTask().mStack.isAdjustedForMinimizedDockedStack();
                     if ((w.mAttrs.privateFlags & PRIVATE_FLAG_NO_MOVE_ANIMATION) == 0
-                            && !w.isDragResizing() && !adjustedForMinimizedDockedStack) {
+                            && !w.isDragResizing() && !adjustedForMinimizedDockedStack
+                            && (task == null || !w.getTask().mStack.getFreezeMovementAnimations())) {
                         winAnimator.setMoveAnimation(left, top);
                     }
 
index c97323c..aa14fff 100644 (file)
@@ -140,7 +140,7 @@ static void sv_status_callback(GpsSvStatus* sv_status)
             ALOGD("Unknown constellation type with Svid = %d.", info.svid);
             info.constellation = GNSS_CONSTELLATION_UNKNOWN;
         }
-        info.snr = sv_status->sv_list[i].snr;
+        info.c_n0_dbhz = sv_status->sv_list[i].snr;
         info.elevation = sv_status->sv_list[i].elevation;
         info.azimuth = sv_status->sv_list[i].azimuth;
         info.flags = GNSS_SV_FLAGS_NONE;
@@ -698,12 +698,12 @@ static void android_location_GnssLocationProvider_delete_aiding_data(JNIEnv* /*
 }
 
 static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jobject /* obj */,
-        jintArray svidWithFlagArray, jfloatArray snrArray, jfloatArray elevArray,
+        jintArray svidWithFlagArray, jfloatArray cn0Array, jfloatArray elevArray,
         jfloatArray azumArray)
 {
     // this should only be called from within a call to reportSvStatus
     jint* svidWithFlags = env->GetIntArrayElements(svidWithFlagArray, 0);
-    jfloat* snrs = env->GetFloatArrayElements(snrArray, 0);
+    jfloat* cn0s = env->GetFloatArrayElements(cn0Array, 0);
     jfloat* elev = env->GetFloatArrayElements(elevArray, 0);
     jfloat* azim = env->GetFloatArrayElements(azumArray, 0);
 
@@ -713,13 +713,13 @@ static jint android_location_GnssLocationProvider_read_sv_status(JNIEnv* env, jo
         svidWithFlags[i] = (info.svid << SVID_SHIFT_WIDTH) |
             (info.constellation << CONSTELLATION_TYPE_SHIFT_WIDTH) |
             info.flags;
-        snrs[i] = info.snr;
+        cn0s[i] = info.c_n0_dbhz;
         elev[i] = info.elevation;
         azim[i] = info.azimuth;
     }
 
     env->ReleaseIntArrayElements(svidWithFlagArray, svidWithFlags, 0);
-    env->ReleaseFloatArrayElements(snrArray, snrs, 0);
+    env->ReleaseFloatArrayElements(cn0Array, cn0s, 0);
     env->ReleaseFloatArrayElements(elevArray, elev, 0);
     env->ReleaseFloatArrayElements(azumArray, azim, 0);
     return (jint) sGnssSvListSize;
@@ -1095,7 +1095,9 @@ static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
     JavaObject object(env, "android/location/GnssClock");
     GpsClockFlags flags = clock->flags;
 
-    SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
+    SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
+           LeapSecond,
+           static_cast<int32_t>(clock->leap_second));
 
     // GnssClock only supports the more effective HW_CLOCK type, so type
     // handling and documentation complexity has been removed.  To convert the
@@ -1122,18 +1124,18 @@ static jobject translate_gps_clock(JNIEnv* env, GpsClock* clock) {
         break;
     }
 
-    SET(TimeInNs, clock->time_ns);
+    SET(TimeNanos, clock->time_ns);
     SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
-           TimeUncertaintyInNs,
+           TimeUncertaintyNanos,
            clock->time_uncertainty_ns);
-    SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
-    SET_IF(GNSS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+    SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, clock->full_bias_ns);
+    SET_IF(GNSS_CLOCK_HAS_BIAS, BiasNanos, clock->bias_ns);
     SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
-           BiasUncertaintyInNs,
+           BiasUncertaintyNanos,
            clock->bias_uncertainty_ns);
-    SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+    SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps);
     SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
-           DriftUncertaintyInNsPerSec,
+           DriftUncertaintyNanosPerSecond,
            clock->drift_uncertainty_nsps);
 
     return object.get();
@@ -1143,20 +1145,21 @@ static jobject translate_gnss_clock(JNIEnv* env, GnssClock* clock) {
     JavaObject object(env, "android/location/GnssClock");
     GpsClockFlags flags = clock->flags;
 
-    SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND, LeapSecond, clock->leap_second);
-    SET(Type, static_cast<uint8_t>(GPS_CLOCK_TYPE_LOCAL_HW_TIME));
-    SET(TimeInNs, clock->time_ns);
+    SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
+           LeapSecond,
+           static_cast<int32_t>(clock->leap_second));
+    SET(TimeNanos, clock->time_ns);
     SET_IF(GNSS_CLOCK_HAS_TIME_UNCERTAINTY,
-           TimeUncertaintyInNs,
+           TimeUncertaintyNanos,
            clock->time_uncertainty_ns);
-    SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasInNs, clock->full_bias_ns);
-    SET_IF(GNSS_CLOCK_HAS_BIAS, BiasInNs, clock->bias_ns);
+    SET_IF(GNSS_CLOCK_HAS_FULL_BIAS, FullBiasNanos, clock->full_bias_ns);
+    SET_IF(GNSS_CLOCK_HAS_BIAS, BiasNanos, clock->bias_ns);
     SET_IF(GNSS_CLOCK_HAS_BIAS_UNCERTAINTY,
-           BiasUncertaintyInNs,
+           BiasUncertaintyNanos,
            clock->bias_uncertainty_ns);
-    SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftInNsPerSec, clock->drift_nsps);
+    SET_IF(GNSS_CLOCK_HAS_DRIFT, DriftNanosPerSecond, clock->drift_nsps);
     SET_IF(GNSS_CLOCK_HAS_DRIFT_UNCERTAINTY,
-           DriftUncertaintyInNsPerSec,
+           DriftUncertaintyNanosPerSecond,
            clock->drift_uncertainty_nsps);
 
     SET(HardwareClockDiscontinuityCount, clock->hw_clock_discontinuity_count);
@@ -1168,41 +1171,30 @@ static jobject translate_gps_measurement(JNIEnv* env,
                                          GpsMeasurement* measurement) {
     JavaObject object(env, "android/location/GnssMeasurement");
     GpsMeasurementFlags flags = measurement->flags;
-    SET(Svid, static_cast<int16_t>(measurement->prn));
+    SET(Svid, static_cast<int32_t>(measurement->prn));
     if (measurement->prn >= 1 || measurement->prn <= 32) {
-        SET(ConstellationType, static_cast<uint8_t>(GNSS_CONSTELLATION_GPS));
+        SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
     } else {
         ALOGD("Unknown constellation type with Svid = %d.", measurement->prn);
         SET(ConstellationType,
-            static_cast<uint8_t>(GNSS_CONSTELLATION_UNKNOWN));
+            static_cast<int32_t>(GNSS_CONSTELLATION_UNKNOWN));
     }
-    SET(TimeOffsetInNs, measurement->time_offset_ns);
-    SET(State, measurement->state);
-    SET(ReceivedSvTimeInNs, measurement->received_gps_tow_ns);
-    SET(ReceivedSvTimeUncertaintyInNs,
+    SET(TimeOffsetNanos, measurement->time_offset_ns);
+    SET(State, static_cast<int32_t>(measurement->state));
+    SET(ReceivedSvTimeNanos, measurement->received_gps_tow_ns);
+    SET(ReceivedSvTimeUncertaintyNanos,
         measurement->received_gps_tow_uncertainty_ns);
-    SET(Cn0InDbHz, measurement->c_n0_dbhz);
-    SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
-    SET(PseudorangeRateUncertaintyInMetersPerSec,
+    SET(Cn0DbHz, measurement->c_n0_dbhz);
+    SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps);
+    SET(PseudorangeRateUncertaintyMetersPerSecond,
         measurement->pseudorange_rate_uncertainty_mps);
-    SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
-    SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
-    SET(AccumulatedDeltaRangeUncertaintyInMeters,
+    SET(AccumulatedDeltaRangeState,
+        static_cast<int32_t>(measurement->accumulated_delta_range_state));
+    SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m);
+    SET(AccumulatedDeltaRangeUncertaintyMeters,
         measurement->accumulated_delta_range_uncertainty_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE,
-           PseudorangeInMeters,
-           measurement->pseudorange_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
-           PseudorangeUncertaintyInMeters,
-           measurement->pseudorange_uncertainty_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE,
-           CodePhaseInChips,
-           measurement->code_phase_chips);
-    SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
-           CodePhaseUncertaintyInChips,
-           measurement->code_phase_uncertainty_chips);
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
-           CarrierFrequencyInHz,
+           CarrierFrequencyHz,
            measurement->carrier_frequency_hz);
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
            CarrierCycles,
@@ -1213,33 +1205,8 @@ static jobject translate_gps_measurement(JNIEnv* env,
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
            CarrierPhaseUncertainty,
            measurement->carrier_phase_uncertainty);
-    SET(LossOfLock, measurement->loss_of_lock);
-    SET_IF(GNSS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
-    SET_IF(GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
-           TimeFromLastBitInMs,
-           measurement->time_from_last_bit_ms);
-    SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT,
-           DopplerShiftInHz,
-           measurement->doppler_shift_hz);
-    SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
-           DopplerShiftUncertaintyInHz,
-           measurement->doppler_shift_uncertainty_hz);
     SET(MultipathIndicator, measurement->multipath_indicator);
     SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
-    SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION,
-           ElevationInDeg,
-           measurement->elevation_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
-           ElevationUncertaintyInDeg,
-           measurement->elevation_uncertainty_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH,
-           AzimuthInDeg,
-           measurement->azimuth_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
-           AzimuthUncertaintyInDeg,
-           measurement->azimuth_uncertainty_deg);
-    SET(UsedInFix,
-        (flags & GNSS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
 
     return object.get();
 }
@@ -1250,34 +1217,23 @@ static jobject translate_gnss_measurement(JNIEnv* env,
     GpsMeasurementFlags flags = measurement->flags;
 
     SET(Svid, measurement->svid);
-    SET(ConstellationType, measurement->constellation);
-    SET(TimeOffsetInNs, measurement->time_offset_ns);
-    SET(State, measurement->state);
-    SET(ReceivedSvTimeInNs, measurement->received_sv_time_in_ns);
-    SET(ReceivedSvTimeUncertaintyInNs,
+    SET(ConstellationType, static_cast<int32_t>(measurement->constellation));
+    SET(TimeOffsetNanos, measurement->time_offset_ns);
+    SET(State, static_cast<int32_t>(measurement->state));
+    SET(ReceivedSvTimeNanos, measurement->received_sv_time_in_ns);
+    SET(ReceivedSvTimeUncertaintyNanos,
         measurement->received_sv_time_uncertainty_in_ns);
-    SET(Cn0InDbHz, measurement->c_n0_dbhz);
-    SET(PseudorangeRateInMetersPerSec, measurement->pseudorange_rate_mps);
-    SET(PseudorangeRateUncertaintyInMetersPerSec,
+    SET(Cn0DbHz, measurement->c_n0_dbhz);
+    SET(PseudorangeRateMetersPerSecond, measurement->pseudorange_rate_mps);
+    SET(PseudorangeRateUncertaintyMetersPerSecond,
         measurement->pseudorange_rate_uncertainty_mps);
-    SET(AccumulatedDeltaRangeState, measurement->accumulated_delta_range_state);
-    SET(AccumulatedDeltaRangeInMeters, measurement->accumulated_delta_range_m);
-    SET(AccumulatedDeltaRangeUncertaintyInMeters,
+    SET(AccumulatedDeltaRangeState,
+        static_cast<int32_t>(measurement->accumulated_delta_range_state));
+    SET(AccumulatedDeltaRangeMeters, measurement->accumulated_delta_range_m);
+    SET(AccumulatedDeltaRangeUncertaintyMeters,
         measurement->accumulated_delta_range_uncertainty_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE,
-           PseudorangeInMeters,
-           measurement->pseudorange_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_PSEUDORANGE_UNCERTAINTY,
-           PseudorangeUncertaintyInMeters,
-           measurement->pseudorange_uncertainty_m);
-    SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE,
-           CodePhaseInChips,
-           measurement->code_phase_chips);
-    SET_IF(GNSS_MEASUREMENT_HAS_CODE_PHASE_UNCERTAINTY,
-           CodePhaseUncertaintyInChips,
-           measurement->code_phase_uncertainty_chips);
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_FREQUENCY,
-           CarrierFrequencyInHz,
+           CarrierFrequencyHz,
            measurement->carrier_frequency_hz);
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_CYCLES,
            CarrierCycles,
@@ -1288,32 +1244,8 @@ static jobject translate_gnss_measurement(JNIEnv* env,
     SET_IF(GNSS_MEASUREMENT_HAS_CARRIER_PHASE_UNCERTAINTY,
            CarrierPhaseUncertainty,
            measurement->carrier_phase_uncertainty);
-    SET_IF(GNSS_MEASUREMENT_HAS_BIT_NUMBER, BitNumber, measurement->bit_number);
-    SET_IF(GNSS_MEASUREMENT_HAS_TIME_FROM_LAST_BIT,
-           TimeFromLastBitInMs,
-           measurement->time_from_last_bit_ms);
-    SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT,
-           DopplerShiftInHz,
-           measurement->doppler_shift_hz);
-    SET_IF(GNSS_MEASUREMENT_HAS_DOPPLER_SHIFT_UNCERTAINTY,
-           DopplerShiftUncertaintyInHz,
-           measurement->doppler_shift_uncertainty_hz);
     SET(MultipathIndicator, measurement->multipath_indicator);
     SET_IF(GNSS_MEASUREMENT_HAS_SNR, SnrInDb, measurement->snr_db);
-    SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION,
-           ElevationInDeg,
-           measurement->elevation_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_ELEVATION_UNCERTAINTY,
-           ElevationUncertaintyInDeg,
-           measurement->elevation_uncertainty_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH,
-           AzimuthInDeg,
-           measurement->azimuth_deg);
-    SET_IF(GNSS_MEASUREMENT_HAS_AZIMUTH_UNCERTAINTY,
-           AzimuthUncertaintyInDeg,
-           measurement->azimuth_uncertainty_deg);
-    SET(UsedInFix,
-        (flags & GNSS_MEASUREMENT_HAS_USED_IN_FIX) && measurement->used_in_fix);
 
     return object.get();
 }
@@ -1493,21 +1425,22 @@ static jobject translate_gps_navigation_message(JNIEnv* env, GpsNavigationMessag
         return NULL;
     }
     JavaObject object(env, "android/location/GnssNavigationMessage");
-    SET(Svid, static_cast<int16_t>(message->prn));
+    SET(Svid, static_cast<int32_t>(message->prn));
     if (message->prn >=1 && message->prn <= 32) {
-        SET(ConstellationType, static_cast<uint8_t>(GNSS_CONSTELLATION_GPS));
+        SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
         // Legacy driver doesn't set the higher byte to constellation type
         // correctly. Set the higher byte to 'GPS'.
-        SET(Type, static_cast<int16_t>(message->type | 0x0100));
+        SET(Type, static_cast<int32_t>(message->type | 0x0100));
     } else {
         ALOGD("Unknown constellation type with Svid = %d.", message->prn);
         SET(ConstellationType,
-            static_cast<uint8_t>(GNSS_CONSTELLATION_UNKNOWN));
-        SET(Type, static_cast<int16_t>(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN));
+            static_cast<int32_t>(GNSS_CONSTELLATION_UNKNOWN));
+        SET(Type, static_cast<int32_t>(GNSS_NAVIGATION_MESSAGE_TYPE_UNKNOWN));
     }
-    SET(MessageId, message->message_id);
-    SET(SubmessageId, message->submessage_id);
+    SET(MessageId, static_cast<int32_t>(message->message_id));
+    SET(SubmessageId, static_cast<int32_t>(message->submessage_id));
     object.callSetter("setData", data, dataLength);
+    SET(Status, static_cast<int32_t>(message->status));
     return object.get();
 }
 
@@ -1520,11 +1453,12 @@ static jobject translate_gnss_navigation_message(
         return NULL;
     }
     JavaObject object(env, "android/location/GnssNavigationMessage");
-    SET(Type, message->type);
-    SET(Svid, message->svid);
-    SET(MessageId, message->message_id);
-    SET(SubmessageId, message->submessage_id);
+    SET(Type, static_cast<int32_t>(message->type));
+    SET(Svid, static_cast<int32_t>(message->svid));
+    SET(MessageId, static_cast<int32_t>(message->message_id));
+    SET(SubmessageId, static_cast<int32_t>(message->submessage_id));
     object.callSetter("setData", data, dataLength);
+    SET(Status, static_cast<int32_t>(message->status));
     return object.get();
 }
 
index 60c3a35..d8aa5d7 100644 (file)
@@ -31,8 +31,8 @@ import com.google.android.collect.Sets;
 import android.Manifest.permission;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accounts.AccountManager;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
-import android.annotation.Nullable;
 import android.app.Activity;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
@@ -151,6 +151,8 @@ import java.io.FileNotFoundException;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.nio.charset.StandardCharsets;
 import java.security.cert.CertificateException;
 import java.security.cert.CertificateFactory;
@@ -280,6 +282,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     private static final int PROFILE_KEYGUARD_FEATURES =
             PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER | PROFILE_KEYGUARD_FEATURES_PROFILE_ONLY;
 
+    private static final int CODE_OK = 0;
+    private static final int CODE_HAS_DEVICE_OWNER = 1;
+    private static final int CODE_USER_HAS_PROFILE_OWNER = 2;
+    private static final int CODE_USER_NOT_RUNNING = 3;
+    private static final int CODE_USER_SETUP_COMPLETED = 4;
+    private static final int CODE_NONSYSTEM_USER_EXISTS = 5;
+    private static final int CODE_ACCOUNTS_NOT_EMPTY = 6;
+    private static final int CODE_NOT_SYSTEM_USER = 7;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({ CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING,
+            CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER })
+    private @interface DeviceOwnerPreConditionCode {}
+
     private static final int DEVICE_ADMIN_DEACTIVATE_TIMEOUT = 10000;
 
     final Context mContext;
@@ -308,7 +324,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
      * Whether or not device admin feature is supported. If it isn't return defaults for all
      * public methods.
      */
-    private boolean mHasFeature;
+    boolean mHasFeature;
 
     private final SecurityLogMonitor mSecurityLogMonitor;
 
@@ -328,7 +344,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
 
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
+            if (DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH.equals(intent.getAction())
                     && mRemoteBugreportServiceIsActive.get()) {
                 onBugreportFinished(intent);
             }
@@ -342,10 +358,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
             String action = intent.getAction();
             mInjector.getNotificationManager().cancel(LOG_TAG,
                     RemoteBugreportUtils.NOTIFICATION_ID);
-            if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
+            if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED.equals(action)) {
                 onBugreportSharingAccepted();
-            } else if (RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED
-                    .equals(action)) {
+            } else if (DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED.equals(action)) {
                 onBugreportSharingDeclined();
             }
             mContext.unregisterReceiver(mRemoteBugreportConsentReceiver);
@@ -437,15 +452,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                     && userHandle == mOwners.getDeviceOwnerUserId()
                     && getDeviceOwnerRemoteBugreportUri() != null) {
                 IntentFilter filterConsent = new IntentFilter();
-                filterConsent.addAction(
-                        RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED);
-                filterConsent.addAction(
-                        RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED);
+                filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
+                filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
                 mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
-                mInjector.getNotificationManager().notify(LOG_TAG,
+                mInjector.getNotificationManager().notifyAsUser(LOG_TAG,
                         RemoteBugreportUtils.NOTIFICATION_ID,
                         RemoteBugreportUtils.buildNotification(mContext,
-                                RemoteBugreportUtils.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED));
+                                DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
+                                UserHandle.ALL);
             }
             if (Intent.ACTION_BOOT_COMPLETED.equals(action)
                     || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
@@ -769,7 +783,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                 out.attribute(null, ATTR_VALUE, Boolean.toString(disableContactsSearch));
                 out.endTag(null, TAG_DISABLE_CONTACTS_SEARCH);
             }
-            if (disableBluetoothContactSharing) {
+            if (!disableBluetoothContactSharing) {
                 out.startTag(null, TAG_DISABLE_BLUETOOTH_CONTACT_SHARING);
                 out.attribute(null, ATTR_VALUE,
                         Boolean.toString(disableBluetoothContactSharing));
@@ -5068,9 +5082,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
             mRemoteBugreportServiceIsActive.set(true);
             mRemoteBugreportSharingAccepted.set(false);
             registerRemoteBugreportReceivers();
-            mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
                     RemoteBugreportUtils.buildNotification(mContext,
-                            RemoteBugreportUtils.NOTIFICATION_BUGREPORT_STARTED));
+                            DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED), UserHandle.ALL);
             mHandler.postDelayed(mRemoteBugreportTimeoutRunnable,
                     RemoteBugreportUtils.REMOTE_BUGREPORT_TIMEOUT_MILLIS);
             return true;
@@ -5104,7 +5118,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     private void registerRemoteBugreportReceivers() {
         try {
             IntentFilter filterFinished = new IntentFilter(
-                    RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_DISPATCH,
+                    DevicePolicyManager.ACTION_REMOTE_BUGREPORT_DISPATCH,
                     RemoteBugreportUtils.BUGREPORT_MIMETYPE);
             mContext.registerReceiver(mRemoteBugreportFinishedReceiver, filterFinished);
         } catch (IntentFilter.MalformedMimeTypeException e) {
@@ -5112,8 +5126,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
             Slog.w(LOG_TAG, "Failed to set type " + RemoteBugreportUtils.BUGREPORT_MIMETYPE, e);
         }
         IntentFilter filterConsent = new IntentFilter();
-        filterConsent.addAction(RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_DECLINED);
-        filterConsent.addAction(RemoteBugreportUtils.ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED);
+        filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED);
+        filterConsent.addAction(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED);
         mContext.registerReceiver(mRemoteBugreportConsentReceiver, filterConsent);
     }
 
@@ -5126,16 +5140,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
             bugreportUriString = bugreportUri.toString();
         }
         String bugreportHash = intent.getStringExtra(
-                RemoteBugreportUtils.EXTRA_REMOTE_BUGREPORT_HASH);
+                DevicePolicyManager.EXTRA_REMOTE_BUGREPORT_HASH);
         if (mRemoteBugreportSharingAccepted.get()) {
             shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
             mInjector.getNotificationManager().cancel(LOG_TAG,
                     RemoteBugreportUtils.NOTIFICATION_ID);
         } else {
             setDeviceOwnerRemoteBugreportUriAndHash(bugreportUriString, bugreportHash);
-            mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
                     RemoteBugreportUtils.buildNotification(mContext,
-                            RemoteBugreportUtils.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED));
+                            DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED),
+                            UserHandle.ALL);
         }
         mContext.unregisterReceiver(mRemoteBugreportFinishedReceiver);
     }
@@ -5166,9 +5181,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
         if (bugreportUriString != null) {
             shareBugreportWithDeviceOwnerIfExists(bugreportUriString, bugreportHash);
         } else if (mRemoteBugreportServiceIsActive.get()) {
-            mInjector.getNotificationManager().notify(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
+            mInjector.getNotificationManager().notifyAsUser(LOG_TAG, RemoteBugreportUtils.NOTIFICATION_ID,
                     RemoteBugreportUtils.buildNotification(mContext,
-                            RemoteBugreportUtils.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED));
+                            DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED),
+                            UserHandle.ALL);
         }
     }
 
@@ -5530,7 +5546,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
         Preconditions.checkNotNull(packageName, "packageName is null");
         final int callingUid = mInjector.binderGetCallingUid();
         try {
-            int uid = mContext.getPackageManager().getPackageUidAsUser(packageName, 0);
+            int uid = mContext.getPackageManager().getPackageUidAsUser(packageName,
+                    UserHandle.getUserId(callingUid));
             if (uid != callingUid) {
                 throw new SecurityException("Invalid packageName");
             }
@@ -5933,52 +5950,40 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     /**
      * The Device owner can only be set by adb or an app with the MANAGE_PROFILE_AND_DEVICE_OWNERS
      * permission.
-     * The device owner can only be set before the setup phase of the primary user has completed,
-     * except for adb if no accounts or additional users are present on the device.
      */
     private void enforceCanSetDeviceOwnerLocked(int userId) {
-        if (mOwners.hasDeviceOwner()) {
-            throw new IllegalStateException("Trying to set the device owner, but device owner "
-                    + "is already set.");
-        }
-        if (mOwners.hasProfileOwner(userId)) {
-            throw new IllegalStateException("Trying to set the device owner, but the user already "
-                    + "has a profile owner.");
-        }
-        if (!mUserManager.isUserRunning(new UserHandle(userId))) {
-            throw new IllegalStateException("User not running: " + userId);
-        }
-
         int callingUid = mInjector.binderGetCallingUid();
-        if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
-            if (!hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
-                return;
-            }
-            // STOPSHIP Do proper check in split user mode
-            if (!mInjector.userManagerIsSplitSystemUser()) {
-                if (mUserManager.getUserCount() > 1) {
-                    throw new IllegalStateException(
-                            "Not allowed to set the device owner because there "
-                                    + "are already several users on the device");
-                }
-                if (AccountManager.get(mContext).getAccounts().length > 0) {
-                    throw new IllegalStateException(
-                            "Not allowed to set the device owner because there "
-                                    + "are already some accounts on the device");
-                }
-            }
-            return;
+        boolean isAdb = callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID;
+        if (!isAdb) {
+            mContext.enforceCallingOrSelfPermission(
+                    android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
         }
-        // STOPSHIP check the caller UID with userId
 
-        mContext.enforceCallingOrSelfPermission(
-                android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
-        // STOPSHIP Do proper check in split user mode
-        if (!mInjector.userManagerIsSplitSystemUser()) {
-            if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
-                throw new IllegalStateException("Cannot set the device owner if the device is "
-                        + "already set-up");
-            }
+        final int code = checkSetDeviceOwnerPreCondition(userId, isAdb);
+        switch (code) {
+            case CODE_OK:
+                return;
+            case CODE_HAS_DEVICE_OWNER:
+                throw new IllegalStateException(
+                        "Trying to set the device owner, but device owner is already set.");
+            case CODE_USER_HAS_PROFILE_OWNER:
+                throw new IllegalStateException("Trying to set the device owner, but the user "
+                        + "already has a profile owner.");
+            case CODE_USER_NOT_RUNNING:
+                throw new IllegalStateException("User not running: " + userId);
+            case CODE_NOT_SYSTEM_USER:
+                throw new IllegalStateException("User is not system user");
+            case CODE_USER_SETUP_COMPLETED:
+                throw new IllegalStateException(
+                        "Cannot set the device owner if the device is already set-up");
+            case CODE_NONSYSTEM_USER_EXISTS:
+                throw new IllegalStateException("Not allowed to set the device owner because there "
+                        + "are already several users on the device");
+            case CODE_ACCOUNTS_NOT_EMPTY:
+                throw new IllegalStateException("Not allowed to set the device owner because there "
+                        + "are already some accounts on the device");
+            default:
+                throw new IllegalStateException("Unknown @DeviceOwnerPreConditionCode " + code);
         }
     }
 
@@ -7809,6 +7814,26 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                 listener.onCrossProfileWidgetProvidersChanged(userId, packages);
             }
         }
+
+        @Override
+        public boolean hasDeviceOwnerOrProfileOwner(String packageName, int userId) {
+            if (!mHasFeature || packageName == null) {
+                return false;
+            }
+            if (userId < 0) {
+                throw new UnsupportedOperationException("userId should be >= 0");
+            }
+            synchronized (DevicePolicyManagerService.this) {
+                if (packageName.equals(mOwners.getProfileOwnerPackage(userId))) {
+                    return true;
+                }
+                if (userId == mOwners.getDeviceOwnerUserId()
+                        && packageName.equals(mOwners.getDeviceOwnerPackageName())) {
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     /**
@@ -8035,6 +8060,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
 
     @Override
     public boolean isProvisioningAllowed(String action) {
+        if (!mHasFeature) {
+            return false;
+        }
+
         final int callingUserId = mInjector.userHandleGetCallingUserId();
         if (DevicePolicyManager.ACTION_PROVISION_MANAGED_PROFILE.equals(action)) {
             if (!hasFeatureManagedUsers()) {
@@ -8099,23 +8128,55 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
         throw new IllegalArgumentException("Unknown provisioning action " + action);
     }
 
-    private boolean isDeviceOwnerProvisioningAllowed(int callingUserId) {
-        synchronized (this) {
-            if (mOwners.hasDeviceOwner()) {
-                return false;
-            }
+    /*
+     * The device owner can only be set before the setup phase of the primary user has completed,
+     * except for adb command if no accounts or additional users are present on the device.
+     */
+    private synchronized @DeviceOwnerPreConditionCode int checkSetDeviceOwnerPreCondition(
+            int deviceOwnerUserId, boolean isAdb) {
+        if (mOwners.hasDeviceOwner()) {
+            return CODE_HAS_DEVICE_OWNER;
         }
-        if (getProfileOwner(callingUserId) != null) {
-            return false;
+        if (mOwners.hasProfileOwner(deviceOwnerUserId)) {
+            return CODE_USER_HAS_PROFILE_OWNER;
         }
-        if (mInjector.settingsGlobalGetInt(Settings.Global.DEVICE_PROVISIONED, 0) != 0) {
-            return false;
+        if (!mUserManager.isUserRunning(new UserHandle(deviceOwnerUserId))) {
+            return CODE_USER_NOT_RUNNING;
         }
-        if (callingUserId != UserHandle.USER_SYSTEM) {
-            // Device owner provisioning can only be initiated from system user.
-            return false;
+        if (isAdb) {
+            // if shell command runs after user setup completed check device status. Otherwise, OK.
+            if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
+                if (!mInjector.userManagerIsSplitSystemUser()) {
+                    if (mUserManager.getUserCount() > 1) {
+                        return CODE_NONSYSTEM_USER_EXISTS;
+                    }
+                    if (AccountManager.get(mContext).getAccounts().length > 0) {
+                        return CODE_ACCOUNTS_NOT_EMPTY;
+                    }
+                } else {
+                    // STOPSHIP Do proper check in split user mode
+                }
+            }
+            return CODE_OK;
+        } else {
+            if (!mInjector.userManagerIsSplitSystemUser()) {
+                // In non-split user mode, DO has to be user 0
+                if (deviceOwnerUserId != UserHandle.USER_SYSTEM) {
+                    return CODE_NOT_SYSTEM_USER;
+                }
+                // In non-split user mode, only provision DO before setup wizard completes
+                if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
+                    return CODE_USER_SETUP_COMPLETED;
+                }
+            } else {
+                // STOPSHIP Do proper check in split user mode
+            }
+            return CODE_OK;
         }
-        return true;
+    }
+
+    private boolean isDeviceOwnerProvisioningAllowed(int deviceOwnerUserId) {
+        return CODE_OK == checkSetDeviceOwnerPreCondition(deviceOwnerUserId, /* isAdb */ false);
     }
 
     private boolean hasFeatureManagedUsers() {
index 117ba15..6d42dc9 100644 (file)
@@ -19,8 +19,12 @@ package com.android.server.devicepolicy;
 import android.annotation.IntDef;
 import android.app.Notification;
 import android.app.PendingIntent;
+import android.app.admin.DevicePolicyManager;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
+import android.os.UserHandle;
+import android.provider.Settings;
 import android.text.format.DateUtils;
 
 import com.android.internal.R;
@@ -37,79 +41,62 @@ class RemoteBugreportUtils {
 
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
-        NOTIFICATION_BUGREPORT_STARTED,
-        NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
-        NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
+        DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED,
+        DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED,
+        DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED
     })
     @interface RemoteBugreportNotificationType {}
-    static final int NOTIFICATION_BUGREPORT_STARTED = 1;
-    static final int NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED = 2;
-    static final int NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED = 3;
 
     static final long REMOTE_BUGREPORT_TIMEOUT_MILLIS = 10 * DateUtils.MINUTE_IN_MILLIS;
 
     static final String CTL_STOP = "ctl.stop";
     static final String REMOTE_BUGREPORT_SERVICE = "bugreportremote";
 
-    static final String ACTION_REMOTE_BUGREPORT_DISPATCH =
-            "android.intent.action.REMOTE_BUGREPORT_DISPATCH";
-    static final String ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED =
-            "com.android.server.action.REMOTE_BUGREPORT_SHARING_ACCEPTED";
-    static final String ACTION_REMOTE_BUGREPORT_SHARING_DECLINED =
-            "com.android.server.action.REMOTE_BUGREPORT_SHARING_DECLINED";
-    static final String EXTRA_REMOTE_BUGREPORT_HASH = "android.intent.extra.REMOTE_BUGREPORT_HASH";
-
     static final String BUGREPORT_MIMETYPE = "application/vnd.android.bugreport";
 
     static Notification buildNotification(Context context,
             @RemoteBugreportNotificationType int type) {
+        Intent dialogIntent = new Intent(Settings.ACTION_SHOW_REMOTE_BUGREPORT_DIALOG);
+        dialogIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        dialogIntent.putExtra(DevicePolicyManager.EXTRA_BUGREPORT_NOTIFICATION_TYPE, type);
+        PendingIntent pendingDialogIntent = PendingIntent.getActivityAsUser(context, type,
+                dialogIntent, 0, null, UserHandle.CURRENT);
+
         Notification.Builder builder = new Notification.Builder(context)
                 .setSmallIcon(com.android.internal.R.drawable.stat_sys_adb)
                 .setOngoing(true)
                 .setLocalOnly(true)
+                .setPriority(Notification.PRIORITY_HIGH)
+                .setContentIntent(pendingDialogIntent)
                 .setColor(context.getColor(
                         com.android.internal.R.color.system_notification_accent_color));
 
-        if (type == NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
+        if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_ACCEPTED_NOT_FINISHED) {
             builder.setContentTitle(context.getString(
-                            R.string.sharing_remote_bugreport_notification_title))
-                    .setContentText(context.getString(
-                            R.string.sharing_remote_bugreport_notification_message))
-                    .setPriority(Notification.PRIORITY_HIGH)
-                    .setProgress(0, 0, true)
-                    .setStyle(new Notification.BigTextStyle().bigText(context.getString(
-                            R.string.sharing_remote_bugreport_notification_message)));
-        } else {
+                        R.string.sharing_remote_bugreport_notification_title))
+                    .setProgress(0, 0, true);
+        } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_STARTED) {
+            builder.setContentTitle(context.getString(
+                        R.string.taking_remote_bugreport_notification_title))
+                    .setProgress(0, 0, true);
+        } else if (type == DevicePolicyManager.NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
             PendingIntent pendingIntentAccept = PendingIntent.getBroadcast(context, NOTIFICATION_ID,
-                    new Intent(ACTION_REMOTE_BUGREPORT_SHARING_ACCEPTED),
+                    new Intent(DevicePolicyManager.ACTION_BUGREPORT_SHARING_ACCEPTED),
                     PendingIntent.FLAG_CANCEL_CURRENT);
             PendingIntent pendingIntentDecline = PendingIntent.getBroadcast(context,
-                    NOTIFICATION_ID, new Intent(ACTION_REMOTE_BUGREPORT_SHARING_DECLINED),
+                    NOTIFICATION_ID, new Intent(
+                            DevicePolicyManager.ACTION_BUGREPORT_SHARING_DECLINED),
                     PendingIntent.FLAG_CANCEL_CURRENT);
             builder.addAction(new Notification.Action.Builder(null /* icon */, context.getString(
-                            R.string.share_remote_bugreport_notification_decline),
-                            pendingIntentDecline).build())
+                        R.string.decline_remote_bugreport_action), pendingIntentDecline).build())
                     .addAction(new Notification.Action.Builder(null /* icon */, context.getString(
-                            R.string.share_remote_bugreport_notification_accept),
-                            pendingIntentAccept).build())
+                        R.string.share_remote_bugreport_action), pendingIntentAccept).build())
                     .setContentTitle(context.getString(
-                            R.string.share_remote_bugreport_notification_title));
-
-            if (type == NOTIFICATION_BUGREPORT_STARTED) {
-                builder.setContentText(context.getString(
-                                R.string.share_remote_bugreport_notification_message))
-                        .setStyle(new Notification.BigTextStyle().bigText(context.getString(
-                                R.string.share_remote_bugreport_notification_message)))
-                        .setProgress(0, 0, true)
-                        .setPriority(Notification.PRIORITY_MAX)
-                        .setVibrate(new long[0]);
-            } else if (type == NOTIFICATION_BUGREPORT_FINISHED_NOT_ACCEPTED) {
-                builder.setContentText(context.getString(
-                                R.string.share_finished_remote_bugreport_notification_message))
-                        .setStyle(new Notification.BigTextStyle().bigText(context.getString(
-                                R.string.share_finished_remote_bugreport_notification_message)))
-                        .setPriority(Notification.PRIORITY_HIGH);
-            }
+                        R.string.share_remote_bugreport_notification_title))
+                    .setContentText(context.getString(
+                        R.string.share_remote_bugreport_notification_message_finished))
+                    .setStyle(new Notification.BigTextStyle().bigText(context.getString(
+                        R.string.share_remote_bugreport_notification_message_finished)));
         }
 
         return builder.build();
index 0ece6aa..b8c31e3 100644 (file)
@@ -431,6 +431,24 @@ public final class SystemServer {
         mPackageManager = mSystemContext.getPackageManager();
         Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
 
+        // Manages A/B OTA dexopting. This is a bootstrap service as we need it to rename
+        // A/B artifacts after boot, before anything else might touch/need them.
+        // Note: this isn't needed during decryption (we don't have /data anyways).
+        if (!mOnlyCore) {
+            boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
+                    false);
+            if (!disableOtaDexopt) {
+                traceBeginAndSlog("StartOtaDexOptService");
+                try {
+                    OtaDexoptService.main(mSystemContext, mPackageManagerService);
+                } catch (Throwable e) {
+                    reportWtf("starting OtaDexOptService", e);
+                } finally {
+                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
+                }
+            }
+        }
+
         traceBeginAndSlog("StartUserManagerService");
         ServiceManager.addService(Context.USER_SERVICE, UserManagerService.getInstance());
         Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
@@ -1036,6 +1054,7 @@ public final class SystemServer {
                 traceBeginAndSlog("StartNetworkTimeUpdateService");
                 try {
                     networkTimeUpdater = new NetworkTimeUpdateService(context);
+                    ServiceManager.addService("network_time_update_service", networkTimeUpdater);
                 } catch (Throwable e) {
                     reportWtf("starting NetworkTimeUpdate service", e);
                 }
@@ -1123,19 +1142,6 @@ public final class SystemServer {
                     reportWtf("starting BackgroundDexOptService", e);
                 }
                 Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-
-                // Manages A/B OTA dexopting.
-                boolean disableOtaDexopt = SystemProperties.getBoolean("config.disable_otadexopt",
-                        false);
-                if (!disableOtaDexopt) {
-                    traceBeginAndSlog("StartOtaDexOptService");
-                    try {
-                        OtaDexoptService.main(mSystemContext, mPackageManagerService);
-                    } catch (Throwable e) {
-                        reportWtf("starting BackgroundDexOptService", e);
-                    }
-                    Trace.traceEnd(Trace.TRACE_TAG_SYSTEM_SERVER);
-                }
             }
 
             mSystemServiceManager.startService(LauncherAppsService.class);
index 4f99bff..e2562cd 100644 (file)
@@ -84,10 +84,10 @@ import static android.net.dhcp.DhcpPacket.*;
 public class DhcpClient extends StateMachine {
 
     private static final String TAG = "DhcpClient";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean STATE_DBG = false;
     private static final boolean MSG_DBG = false;
-    private static final boolean PACKET_DBG = true;
+    private static final boolean PACKET_DBG = false;
 
     // Timers and timeouts.
     private static final int SECONDS = 1000;
@@ -342,14 +342,14 @@ public class DhcpClient extends StateMachine {
 
         @Override
         public void run() {
-            maybeLog("Receive thread started");
+            if (DBG) Log.d(TAG, "Receive thread started");
             while (!stopped) {
                 int length = 0;  // Or compiler can't tell it's initialized if a parse error occurs.
                 try {
                     length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
                     DhcpPacket packet = null;
                     packet = DhcpPacket.decodeFullPacket(mPacket, length, DhcpPacket.ENCAP_L2);
-                    maybeLog("Received packet: " + packet);
+                    if (DBG) Log.d(TAG, "Received packet: " + packet);
                     sendMessage(CMD_RECEIVED_PACKET, packet);
                 } catch (IOException|ErrnoException e) {
                     if (!stopped) {
@@ -362,7 +362,7 @@ public class DhcpClient extends StateMachine {
                     }
                 }
             }
-            maybeLog("Receive thread stopped");
+            if (DBG) Log.d(TAG, "Receive thread stopped");
         }
     }
 
@@ -373,12 +373,12 @@ public class DhcpClient extends StateMachine {
     private boolean transmitPacket(ByteBuffer buf, String description, Inet4Address to) {
         try {
             if (to.equals(INADDR_BROADCAST)) {
-                maybeLog("Broadcasting " + description);
+                if (DBG) Log.d(TAG, "Broadcasting " + description);
                 Os.sendto(mPacketSock, buf.array(), 0, buf.limit(), 0, mInterfaceBroadcastAddr);
             } else {
                 // It's safe to call getpeername here, because we only send unicast packets if we
                 // have an IP address, and we connect the UDP socket in DhcpHaveAddressState#enter.
-                maybeLog("Unicasting " + description + " to " + Os.getpeername(mUdpSock));
+                if (DBG) Log.d(TAG, "Unicasting " + description + " to " + Os.getpeername(mUdpSock));
                 Os.write(mUdpSock, buf);
             }
         } catch(ErrnoException|IOException e) {
@@ -454,10 +454,6 @@ public class DhcpClient extends StateMachine {
         mController.sendMessage(CMD_ON_QUIT);
     }
 
-    private void maybeLog(String msg) {
-        if (DBG) Log.d(TAG, msg);
-    }
-
     abstract class LoggingState extends State {
         public void enter() {
             if (STATE_DBG) Log.d(TAG, "Entering state " + getName());
@@ -592,7 +588,7 @@ public class DhcpClient extends StateMachine {
                     transitionTo(mStoppedState);
                     return HANDLED;
                 case CMD_ONESHOT_TIMEOUT:
-                    maybeLog("Timed out");
+                    if (DBG) Log.d(TAG, "Timed out");
                     notifyFailure();
                     return HANDLED;
                 default:
@@ -790,7 +786,7 @@ public class DhcpClient extends StateMachine {
 
         @Override
         public void exit() {
-            maybeLog("Clearing IP address");
+            if (DBG) Log.d(TAG, "Clearing IP address");
             setIpAddress(new LinkAddress("0.0.0.0/0"));
         }
     }
index 2a90c60..c7c5015 100644 (file)
@@ -63,12 +63,9 @@ import java.util.Objects;
  * @hide
  */
 public class IpManager extends StateMachine {
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false;
 
-    private static final boolean NO_CALLBACKS = false;
-    private static final boolean SEND_CALLBACKS = true;
-
     // For message logging.
     private static final Class[] sMessageClasses = { IpManager.class, DhcpClient.class };
     private static final SparseArray<String> sWhatToString =
@@ -98,6 +95,10 @@ public class IpManager extends StateMachine {
         public void onProvisioningSuccess(LinkProperties newLp) {}
         public void onProvisioningFailure(LinkProperties newLp) {}
 
+        // This is called whenever 464xlat is being enabled or disabled (i.e.
+        // started or stopped).
+        public void on464XlatChange(boolean enabled) {}
+
         // Invoked on LinkProperties changes.
         public void onLinkPropertiesChange(LinkProperties newLp) {}
 
@@ -207,6 +208,13 @@ public class IpManager extends StateMachine {
 
     private static final int MAX_LOG_RECORDS = 1000;
 
+    private static final boolean NO_CALLBACKS = false;
+    private static final boolean SEND_CALLBACKS = true;
+
+    // This must match the interface prefix in clatd.c.
+    // TODO: Revert this hack once IpManager and Nat464Xlat work in concert.
+    private static final String CLAT_PREFIX = "v4-";
+
     private final Object mLock = new Object();
     private final State mStoppedState = new StoppedState();
     private final State mStoppingState = new StoppingState();
@@ -215,6 +223,7 @@ public class IpManager extends StateMachine {
     private final String mTag;
     private final Context mContext;
     private final String mInterfaceName;
+    private final String mClatInterfaceName;
     @VisibleForTesting
     protected final Callback mCallback;
     private final INetworkManagementService mNwService;
@@ -241,15 +250,23 @@ public class IpManager extends StateMachine {
 
     public IpManager(Context context, String ifName, Callback callback)
                 throws IllegalArgumentException {
+        this(context, ifName, callback, INetworkManagementService.Stub.asInterface(
+                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE)));
+    }
+
+    /**
+     * An expanded constructor, useful for dependency injection.
+     */
+    public IpManager(Context context, String ifName, Callback callback,
+            INetworkManagementService nwService) throws IllegalArgumentException {
         super(IpManager.class.getSimpleName() + "." + ifName);
         mTag = getName();
 
         mContext = context;
         mInterfaceName = ifName;
+        mClatInterfaceName = CLAT_PREFIX + ifName;
         mCallback = callback;
-
-        mNwService = INetworkManagementService.Stub.asInterface(
-                ServiceManager.getService(Context.NETWORKMANAGEMENT_SERVICE));
+        mNwService = nwService;
 
         mNetlinkTracker = new NetlinkTracker(
                 mInterfaceName,
@@ -258,7 +275,22 @@ public class IpManager extends StateMachine {
                     public void update() {
                         sendMessage(EVENT_NETLINK_LINKPROPERTIES_CHANGED);
                     }
-                });
+                }) {
+            @Override
+            public void interfaceAdded(String iface) {
+                if (mClatInterfaceName.equals(iface)) {
+                    mCallback.on464XlatChange(true);
+                }
+            }
+
+            @Override
+            public void interfaceRemoved(String iface) {
+                if (mClatInterfaceName.equals(iface)) {
+                    mCallback.on464XlatChange(false);
+                }
+            }
+        };
+
         try {
             mNwService.registerObserver(mNetlinkTracker);
         } catch (RemoteException e) {
@@ -277,25 +309,6 @@ public class IpManager extends StateMachine {
         super.start();
     }
 
-    /**
-     * A special constructor for use in testing that bypasses some of the more
-     * complicated setup bits.
-     *
-     * TODO: Figure out how to delete this yet preserve testability.
-     */
-    @VisibleForTesting
-    protected IpManager(String ifName, Callback callback) {
-        super(IpManager.class.getSimpleName() + ".test-" + ifName);
-        mTag = getName();
-
-        mInterfaceName = ifName;
-        mCallback = callback;
-
-        mContext = null;
-        mNwService = null;
-        mNetlinkTracker = null;
-    }
-
     @Override
     protected void onQuitting() {
         mCallback.onQuit();
index 88155f7..5b4fd50 100644 (file)
@@ -132,7 +132,7 @@ import java.util.Set;
  */
 public class IpReachabilityMonitor {
     private static final String TAG = "IpReachabilityMonitor";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
     private static final boolean VDBG = false;
 
     public interface Callback {
index 5874429..69f12eb 100644 (file)
@@ -59,14 +59,17 @@ import android.os.Message;
 import android.os.MessageQueue;
 import android.os.Messenger;
 import android.os.MessageQueue.IdleHandler;
+import android.os.SystemClock;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.test.suitebuilder.annotation.SmallTest;
 import android.util.Log;
 import android.util.LogPrinter;
 
+import com.android.internal.util.WakeupMessage;
 import com.android.server.connectivity.NetworkAgentInfo;
 import com.android.server.connectivity.NetworkMonitor;
+import com.android.server.net.NetworkPinner;
 
 import java.net.InetAddress;
 import java.util.concurrent.CountDownLatch;
@@ -87,10 +90,30 @@ public class ConnectivityServiceTest extends AndroidTestCase {
 
     private BroadcastInterceptingContext mServiceContext;
     private WrappedConnectivityService mService;
-    private ConnectivityManager mCm;
+    private WrappedConnectivityManager mCm;
     private MockNetworkAgent mWiFiNetworkAgent;
     private MockNetworkAgent mCellNetworkAgent;
 
+    // This class exists to test bindProcessToNetwork and getBoundNetworkForProcess. These methods
+    // do not go through ConnectivityService but talk to netd directly, so they don't automatically
+    // reflect the state of our test ConnectivityService.
+    private class WrappedConnectivityManager extends ConnectivityManager {
+        private Network mFakeBoundNetwork;
+
+        public synchronized boolean bindProcessToNetwork(Network network) {
+            mFakeBoundNetwork = network;
+            return true;
+        }
+
+        public synchronized Network getBoundNetworkForProcess() {
+            return mFakeBoundNetwork;
+        }
+
+        public WrappedConnectivityManager(Context context, ConnectivityService service) {
+            super(context, service);
+        }
+    }
+
     private class MockContext extends BroadcastInterceptingContext {
         MockContext(Context base) {
             super(base);
@@ -484,6 +507,35 @@ public class ConnectivityServiceTest extends AndroidTestCase {
         }
     }
 
+    private class FakeWakeupMessage extends WakeupMessage {
+        private static final int UNREASONABLY_LONG_WAIT = 1000;
+
+        public FakeWakeupMessage(Context context, Handler handler, String cmdName, int cmd) {
+            super(context, handler, cmdName, cmd);
+        }
+
+        @Override
+        public void schedule(long when) {
+            long delayMs = when - SystemClock.elapsedRealtime();
+            if (delayMs < 0) delayMs = 0;
+            if (delayMs > UNREASONABLY_LONG_WAIT) {
+                fail("Attempting to send msg more than " + UNREASONABLY_LONG_WAIT +
+                        "ms into the future: " + delayMs);
+            }
+            mHandler.sendEmptyMessageDelayed(mCmd, delayMs);
+        }
+
+        @Override
+        public void cancel() {
+            mHandler.removeMessages(mCmd);
+        }
+
+        @Override
+        public void onAlarm() {
+            throw new AssertionError("Should never happen. Update this fake.");
+        }
+    }
+
     // NetworkMonitor implementation allowing overriding of Internet connectivity probe result.
     private class WrappedNetworkMonitor extends NetworkMonitor {
         // HTTP response code fed back to NetworkMonitor for Internet connectivity probe.
@@ -498,6 +550,12 @@ public class ConnectivityServiceTest extends AndroidTestCase {
         protected int isCaptivePortal() {
             return gen204ProbeResult;
         }
+
+        @Override
+        protected WakeupMessage makeWakeupMessage(
+                Context context, Handler handler, String cmdName, int cmd) {
+            return new FakeWakeupMessage(context, handler, cmdName, cmd);
+        }
     }
 
     private class WrappedConnectivityService extends ConnectivityService {
@@ -575,10 +633,10 @@ public class ConnectivityServiceTest extends AndroidTestCase {
         int delays = 0;
         while (!criteria.get()) {
             try {
-                Thread.sleep(100);
+                Thread.sleep(50);
             } catch (InterruptedException e) {
             }
-            if (++delays == 5) fail();
+            if (++delays == 10) fail();
         }
     }
 
@@ -594,6 +652,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
     public void setUp() throws Exception {
         super.setUp();
 
+        NetworkMonitor.SetDefaultLingerTime(120);
+
         // InstrumentationTestRunner prepares a looper, but AndroidJUnitRunner does not.
         // http://b/25897652 .
         if (Looper.myLooper() == null) {
@@ -607,7 +667,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
                 mock(INetworkPolicyManager.class));
 
         mService.systemReady();
-        mCm = new ConnectivityManager(getContext(), mService);
+        mCm = new WrappedConnectivityManager(getContext(), mService);
+        mCm.bindProcessToNetwork(null);
     }
 
     private int transportToLegacyType(int transport) {
@@ -674,8 +735,6 @@ public class ConnectivityServiceTest extends AndroidTestCase {
 
     @LargeTest
     public void testLingering() throws Exception {
-        // Decrease linger timeout to the minimum allowed by AlarmManagerService.
-        NetworkMonitor.SetDefaultLingerTime(5000);
         verifyNoNetwork();
         mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
         mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
@@ -702,10 +761,8 @@ public class ConnectivityServiceTest extends AndroidTestCase {
         assertTrue(mCm.getAllNetworks()[0].equals(mCellNetworkAgent.getNetwork()) ||
                 mCm.getAllNetworks()[1].equals(mCellNetworkAgent.getNetwork()));
         // Test cellular linger timeout.
-        try {
-            Thread.sleep(6000);
-        } catch (InterruptedException e) {
-        }
+        waitFor(new Criteria() {
+                public boolean get() { return mCm.getAllNetworks().length == 1; } });
         verifyActiveNetwork(TRANSPORT_WIFI);
         assertEquals(1, mCm.getAllNetworks().length);
         assertEquals(mCm.getAllNetworks()[0], mCm.getActiveNetwork());
@@ -1543,4 +1600,103 @@ public class ConnectivityServiceTest extends AndroidTestCase {
         String url = mCm.getCaptivePortalServerUrl();
         assertEquals("http://connectivitycheck.gstatic.com/generate_204", url);
     }
+
+    private static class TestNetworkPinner extends NetworkPinner {
+        public static boolean awaitPin(int timeoutMs) {
+            synchronized(sLock) {
+                if (sNetwork == null) {
+                    try {
+                        sLock.wait(timeoutMs);
+                    } catch (InterruptedException e) {}
+                }
+                return sNetwork != null;
+            }
+        }
+
+        public static boolean awaitUnpin(int timeoutMs) {
+            synchronized(sLock) {
+                if (sNetwork != null) {
+                    try {
+                        sLock.wait(timeoutMs);
+                    } catch (InterruptedException e) {}
+                }
+                return sNetwork == null;
+            }
+        }
+    }
+
+    private void assertPinnedToWifiWithCellDefault() {
+        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+    }
+
+    private void assertPinnedToWifiWithWifiDefault() {
+        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getBoundNetworkForProcess());
+        assertEquals(mWiFiNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+    }
+
+    private void assertNotPinnedToWifi() {
+        assertNull(mCm.getBoundNetworkForProcess());
+        assertEquals(mCellNetworkAgent.getNetwork(), mCm.getActiveNetwork());
+    }
+
+    @SmallTest
+    public void testNetworkPinner() {
+        NetworkRequest wifiRequest = new NetworkRequest.Builder()
+                .addTransportType(TRANSPORT_WIFI)
+                .build();
+        assertNull(mCm.getBoundNetworkForProcess());
+
+        TestNetworkPinner.pin(mServiceContext, wifiRequest);
+        assertNull(mCm.getBoundNetworkForProcess());
+
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_CELLULAR);
+        mCellNetworkAgent.connect(true);
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+
+        // When wi-fi connects, expect to be pinned.
+        assertTrue(TestNetworkPinner.awaitPin(100));
+        assertPinnedToWifiWithCellDefault();
+
+        // Disconnect and expect the pin to drop.
+        mWiFiNetworkAgent.disconnect();
+        assertTrue(TestNetworkPinner.awaitUnpin(100));
+        assertNotPinnedToWifi();
+
+        // Reconnecting does not cause the pin to come back.
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+        assertFalse(TestNetworkPinner.awaitPin(100));
+        assertNotPinnedToWifi();
+
+        // Pinning while connected causes the pin to take effect immediately.
+        TestNetworkPinner.pin(mServiceContext, wifiRequest);
+        assertTrue(TestNetworkPinner.awaitPin(100));
+        assertPinnedToWifiWithCellDefault();
+
+        // Explicitly unpin and expect to use the default network again.
+        TestNetworkPinner.unpin();
+        assertNotPinnedToWifi();
+
+        // Disconnect cell and wifi.
+        ConditionVariable cv = waitForConnectivityBroadcasts(3);  // cell down, wifi up, wifi down.
+        mCellNetworkAgent.disconnect();
+        mWiFiNetworkAgent.disconnect();
+        waitFor(cv);
+
+        // Pinning takes effect even if the pinned network is the default when the pin is set...
+        TestNetworkPinner.pin(mServiceContext, wifiRequest);
+        mWiFiNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mWiFiNetworkAgent.connect(false);
+        assertTrue(TestNetworkPinner.awaitPin(100));
+        assertPinnedToWifiWithWifiDefault();
+
+        // ... and is maintained even when that network is no longer the default.
+        cv = waitForConnectivityBroadcasts(1);
+        mCellNetworkAgent = new MockNetworkAgent(TRANSPORT_WIFI);
+        mCellNetworkAgent.connect(true);
+        waitFor(cv);
+        assertPinnedToWifiWithCellDefault();
+    }
 }
index 212b37c..8c47087 100644 (file)
@@ -969,6 +969,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
 
         mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
 
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
+
         // Make sure the admin packge is installed to each user.
         setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
         setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_SYSTEM_USER_UID);
@@ -1008,6 +1010,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
      * finds the right component from a package name upon migration.
      */
     public void testDeviceOwnerMigration() throws Exception {
+        when(mContext.userManagerForMock.isSplitSystemUser()).thenReturn(true);
         checkDeviceOwnerWithMultipleDeviceAdmins();
 
         // Overwrite the device owner setting and clears the clas name.
index 8b250f4..8da1785 100644 (file)
@@ -437,7 +437,7 @@ public class UsageStatsService extends SystemService implements
                 return false;
             }
         } catch (RemoteException re) {
-            return false;
+            throw re.rethrowFromSystemServer();
         }
 
         final long elapsedRealtime = SystemClock.elapsedRealtime();
@@ -805,6 +805,7 @@ public class UsageStatsService extends SystemService implements
                 return false;
             }
         } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
         }
 
         if (isActiveDeviceAdmin(packageName, userId)) {
@@ -849,7 +850,7 @@ public class UsageStatsService extends SystemService implements
             }
             apps = slice.getList();
         } catch (RemoteException e) {
-            return new int[0];
+            throw e.rethrowFromSystemServer();
         }
 
         // State of each uid.  Key is the uid.  Value lower 16 bits is the number of apps
@@ -1258,7 +1259,7 @@ public class UsageStatsService extends SystemService implements
                 userId = ActivityManagerNative.getDefault().handleIncomingUser(Binder.getCallingPid(),
                         Binder.getCallingUid(), userId, false, true, "isAppInactive", null);
             } catch (RemoteException re) {
-                return false;
+                throw re.rethrowFromSystemServer();
             }
             final long token = Binder.clearCallingIdentity();
             try {
@@ -1277,7 +1278,7 @@ public class UsageStatsService extends SystemService implements
                         Binder.getCallingPid(), callingUid, userId, false, true,
                         "setAppIdle", null);
             } catch (RemoteException re) {
-                return;
+                throw re.rethrowFromSystemServer();
             }
             getContext().enforceCallingPermission(Manifest.permission.CHANGE_APP_IDLE_STATE,
                     "No permission to change app idle state");
index 6ab0b99..837b4a4 100644 (file)
@@ -75,7 +75,7 @@ import java.util.List;
  */
 public class VoiceInteractionManagerService extends SystemService {
     static final String TAG = "VoiceInteractionManagerService";
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
 
     final Context mContext;
     final ContentResolver mResolver;
index de90202..10808da 100644 (file)
@@ -624,6 +624,21 @@ public final class Call {
                     parcelableCall.getExtras(),
                     parcelableCall.getIntentExtras());
         }
+
+        @Override
+        public String toString() {
+            StringBuilder sb = new StringBuilder();
+            sb.append("[pa: ");
+            sb.append(mAccountHandle);
+            sb.append(", hdl: ");
+            sb.append(Log.pii(mHandle));
+            sb.append(", caps: ");
+            sb.append(capabilitiesToString(mCallCapabilities));
+            sb.append(", props: ");
+            sb.append(mCallProperties);
+            sb.append("]");
+            return sb.toString();
+        }
     }
 
     public static abstract class Callback {
@@ -1000,6 +1015,48 @@ public final class Call {
         }
     }
 
+    @Override
+    public String toString() {
+        return new StringBuilder().
+                append("Call [id: ").
+                append(mTelecomCallId).
+                append(", state: ").
+                append(stateToString(mState)).
+                append(", details: ").
+                append(mDetails).
+                append("]").toString();
+    }
+
+    /**
+     * @param state An integer value of a {@code STATE_*} constant.
+     * @return A string representation of the value.
+     */
+    private static String stateToString(int state) {
+        switch (state) {
+            case STATE_NEW:
+                return "NEW";
+            case STATE_RINGING:
+                return "RINGING";
+            case STATE_DIALING:
+                return "DIALING";
+            case STATE_ACTIVE:
+                return "ACTIVE";
+            case STATE_HOLDING:
+                return "HOLDING";
+            case STATE_DISCONNECTED:
+                return "DISCONNECTED";
+            case STATE_CONNECTING:
+                return "CONNECTING";
+            case STATE_DISCONNECTING:
+                return "DISCONNECTING";
+            case STATE_SELECT_PHONE_ACCOUNT:
+                return "SELECT_PHONE_ACCOUNT";
+            default:
+                Log.w(Call.class, "Unknown state %d", state);
+                return "UNKNOWN";
+        }
+    }
+
     /**
      * Adds a listener to this {@code Call}.
      *
index 3f32dbe..2ab0525 100644 (file)
 
 package android.telecom;
 
+import android.net.Uri;
 import android.os.AsyncTask;
+import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
 
 import java.security.MessageDigest;
 import java.security.NoSuchAlgorithmException;
@@ -152,10 +155,37 @@ final public class Log {
     public static String pii(Object pii) {
         if (pii == null || VERBOSE) {
             return String.valueOf(pii);
+        } if (pii instanceof Uri) {
+            return piiUri((Uri) pii);
         }
         return "[" + secureHash(String.valueOf(pii).getBytes()) + "]";
     }
 
+    private static String piiUri(Uri handle) {
+        StringBuilder sb = new StringBuilder();
+        String scheme = handle.getScheme();
+        if (!TextUtils.isEmpty(scheme)) {
+            sb.append(scheme).append(":");
+        }
+        String value = handle.getSchemeSpecificPart();
+        if (!TextUtils.isEmpty(value)) {
+            for (int i = 0; i < value.length(); i++) {
+                char c = value.charAt(i);
+                if (PhoneNumberUtils.isStartsPostDial(c)) {
+                    sb.append(c);
+                } else if (PhoneNumberUtils.isDialable(c)) {
+                    sb.append("*");
+                } else if (('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
+                    sb.append("*");
+                } else {
+                    sb.append(c);
+                }
+            }
+        }
+        return sb.toString();
+
+    }
+
     private static String secureHash(byte[] input) {
         if (sMessageDigest != null) {
             sMessageDigest.reset();
index 857d2df..605e0d3 100644 (file)
@@ -1425,6 +1425,7 @@ public class TelecomManager {
      * <p> This method displays the UI to manage blocked numbers only if
      * {@link android.provider.BlockedNumberContract#canCurrentUserBlockNumbers(Context)} returns
      * {@code true} for the current user.
+     * @deprecated Use {@link #createManageBlockedNumbersIntent()} instead.
      */
     // TODO: Delete this.
     public void launchManageBlockedNumbersActivity() {
index 1278c07..cd1c5e9 100644 (file)
@@ -637,7 +637,7 @@ public class CarrierConfigManager {
         sDefaults.putBoolean(KEY_SHOW_CDMA_CHOICES_BOOL, false);
         sDefaults.putBoolean(KEY_SHOW_ONSCREEN_DIAL_BUTTON_BOOL, true);
         sDefaults.putBoolean(KEY_SIM_NETWORK_UNLOCK_ALLOW_DISMISS_BOOL, true);
-        sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, true);
+        sDefaults.putBoolean(KEY_SUPPORT_PAUSE_IMS_VIDEO_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_SUPPORT_SWAP_AFTER_MERGE_BOOL, true);
         sDefaults.putBoolean(KEY_USE_HFA_FOR_PROVISIONING_BOOL, false);
         sDefaults.putBoolean(KEY_USE_OTASP_FOR_PROVISIONING_BOOL, false);
index ad007c6..39a9295 100644 (file)
@@ -36,7 +36,7 @@ import android.telephony.Rlog;
 public class ServiceState implements Parcelable {
 
     static final String LOG_TAG = "PHONE";
-    static final boolean DBG = true;
+    static final boolean DBG = false;
     static final boolean VDBG = false;  // STOPSHIP if true
 
     /**
index e90be91..b482811 100644 (file)
@@ -4403,7 +4403,6 @@ public class TelephonyManager {
             Log.e(TAG, "Error calling ITelephony#getDataEnabled", e);
         } catch (NullPointerException e) {
         }
-        Log.d(TAG, "getDataEnabled: retVal=" + retVal);
         return retVal;
     }
 
index da43460..e851c8d 100644 (file)
@@ -25,7 +25,6 @@ import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.EphemeralApplicationInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
@@ -44,7 +43,6 @@ import android.content.pm.PermissionInfo;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -520,6 +518,14 @@ public class MockPackageManager extends PackageManager {
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+            int badgeDensity) {
+        throw new UnsupportedOperationException();
+    }
+
+
     @Override
     public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
         throw new UnsupportedOperationException();
@@ -602,14 +608,6 @@ public class MockPackageManager extends PackageManager {
         throw new UnsupportedOperationException();
     }
 
-    /** @hide */
-    @Override
-    public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,
-            int flags, String installerPackageName, int userId) {
-        throw new UnsupportedOperationException();
-    }
-
-
     @Override
     public void setInstallerPackageName(String targetPackage,
             String installerPackageName) {
@@ -873,26 +871,6 @@ public class MockPackageManager extends PackageManager {
      * @hide
      */
     @Override
-    public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
-            int flags, String installerPackageName, Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
     public boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden,
             UserHandle user) {
         return false;
@@ -1024,27 +1002,6 @@ public class MockPackageManager extends PackageManager {
      * @hide
      */
     @Override
-    public void installPackageWithVerification(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-        throw new UnsupportedOperationException();
-    }
-
-    /**
-     * @hide
-     */
-    @Override
     public void addCrossProfileIntentFilter(IntentFilter filter, int sourceUserId, int targetUserId,
             int flags) {
         throw new UnsupportedOperationException();
diff --git a/tests/HwAccelerationTest/res/drawable/default_wallpaper.jpg b/tests/HwAccelerationTest/res/drawable/default_wallpaper.jpg
deleted file mode 100644 (file)
index 5acad94..0000000
Binary files a/tests/HwAccelerationTest/res/drawable/default_wallpaper.jpg and /dev/null differ
diff --git a/tests/HwAccelerationTest/res/drawable/default_wallpaper.png b/tests/HwAccelerationTest/res/drawable/default_wallpaper.png
new file mode 100644 (file)
index 0000000..187a6c0
Binary files /dev/null and b/tests/HwAccelerationTest/res/drawable/default_wallpaper.png differ
index 1f2b939..1ea9f9c 100644 (file)
@@ -3,24 +3,32 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
-    <FrameLayout
+    <ScrollView
+        android:orientation="vertical"
         android:translationX="50dp"
         android:translationY="50dp"
         android:elevation="30dp"
         android:layout_width="200dp"
         android:layout_height="200dp"
         android:background="@drawable/round_rect_background">
-        <View
-            android:id="@+id/clickable1"
-            android:layout_width="100dp"
-            android:layout_height="100dp"
-            android:background="?android:attr/selectableItemBackgroundBorderless"/>
-        <View
-            android:id="@+id/clickable2"
-            android:translationX="50dp"
-            android:translationY="10dp"
-            android:layout_width="150dp"
-            android:layout_height="100dp"
-            android:background="?android:attr/selectableItemBackgroundBorderless"/>
-    </FrameLayout>
+        <FrameLayout
+            android:layout_width="200dp"
+            android:layout_height="wrap_content">
+            <View
+                android:layout_width="200dp"
+                android:layout_height="2000dp"/>
+            <View
+                android:id="@+id/clickable1"
+                android:layout_width="100dp"
+                android:layout_height="100dp"
+                android:background="?android:attr/selectableItemBackgroundBorderless"/>
+            <View
+                android:id="@+id/clickable2"
+                android:translationX="50dp"
+                android:translationY="10dp"
+                android:layout_width="150dp"
+                android:layout_height="100dp"
+                android:background="?android:attr/selectableItemBackgroundBorderless"/>
+       </FrameLayout>
+    </ScrollView>
 </LinearLayout>
index c8a8d6c..6463e1f 100644 (file)
@@ -47,7 +47,7 @@ public class LocalRenderer extends Renderer implements OnPreparedListener,
         OnBufferingUpdateListener, OnCompletionListener, OnErrorListener,
         OnAudioFocusChangeListener {
     private static final String TAG = "MediaPlayerManager";
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
     private static long sDebugInstanceId = 0;
 
     private static final String[] SUPPORTED_FEATURES = {
index 4770c05..3ca96d2 100644 (file)
@@ -40,7 +40,7 @@ import android.widget.Toast;
 
 public class TestSoundTriggerActivity extends Activity {
     private static final String TAG = "TestSoundTriggerActivity";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     private SoundTriggerUtil mSoundTriggerUtil;
     private Random mRandom;
index 407a9d7..ac562b9 100644 (file)
@@ -18,7 +18,14 @@ include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := tests
 
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
+ifeq ($(SOUND_TRIGGER_USE_STUB_MODULE), 1)
+  LOCAL_SRC_FILES := $(call all-subdir-java-files)
+  LOCAL_PRIVILEGED_MODULE := true
+  LOCAL_CERTIFICATE := platform
+  TARGET_OUT_DATA_APPS_PRIVILEGED := $(TARGET_OUT_DATA)/priv-app
+else
+  LOCAL_SRC_FILES := src/android/hardware/soundtrigger/SoundTriggerTest.java
+endif
 
 LOCAL_JAVA_LIBRARIES := android.test.runner
 
index 5e5a108..e8b9dd3 100644 (file)
      limitations under the License.
 -->
 
-<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="android.hardware.soundtrigger">
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="android.hardware.soundtrigger">
+    <uses-permission android:name="android.permission.MANAGE_SOUND_TRIGGER" />
+
     <application>
         <uses-library android:name="android.test.runner" />
     </application>
diff --git a/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java b/tests/SoundTriggerTests/src/android/hardware/soundtrigger/stubhal/GenericSoundModelTest.java
new file mode 100644 (file)
index 0000000..7acb472
--- /dev/null
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.soundtrigger;
+
+import java.util.Random;
+import java.util.UUID;
+
+import android.content.Context;
+import android.hardware.soundtrigger.SoundTrigger.GenericSoundModel;
+import android.media.soundtrigger.SoundTriggerManager;
+import android.os.ParcelUuid;
+import android.os.ServiceManager;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.internal.app.ISoundTriggerService;
+
+import java.util.Arrays;
+import java.util.Random;
+import java.util.UUID;
+
+public class GenericSoundModelTest extends AndroidTestCase {
+    private Random mRandom = new Random();
+
+    @SmallTest
+    public void testUpdateGenericSoundModel() throws Exception {
+        Context context = getContext();
+        ISoundTriggerService mSoundTriggerService = ISoundTriggerService.Stub.asInterface(
+            ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE));
+        SoundTriggerManager mSoundTriggerManager = (SoundTriggerManager) context.getSystemService(
+            Context.SOUND_TRIGGER_SERVICE);
+
+        byte[] data = new byte[1024];
+        mRandom.nextBytes(data);
+        UUID modelUuid = UUID.randomUUID();
+        UUID mVendorUuid = UUID.randomUUID();
+        GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data);
+
+        mSoundTriggerService.updateSoundModel(model);
+        GenericSoundModel returnedModel =
+            mSoundTriggerService.getSoundModel(new ParcelUuid(modelUuid));
+
+        assertEquals(model, returnedModel);
+
+        // Cleanup sound model
+        mSoundTriggerService.deleteSoundModel(new ParcelUuid(modelUuid));
+    }
+
+
+    @SmallTest
+    public void testDeleteGenericSoundModel() throws Exception {
+        Context context = getContext();
+        ISoundTriggerService mSoundTriggerService = ISoundTriggerService.Stub.asInterface(
+            ServiceManager.getService(Context.SOUND_TRIGGER_SERVICE));
+        SoundTriggerManager mSoundTriggerManager = (SoundTriggerManager) context.getSystemService(
+            Context.SOUND_TRIGGER_SERVICE);
+
+        byte[] data = new byte[1024];
+        mRandom.nextBytes(data);
+        UUID modelUuid = UUID.randomUUID();
+        UUID mVendorUuid = UUID.randomUUID();
+        GenericSoundModel model = new GenericSoundModel(modelUuid, mVendorUuid, data);
+
+        mSoundTriggerService.updateSoundModel(model);
+        mSoundTriggerService.deleteSoundModel(new ParcelUuid(modelUuid));
+
+        GenericSoundModel returnedModel =
+            mSoundTriggerService.getSoundModel(new ParcelUuid(modelUuid));
+        assertEquals(null, returnedModel);
+    }
+}
index 2a3f143..0da1bb1 100644 (file)
@@ -93,11 +93,7 @@ public class NotificationTestList extends TestActivity
                             .setSmallIcon(R.drawable.icon2)
                             .setContentTitle("Min priority")
                             .setLights(0xff0000ff, 1, 0)
-                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
-                            .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
-                                    getPackageName() + "/raw/ringer"))
                             .setPriority(Notification.PRIORITY_MIN)
-                            .setFullScreenIntent(makeIntent2(), false)
                             .build();
                     mNM.notify(7000, n);
                 }
@@ -125,11 +121,7 @@ public class NotificationTestList extends TestActivity
                             .setSmallIcon(R.drawable.icon2)
                             .setContentTitle("Low priority")
                             .setLights(0xff0000ff, 1, 0)
-                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
-                            .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
-                                    getPackageName() + "/raw/ringer"))
                             .setPriority(Notification.PRIORITY_LOW)
-                            .setFullScreenIntent(makeIntent2(), false)
                             .build();
                     mNM.notify(7002, n);
                 }
@@ -141,11 +133,7 @@ public class NotificationTestList extends TestActivity
                             .setSmallIcon(R.drawable.icon2)
                             .setContentTitle("Default priority")
                             .setLights(0xff0000ff, 1, 0)
-                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
-                            .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
-                                    getPackageName() + "/raw/ringer"))
                             .setPriority(Notification.PRIORITY_DEFAULT)
-                            .setFullScreenIntent(makeIntent2(), false)
                             .build();
                     mNM.notify(7004, n);
                 }
@@ -161,7 +149,6 @@ public class NotificationTestList extends TestActivity
                             .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
                                     getPackageName() + "/raw/ringer"))
                             .setPriority(Notification.PRIORITY_HIGH)
-                            .setFullScreenIntent(makeIntent2(), false)
                             .build();
                     mNM.notify(7006, n);
                 }
@@ -179,7 +166,7 @@ public class NotificationTestList extends TestActivity
                             .setPriority(Notification.PRIORITY_MAX)
                             .setFullScreenIntent(makeIntent2(), false)
                             .build();
-                    mNM.notify(7008, n);
+                    mNM.notify(7007, n);
                 }
             },
             new Test("Max priority with delay") {
@@ -202,6 +189,64 @@ public class NotificationTestList extends TestActivity
                     mNM.notify(7008, n);
                 }
             },
+            new Test("public notification") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("public notification")
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setPriority(Notification.PRIORITY_DEFAULT)
+                            .setVisibility(Notification.VISIBILITY_PUBLIC)
+                            .build();
+                    mNM.notify(7009, n);
+                }
+            },
+            new Test("private notification, no public") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("private only notification")
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setPriority(Notification.PRIORITY_DEFAULT)
+                            .setVisibility(Notification.VISIBILITY_PRIVATE)
+                            .build();
+                    mNM.notify(7010, n);
+                }
+            },
+            new Test("private notification, has public") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("private version of notification")
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setPriority(Notification.PRIORITY_DEFAULT)
+                            .setVisibility(Notification.VISIBILITY_PRIVATE)
+                            .setPublicVersion(new Notification.Builder(NotificationTestList.this)
+                                    .setSmallIcon(R.drawable.icon2)
+                                    .setContentTitle("public notification of private notification")
+                                    .setPriority(Notification.PRIORITY_DEFAULT)
+                                    .setVisibility(Notification.VISIBILITY_PUBLIC)
+                                    .build())
+                            .build();
+                    mNM.notify(7011, n);
+                }
+            },
+            new Test("secret notification") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("secret notification")
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setPriority(Notification.PRIORITY_DEFAULT)
+                            .setVisibility(Notification.VISIBILITY_SECRET)
+                            .build();
+                    mNM.notify(7012, n);
+                }
+            },
         new Test("Off") {
             public void run() {
                 PowerManager pm = (PowerManager)NotificationTestList.this.getSystemService(Context.POWER_SERVICE);
index 2494db7..54c944f 100644 (file)
@@ -31,7 +31,7 @@ import android.widget.Toast;
 
 public class TestEnrollmentActivity extends Activity {
     private static final String TAG = "TestEnrollmentActivity";
-    private static final boolean DBG = true;
+    private static final boolean DBG = false;
 
     /** Keyphrase related constants, must match those defined in enrollment_application.xml */
     private static final int KEYPHRASE_ID = 101;
index 3791d02..d7f4a38 100644 (file)
@@ -140,7 +140,7 @@ public class ActivityManagerPermissionTests extends TestCase {
     @SmallTest
     public void testSET_ACTIVITY_WATCHER() {
         try {
-            mAm.setActivityController(null);
+            mAm.setActivityController(null, false);
             fail("IActivityManager.setActivityController did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
index 3b01827..cbd8480 100644 (file)
@@ -373,7 +373,7 @@ int AaptLocaleValue::initFromDirName(const Vector<String8>& parts, const int sta
 void AaptLocaleValue::initFromResTable(const ResTable_config& config) {
     config.unpackLanguage(language);
     config.unpackRegion(region);
-    if (config.localeScriptWasProvided) {
+    if (config.localeScript[0] && !config.localeScriptWasComputed) {
         memcpy(script, config.localeScript, sizeof(config.localeScript));
     }
 
@@ -388,10 +388,10 @@ void AaptLocaleValue::writeTo(ResTable_config* out) const {
 
     if (script[0]) {
         memcpy(out->localeScript, script, sizeof(out->localeScript));
-        out->localeScriptWasProvided = true;
+        out->localeScriptWasComputed = false;
     } else {
         out->computeScript();
-        out->localeScriptWasProvided = false;
+        out->localeScriptWasComputed = true;
     }
 
     if (variant[0]) {
index f9d35ab..57a7692 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-
-# This tool is prebuilt if we're doing an app-only build.
-ifeq ($(TARGET_BUILD_APPS)$(filter true,$(TARGET_BUILD_PDK)),)
+LOCAL_PATH:= $(call my-dir)
 
 # ==========================================================
 # Setup some common variables for the different build
 # targets here.
 # ==========================================================
-LOCAL_PATH:= $(call my-dir)
 
 main := Main.cpp
 sources := \
@@ -192,4 +189,6 @@ LOCAL_C_INCLUDES += $(protoIncludes)
 
 include $(BUILD_HOST_EXECUTABLE)
 
-endif # No TARGET_BUILD_APPS or TARGET_BUILD_PDK
+ifeq ($(ONE_SHOT_MAKEFILE),)
+include $(call all-makefiles-under,$(LOCAL_PATH))
+endif
index 6acf3b0..12f56fc 100644 (file)
@@ -253,7 +253,7 @@ std::string LocaleValue::toDirName() const {
 void LocaleValue::initFromResTable(const ResTable_config& config) {
     config.unpackLanguage(language);
     config.unpackRegion(region);
-    if (config.localeScriptWasProvided) {
+    if (config.localeScript[0] && !config.localeScriptWasComputed) {
         memcpy(script, config.localeScript, sizeof(config.localeScript));
     }
 
@@ -268,10 +268,10 @@ void LocaleValue::writeTo(ResTable_config* out) const {
 
     if (script[0]) {
         memcpy(out->localeScript, script, sizeof(out->localeScript));
-        out->localeScriptWasProvided = true;
+        out->localeScriptWasComputed = false;
     } else {
         out->computeScript();
-        out->localeScriptWasProvided = false;
+        out->localeScriptWasComputed = true;
     }
 
     if (variant[0]) {
index 5f9719e..2452a1d 100644 (file)
@@ -422,10 +422,6 @@ static bool compileFile(IAaptContext* context, const CompileOptions& options,
 }
 
 class CompileContext : public IAaptContext {
-private:
-    StdErrDiagnostics mDiagnostics;
-    bool mVerbose = false;
-
 public:
     void setVerbose(bool val) {
         mVerbose = val;
@@ -444,18 +440,24 @@ public:
        return nullptr;
     }
 
-    StringPiece16 getCompilationPackage() override {
-       return {};
+    const std::u16string& getCompilationPackage() override {
+        static std::u16string empty;
+        return empty;
     }
 
     uint8_t getPackageId() override {
        return 0x0;
     }
 
-    ISymbolTable* getExternalSymbols() override {
+    SymbolTable* getExternalSymbols() override {
        abort();
        return nullptr;
     }
+
+private:
+    StdErrDiagnostics mDiagnostics;
+    bool mVerbose = false;
+
 };
 
 /**
index 9837c4e..bbf7f41 100644 (file)
@@ -1175,7 +1175,7 @@ getout:
     if (errorMsg) {
         std::stringstream err;
         err << "9-patch malformed: " << errorMsg;
-        if (!errorEdge) {
+        if (errorEdge) {
             err << "." << std::endl;
             if (errorPixel >= 0) {
                 err << "Found at pixel #" << errorPixel << " along " << errorEdge << " edge";
diff --git a/tools/aapt2/data/AndroidManifest.xml b/tools/aapt2/data/AndroidManifest.xml
deleted file mode 100644 (file)
index d3b2fbe..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="com.android.app">
-    <application
-        android:name=".ActivityMain">
-    </application>
-</manifest>
diff --git a/tools/aapt2/data/Makefile b/tools/aapt2/data/Makefile
deleted file mode 100644 (file)
index 37012de..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-##
-# Environment dependent variables
-##
-
-AAPT := aapt2
-ZIPALIGN := zipalign -f 4
-FRAMEWORK := ../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
-
-##
-# Project depenedent variables
-##
-
-LOCAL_PACKAGE := com.android.app
-LOCAL_RESOURCE_DIR := res
-LOCAL_LIBS := lib/out/package.apk
-LOCAL_OUT := out
-LOCAL_GEN := out/gen
-LOCAL_PROGUARD := out/proguard.rule
-
-##
-# AAPT2 custom rules.
-##
-
-PRIVATE_R_FILE := $(LOCAL_GEN)/$(subst .,/,$(LOCAL_PACKAGE))/R.java
-$(info PRIVATE_R_FILE = $(PRIVATE_R_FILE))
-
-# Eg: framework.apk, etc.
-PRIVATE_INCLUDES := $(FRAMEWORK)
-$(info PRIVATE_INCLUDES = $(PRIVATE_INCLUDES))
-
-# Eg: res/drawable/icon.png, res/values/styles.xml
-PRIVATE_RESOURCES := $(shell find $(LOCAL_RESOURCE_DIR) -mindepth 1 -maxdepth 2 -type f)
-$(info PRIVATE_RESOURCES = $(PRIVATE_RESOURCES))
-
-PRIVATE_RESOURCE_OBJECTS := $(subst /,_,$(patsubst $(LOCAL_RESOURCE_DIR)/%,%,$(filter $(LOCAL_RESOURCE_DIR)/values%,$(PRIVATE_RESOURCES))))
-PRIVATE_RESOURCE_OBJECTS := $(addprefix $(LOCAL_OUT)/,$(PRIVATE_RESOURCE_OBJECTS:.xml=.arsc.flat))
-$(info PRIVATE_RESOURCE_OBJECTS = $(PRIVATE_RESOURCE_OBJECTS))
-
-PRIVATE_FILE_OBJECTS := $(subst /,_,$(patsubst $(LOCAL_RESOURCE_DIR)/%,%,$(filter-out $(LOCAL_RESOURCE_DIR)/values%,$(PRIVATE_RESOURCES))))
-PRIVATE_FILE_OBJECTS := $(addprefix $(LOCAL_OUT)/,$(addsuffix .flat,$(PRIVATE_FILE_OBJECTS)))
-$(info PRIVATE_FILE_OBJECTS = $(PRIVATE_FILE_OBJECTS))
-
-.SECONDEXPANSION:
-
-$(LOCAL_OUT)/%.arsc.flat: $(LOCAL_RESOURCE_DIR)/$$(subst _,/,%).xml
-       $(AAPT) compile -o $(LOCAL_OUT) $<
-
-$(LOCAL_OUT)/%.flat: $(LOCAL_RESOURCE_DIR)/$$(subst _,/,%)
-       $(AAPT) compile -o $(LOCAL_OUT) $<
-
-$(LOCAL_PROGUARD) $(LOCAL_OUT)/package.apk: AndroidManifest.xml
-$(PRIVATE_R_FILE) $(LOCAL_PROGUARD) $(LOCAL_OUT)/package.apk: $(PRIVATE_FILE_OBJECTS) $(PRIVATE_RESOURCE_OBJECTS)
-       $(AAPT) link -o $(LOCAL_OUT)/package.apk --manifest AndroidManifest.xml --java $(LOCAL_GEN) --proguard $(LOCAL_PROGUARD) -I $(PRIVATE_INCLUDES) $(filter-out AndroidManifest.xml,$^) -v
-
-# Create the out directory if needed.
-dummy := $(shell test -d $(LOCAL_OUT) || mkdir -p $(LOCAL_OUT))
-
-.PHONY: all
-all: $(LOCAL_OUT)/package.apk $(LOCAL_PROGUARD) $(PRIVATE_R_FILE)
-
-.DEFAULT_GOAL := all
diff --git a/tools/aapt2/data/lib/AndroidManifest.xml b/tools/aapt2/data/lib/AndroidManifest.xml
deleted file mode 100644 (file)
index 08b468e..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<manifest xmlns:android="http://schemas.android.com/apk/res/android"
-    package="android.appcompat">
-
-    <uses-feature android:name="bloooop" />
-</manifest>
diff --git a/tools/aapt2/data/lib/Makefile b/tools/aapt2/data/lib/Makefile
deleted file mode 100644 (file)
index 741be9a..0000000
+++ /dev/null
@@ -1,81 +0,0 @@
-##
-# Environment dependent variables
-##
-
-AAPT := aapt2
-ZIPALIGN := zipalign -f 4
-FRAMEWORK := ../../../../../../out/target/common/obj/APPS/framework-res_intermediates/package-export.apk
-
-##
-# Project depenedent variables
-##
-
-LOCAL_PACKAGE := android.appcompat
-LOCAL_RESOURCE_DIR := res
-LOCAL_OUT := out
-LOCAL_GEN := out/gen
-
-##
-# AAPT2 custom rules.
-##
-
-PRIVATE_APK_UNALIGNED := $(LOCAL_OUT)/package-unaligned.apk
-PRIVATE_APK_ALIGNED := $(LOCAL_OUT)/package.apk
-
-# Eg: framework.apk, etc.
-PRIVATE_LIBS := $(FRAMEWORK)
-$(info PRIVATE_LIBS = $(PRIVATE_LIBS))
-
-# Eg: gen/com/android/app/R.java
-PRIVATE_R_JAVA := $(LOCAL_GEN)/$(subst .,/,$(LOCAL_PACKAGE))/R.java
-$(info PRIVATE_R_JAVA = $(PRIVATE_R_JAVA))
-
-# Eg: res/drawable/icon.png, res/values/styles.xml
-PRIVATE_RESOURCES := $(shell find $(LOCAL_RESOURCE_DIR) -mindepth 1 -maxdepth 2 -type f)
-$(info PRIVATE_RESOURCES = $(PRIVATE_RESOURCES))
-
-# Eg: drawable, values, layouts
-PRIVATE_RESOURCE_TYPES := \
-       $(patsubst $(LOCAL_RESOURCE_DIR)/%/,%,$(sort $(dir $(PRIVATE_RESOURCES))))
-$(info PRIVATE_RESOURCE_TYPES = $(PRIVATE_RESOURCE_TYPES))
-
-# Eg: out/values-v4.apk, out/drawable-xhdpi.apk
-PRIVATE_INTERMEDIATE_TABLES := $(patsubst %,$(LOCAL_OUT)/%.apk,$(PRIVATE_RESOURCE_TYPES))
-$(info PRIVATE_INTERMEDIATE_TABLES = $(PRIVATE_INTERMEDIATE_TABLES))
-
-# Generates rules for collect phase.
-# $1: Resource type (values-v4)
-# returns: out/values-v4.apk: res/values-v4/styles.xml res/values-v4/colors.xml
-define make-collect-rule
-$(LOCAL_OUT)/$1.apk: $(filter $(LOCAL_RESOURCE_DIR)/$1/%,$(PRIVATE_RESOURCES))
-       $(AAPT) compile -o $$@ $$^
-endef
-
-# Collect: out/values-v4.apk <- res/values-v4/styles.xml res/values-v4/colors.xml
-$(foreach d,$(PRIVATE_RESOURCE_TYPES),$(eval $(call make-collect-rule,$d)))
-
-# Link: out/package-unaligned.apk <- out/values-v4.apk out/drawable-v4.apk
-$(PRIVATE_APK_UNALIGNED): $(PRIVATE_INTERMEDIATE_TABLES) $(PRIVATE_LIBS) AndroidManifest.xml
-       $(AAPT) link --manifest AndroidManifest.xml $(addprefix -I ,$(PRIVATE_LIBS)) --java $(LOCAL_GEN) -o $@ $(PRIVATE_INTERMEDIATE_TABLES) --static-lib
-
-# R.java: gen/com/android/app/R.java <- out/resources.arsc
-# No action since R.java is generated when out/resources.arsc is.
-$(PRIVATE_R_JAVA): $(PRIVATE_APK_UNALIGNED)
-
-# Assemble: zip out/resources.arsc AndroidManifest.xml and res/**/*
-$(PRIVATE_APK_ALIGNED): $(PRIVATE_APK_UNALIGNED)
-       $(ZIPALIGN) $< $@
-
-# Create the out directory if needed.
-dummy := $(shell test -d $(LOCAL_OUT) || mkdir -p $(LOCAL_OUT))
-
-.PHONY: java
-java: $(PRIVATE_R_JAVA)
-
-.PHONY: assemble
-assemble: $(PRIVATE_APK_ALIGNED)
-
-.PHONY: all
-all: assemble java
-
-.DEFAULT_GOAL := all
diff --git a/tools/aapt2/data/lib/res/layout/main.xml b/tools/aapt2/data/lib/res/layout/main.xml
deleted file mode 100644 (file)
index 187ed2d..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"/>
diff --git a/tools/aapt2/data/lib/res/raw/hello.txt b/tools/aapt2/data/lib/res/raw/hello.txt
deleted file mode 100644 (file)
index 44fc22b..0000000
+++ /dev/null
@@ -1 +0,0 @@
-Oh howdy there
diff --git a/tools/aapt2/data/lib/res/values/styles.xml b/tools/aapt2/data/lib/res/values/styles.xml
deleted file mode 100644 (file)
index 4ce6333..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <style name="Platform.AppCompat" parent="@android:style/Theme">
-        <item name="android:windowNoTitle">true</item>
-    </style>
-
-    <bool name="allow">true</bool>
-</resources>
diff --git a/tools/aapt2/data/res/drawable/image.xml b/tools/aapt2/data/res/drawable/image.xml
deleted file mode 100644 (file)
index 9b38739..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<vector />
diff --git a/tools/aapt2/data/res/layout-v21/main.xml b/tools/aapt2/data/res/layout-v21/main.xml
deleted file mode 100644 (file)
index 959b349..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-              xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
-    android:id="@+id/view"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content">
-</LinearLayout>
diff --git a/tools/aapt2/data/res/values-v4/styles.xml b/tools/aapt2/data/res/values-v4/styles.xml
deleted file mode 100644 (file)
index 979a82a..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <style name="App" parent="android:Theme.Material">
-        <item name="android:colorAccent">@color/accent</item>
-        <item name="android:text">Hey</item>
-    </style>
-</resources>
diff --git a/tools/aapt2/data/res/values/colors.xml b/tools/aapt2/data/res/values/colors.xml
deleted file mode 100644 (file)
index 89db5fb..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources>
-    <color name="primary">#f44336</color>
-    <color name="primary_dark">#b71c1c</color>
-    <color name="accent">#fdd835</color>
-</resources>
diff --git a/tools/aapt2/data/res/values/test.xml b/tools/aapt2/data/res/values/test.xml
deleted file mode 100644 (file)
index d7ab1c8..0000000
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="hooha"><font bgcolor="#ffffff">Hey guys!</font> <xliff:g>My</xliff:g> name is <b>Adam</b>. How <b><i>are</i></b> you?</string>
-    <public name="hooha" type="string" id="0x7f020001"/>
-    <string name="wow">@android:string/ok</string>
-    <public name="layout_width" type="attr" />
-    <attr name="layout_width" format="boolean" />
-    <attr name="flags">
-        <flag name="complex" value="1" />
-        <flag name="pub" value="2" />
-        <flag name="weak" value="4" />
-    </attr>
-</resources>
diff --git a/tools/aapt2/data/resources.arsc b/tools/aapt2/data/resources.arsc
deleted file mode 100644 (file)
index 6a416df..0000000
Binary files a/tools/aapt2/data/resources.arsc and /dev/null differ
diff --git a/tools/aapt2/data/resources_base.arsc b/tools/aapt2/data/resources_base.arsc
deleted file mode 100644 (file)
index f9d0610..0000000
Binary files a/tools/aapt2/data/resources_base.arsc and /dev/null differ
diff --git a/tools/aapt2/data/resources_hdpi.arsc b/tools/aapt2/data/resources_hdpi.arsc
deleted file mode 100644 (file)
index 97232a3..0000000
Binary files a/tools/aapt2/data/resources_hdpi.arsc and /dev/null differ
index ad7de0a..56b9f9a 100644 (file)
@@ -17,6 +17,7 @@
 #include "Debug.h"
 #include "Diagnostics.h"
 #include "Flags.h"
+#include "io/ZipArchive.h"
 #include "process/IResourceTableConsumer.h"
 #include "proto/ProtoSerialize.h"
 #include "util/Files.h"
@@ -56,6 +57,35 @@ void dumpCompiledTable(const pb::ResourceTable& pbTable, const Source& source,
 
 void tryDumpFile(IAaptContext* context, const std::string& filePath) {
     std::string err;
+    std::unique_ptr<io::ZipFileCollection> zip = io::ZipFileCollection::create(filePath, &err);
+    if (zip) {
+        io::IFile* file = zip->findFile("resources.arsc.flat");
+        if (file) {
+            std::unique_ptr<io::IData> data = file->openAsData();
+            if (!data) {
+                context->getDiagnostics()->error(DiagMessage(filePath)
+                                                 << "failed to open resources.arsc.flat");
+                return;
+            }
+
+            pb::ResourceTable pbTable;
+            if (!pbTable.ParseFromArray(data->data(), data->size())) {
+                context->getDiagnostics()->error(DiagMessage(filePath)
+                                                 << "invalid resources.arsc.flat");
+                return;
+            }
+
+            std::unique_ptr<ResourceTable> table = deserializeTableFromPb(
+                    pbTable, Source(filePath), context->getDiagnostics());
+            if (table) {
+                DebugPrintTableOptions debugPrintTableOptions;
+                debugPrintTableOptions.showSources = true;
+                Debug::printTable(table.get(), debugPrintTableOptions);
+            }
+        }
+        return;
+    }
+
     Maybe<android::FileMap> file = file::mmapPath(filePath, &err);
     if (!file) {
         context->getDiagnostics()->error(DiagMessage(filePath) << err);
@@ -90,15 +120,16 @@ public:
         return nullptr;
     }
 
-    StringPiece16 getCompilationPackage() override {
-        return {};
+    const std::u16string& getCompilationPackage() override {
+        static std::u16string empty;
+        return empty;
     }
 
     uint8_t getPackageId() override {
         return 0;
     }
 
-    ISymbolTable* getExternalSymbols() override {
+    SymbolTable* getExternalSymbols() override {
         abort();
         return nullptr;
     }
index 8219462..3eac633 100644 (file)
@@ -144,9 +144,9 @@ struct XmlFlattenerVisitor : public xml::Visitor {
     }
 
     static bool cmpXmlAttributeById(const xml::Attribute* a, const xml::Attribute* b) {
-        if (a->compiledAttribute) {
-            if (b->compiledAttribute) {
-                return a->compiledAttribute.value().id < b->compiledAttribute.value().id;
+        if (a->compiledAttribute && a->compiledAttribute.value().id) {
+            if (b->compiledAttribute && b->compiledAttribute.value().id) {
+                return a->compiledAttribute.value().id.value() < b->compiledAttribute.value().id.value();
             }
             return true;
         } else if (!b->compiledAttribute) {
@@ -167,8 +167,8 @@ struct XmlFlattenerVisitor : public xml::Visitor {
 
         // Filter the attributes.
         for (xml::Attribute& attr : node->attributes) {
-            if (mOptions.maxSdkLevel && attr.compiledAttribute) {
-                size_t sdkLevel = findAttributeSdkLevel(attr.compiledAttribute.value().id);
+            if (mOptions.maxSdkLevel && attr.compiledAttribute && attr.compiledAttribute.value().id) {
+                size_t sdkLevel = findAttributeSdkLevel(attr.compiledAttribute.value().id.value());
                 if (sdkLevel > mOptions.maxSdkLevel.value()) {
                     continue;
                 }
@@ -191,8 +191,8 @@ struct XmlFlattenerVisitor : public xml::Visitor {
         uint16_t attributeIndex = 1;
         for (const xml::Attribute* xmlAttr : mFilteredAttrs) {
             // Assign the indices for specific attributes.
-            if (xmlAttr->compiledAttribute &&
-                    xmlAttr->compiledAttribute.value().id == kIdAttr) {
+            if (xmlAttr->compiledAttribute && xmlAttr->compiledAttribute.value().id &&
+                    xmlAttr->compiledAttribute.value().id.value() == kIdAttr) {
                 flatElem->idIndex = util::hostToDevice16(attributeIndex);
             } else if (xmlAttr->namespaceUri.empty()) {
                 if (xmlAttr->name == u"class") {
@@ -208,7 +208,7 @@ struct XmlFlattenerVisitor : public xml::Visitor {
 
             flatAttr->rawValue.index = util::hostToDevice32(-1);
 
-            if (!xmlAttr->compiledAttribute) {
+            if (!xmlAttr->compiledAttribute || !xmlAttr->compiledAttribute.value().id) {
                 // The attribute has no associated ResourceID, so the string order doesn't matter.
                 addString(xmlAttr->name, kLowPriority, &flatAttr->name);
             } else {
@@ -221,17 +221,17 @@ struct XmlFlattenerVisitor : public xml::Visitor {
                 // Lookup the StringPool for this package and make the reference there.
                 const xml::AaptAttribute& aaptAttr = xmlAttr->compiledAttribute.value();
 
-                StringPool::Ref nameRef = mPackagePools[aaptAttr.id.packageId()].makeRef(
-                        xmlAttr->name, StringPool::Context{ aaptAttr.id.id });
+                StringPool::Ref nameRef = mPackagePools[aaptAttr.id.value().packageId()].makeRef(
+                        xmlAttr->name, StringPool::Context{ aaptAttr.id.value().id });
 
                 // Add it to the list of strings to flatten.
                 addString(nameRef, &flatAttr->name);
+            }
 
-                if (mOptions.keepRawValues) {
-                    // Keep raw values (this is for static libraries).
-                    // TODO(with a smarter inflater for binary XML, we can do without this).
-                    addString(xmlAttr->value, kLowPriority, &flatAttr->rawValue);
-                }
+            if (mOptions.keepRawValues || !xmlAttr->compiledValue) {
+                // Keep raw values if the value is not compiled or
+                // if we're building a static library (need symbols).
+                addString(xmlAttr->value, kLowPriority, &flatAttr->rawValue);
             }
 
             if (xmlAttr->compiledValue) {
@@ -240,7 +240,6 @@ struct XmlFlattenerVisitor : public xml::Visitor {
             } else {
                 // Flatten as a regular string type.
                 flatAttr->typedValue.dataType = android::Res_value::TYPE_STRING;
-                addString(xmlAttr->value, kLowPriority, &flatAttr->rawValue);
                 addString(xmlAttr->value, kLowPriority,
                           (ResStringPool_ref*) &flatAttr->typedValue.data);
             }
index 8648879..fef5ca3 100644 (file)
@@ -32,7 +32,7 @@ public:
         mContext = test::ContextBuilder()
                 .setCompilationPackage(u"com.app.test")
                 .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
-                .setSymbolTable(test::StaticSymbolTableBuilder()
+                .addSymbolSource(test::StaticSymbolSourceBuilder()
                         .addSymbol(u"@android:attr/id", ResourceId(0x010100d0),
                                    test::AttributeBuilder().build())
                         .addSymbol(u"@com.app.test:id/id", ResourceId(0x7f020000))
diff --git a/tools/aapt2/integration-tests/Android.mk b/tools/aapt2/integration-tests/Android.mk
new file mode 100644 (file)
index 0000000..6361f9b
--- /dev/null
@@ -0,0 +1,2 @@
+LOCAL_PATH := $(call my-dir)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/tools/aapt2/integration-tests/AppOne/Android.mk b/tools/aapt2/integration-tests/AppOne/Android.mk
new file mode 100644 (file)
index 0000000..859cc8c
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_PACKAGE_NAME := AaptTestAppOne
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_STATIC_ANDROID_LIBRARIES := \
+    AaptTestStaticLibOne \
+    AaptTestStaticLibTwo
+include $(BUILD_PACKAGE)
diff --git a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..b6d8f2d
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest package="com.android.aapt.app.one" />
diff --git a/tools/aapt2/integration-tests/AppOne/core b/tools/aapt2/integration-tests/AppOne/core
new file mode 100644 (file)
index 0000000..a9ae976
Binary files /dev/null and b/tools/aapt2/integration-tests/AppOne/core differ
diff --git a/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml b/tools/aapt2/integration-tests/AppOne/res/drawable/image.xml
new file mode 100644 (file)
index 0000000..6132a75
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<vector />
diff --git a/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml b/tools/aapt2/integration-tests/AppOne/res/layout-v21/main.xml
new file mode 100644 (file)
index 0000000..9f5a4a8
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
+    android:id="@+id/view"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content">
+</LinearLayout>
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
               xmlns:support="http://schemas.android.com/apk/res/android.appcompat"
     android:id="@+id/view"
diff --git a/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml b/tools/aapt2/integration-tests/AppOne/res/values-v4/styles.xml
new file mode 100644 (file)
index 0000000..d8c11e2
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <style name="App" parent="android:Theme.Material">
+        <item name="android:colorAccent">@color/accent</item>
+        <item name="android:text">Hey</item>
+    </style>
+</resources>
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/colors.xml b/tools/aapt2/integration-tests/AppOne/res/values/colors.xml
new file mode 100644 (file)
index 0000000..4df5077
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <color name="primary">#f44336</color>
+    <color name="primary_dark">#b71c1c</color>
+    <color name="accent">#fdd835</color>
+</resources>
@@ -1,4 +1,19 @@
 <?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
 <resources xmlns:lib="http://schemas.android.com/apk/res/android.appcompat">
     <style name="App">
         <item name="android:background">@color/primary</item>
diff --git a/tools/aapt2/integration-tests/AppOne/res/values/test.xml b/tools/aapt2/integration-tests/AppOne/res/values/test.xml
new file mode 100644 (file)
index 0000000..f4b7471
--- /dev/null
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- Reference the two static libraries -->
+    <string name="AppFooBar">@string/FooBar</string>
+    <string name="AppFoo">@string/Foo</string>
+
+    <string name="hooha"><font bgcolor="#ffffff">Hey guys!</font> <xliff:g>My</xliff:g> name is <b>Adam</b>. How <b><i>are</i></b> you?</string>
+    <public name="hooha" type="string" id="0x7f020001"/>
+    <string name="wow">@android:string/ok</string>
+    <public name="layout_width" type="attr" />
+    <attr name="layout_width" format="boolean" />
+    <attr name="flags">
+        <flag name="complex" value="1" />
+        <flag name="pub" value="2" />
+        <flag name="weak" value="4" />
+    </attr>
+</resources>
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.aapt.app.one;
 
-package android.hardware;
+public class AppOne {
+    // IDs from StaticLibOne
+    public static int FooId = com.android.aapt.staticlib.one.R.string.Foo;
+    public static int LayoutId = com.android.aapt.staticlib.one.R.layout.layout;
+
+    // IDs from StaticLibTwo
+    public static int FooBarId = com.android.aapt.staticlib.two.R.string.FooBar;
+}
 
-/** @hide */
-parcelable CameraInfo;
diff --git a/tools/aapt2/integration-tests/StaticLibOne/Android.mk b/tools/aapt2/integration-tests/StaticLibOne/Android.mk
new file mode 100644 (file)
index 0000000..d59dc60
--- /dev/null
@@ -0,0 +1,25 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_MODULE := AaptTestStaticLibOne
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+include $(BUILD_STATIC_JAVA_LIBRARY)
diff --git a/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibOne/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..705047e
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest package="com.android.aapt.staticlib.one" />
diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml b/tools/aapt2/integration-tests/StaticLibOne/res/layout/layout.xml
new file mode 100644 (file)
index 0000000..683c91c
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<View xmlns:android="http://schemas.android.com/apk/res/android"
+      android:text="@string/Foo" />
diff --git a/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibOne/res/values/values.xml
new file mode 100644 (file)
index 0000000..2b24544
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <attr name="StaticLibOne_attr" format="string" />
+
+    <string name="Foo">Foo</string>
+    <string name="Foo" product="tablet">Bar</string>
+</resources>
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.aapt.staticlib.one;
 
-package android.hardware;
-
-/** @hide */
-interface ICameraClient
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/ICameraClient.h
-     */
-    // TODO: consider implementing this.
+public class StaticLibOne {
+    // IDs from StaticLibOne
+    public static int FooId = com.android.aapt.staticlib.one.R.string.Foo;
+    public static int LayoutId = com.android.aapt.staticlib.one.R.layout.layout;
 }
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/Android.mk b/tools/aapt2/integration-tests/StaticLibTwo/Android.mk
new file mode 100644 (file)
index 0000000..8b6eb41
--- /dev/null
@@ -0,0 +1,27 @@
+#
+# Copyright (C) 2016 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+LOCAL_USE_AAPT2 := true
+LOCAL_MODULE := AaptTestStaticLibTwo
+LOCAL_MODULE_TAGS := tests
+LOCAL_SRC_FILES := $(call all-java-files-under,src)
+LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/res
+LOCAL_SHARED_ANDROID_LIBRARIES := AaptTestStaticLibOne
+include $(BUILD_STATIC_JAVA_LIBRARY)
+
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml b/tools/aapt2/integration-tests/StaticLibTwo/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..28f0699
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<manifest package="com.android.aapt.staticlib.two" />
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml b/tools/aapt2/integration-tests/StaticLibTwo/res/layout/layout_two.xml
new file mode 100644 (file)
index 0000000..ba98307
--- /dev/null
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 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.
+-->
+
+<View xmlns:custom="http://schemas.android.com/apk/res-auto"
+      custom:StaticLibOne_attr="@string/FooBar" />
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml b/tools/aapt2/integration-tests/StaticLibTwo/res/values/values.xml
new file mode 100644 (file)
index 0000000..97bb2a5
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<resources>
+    <string name="FooBar">@string/Foo</string>
+</resources>
diff --git a/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java b/tools/aapt2/integration-tests/StaticLibTwo/src/com/android/aapt/staticlib/two/StaticLibTwo.java
new file mode 100644 (file)
index 0000000..7110dcd
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.aapt.staticlib.two;
+
+public class StaticLibTwo {
+    // IDs from StaticLibOne
+    public static int FooId = com.android.aapt.staticlib.one.R.string.Foo;
+    public static int LayoutId = com.android.aapt.staticlib.one.R.layout.layout;
+
+    // IDs from StaticLibTwo
+    public static int FooBarId = com.android.aapt.staticlib.two.R.string.FooBar;
+}
index 329dac9..b3e7a02 100644 (file)
@@ -92,9 +92,8 @@ std::unique_ptr<ZipFileCollection> ZipFileCollection::create(const StringPiece&
         return {};
     }
 
-    ZipString suffix(".flat");
     void* cookie = nullptr;
-    result = StartIteration(collection->mHandle, &cookie, nullptr, &suffix);
+    result = StartIteration(collection->mHandle, &cookie, nullptr, nullptr);
     if (result != 0) {
         if (outError) *outError = ErrorCodeString(result);
         return {};
index 6e340a2..9e94d42 100644 (file)
@@ -223,8 +223,10 @@ bool JavaClassGenerator::writeEntriesForClass(ClassDefinitionWriter* outClassDef
             continue;
         }
 
-        ResourceId id(package->id.value(), type->id.value(), entry->id.value());
-        assert(id.isValid());
+        ResourceId id;
+        if (package->id && type->id && entry->id) {
+            id = ResourceId(package->id.value(), type->id.value(), entry->id.value());
+        }
 
         std::u16string unmangledPackage;
         std::u16string unmangledName = entry->name;
index d83f6de..b28415d 100644 (file)
@@ -62,7 +62,9 @@ struct LinkOptions {
     std::set<std::u16string> extraJavaPackages;
     Maybe<std::string> generateProguardRulesPath;
     bool noAutoVersion = false;
+    bool noVersionVectors = false;
     bool staticLib = false;
+    bool noStaticLibPackages = false;
     bool generateNonFinalIds = false;
     bool outputToDirectory = false;
     bool autoAddOverlay = false;
@@ -74,37 +76,58 @@ struct LinkOptions {
     TableSplitterOptions tableSplitterOptions;
 };
 
-struct LinkContext : public IAaptContext {
-    StdErrDiagnostics mDiagnostics;
-    std::unique_ptr<NameMangler> mNameMangler;
-    std::u16string mCompilationPackage;
-    uint8_t mPackageId;
-    std::unique_ptr<ISymbolTable> mSymbols;
-    bool mVerbose = false;
+class LinkContext : public IAaptContext {
+public:
+    LinkContext() : mNameMangler({}) {
+    }
 
     IDiagnostics* getDiagnostics() override {
         return &mDiagnostics;
     }
 
     NameMangler* getNameMangler() override {
-        return mNameMangler.get();
+        return &mNameMangler;
     }
 
-    StringPiece16 getCompilationPackage() override {
+    void setNameManglerPolicy(const NameManglerPolicy& policy) {
+        mNameMangler = NameMangler(policy);
+    }
+
+    const std::u16string& getCompilationPackage() override {
         return mCompilationPackage;
     }
 
+    void setCompilationPackage(const StringPiece16& packageName) {
+        mCompilationPackage = packageName.toString();
+    }
+
     uint8_t getPackageId() override {
         return mPackageId;
     }
 
-    ISymbolTable* getExternalSymbols() override {
-        return mSymbols.get();
+    void setPackageId(uint8_t id) {
+        mPackageId = id;
+    }
+
+    SymbolTable* getExternalSymbols() override {
+        return &mSymbols;
     }
 
     bool verbose() override {
         return mVerbose;
     }
+
+    void setVerbose(bool val) {
+        mVerbose = val;
+    }
+
+private:
+    StdErrDiagnostics mDiagnostics;
+    NameMangler mNameMangler;
+    std::u16string mCompilationPackage;
+    uint8_t mPackageId = 0x0;
+    SymbolTable mSymbols;
+    bool mVerbose = false;
 };
 
 static bool copyFileToArchive(io::IFile* file, const std::string& outPath,
@@ -117,11 +140,19 @@ static bool copyFileToArchive(io::IFile* file, const std::string& outPath,
         return false;
     }
 
-    CompiledFileInputStream inputStream(data->data(), data->size());
-    if (!inputStream.CompiledFile()) {
-        context->getDiagnostics()->error(DiagMessage(file->getSource())
-                                         << "invalid compiled file header");
-        return false;
+    const uint8_t* buffer = reinterpret_cast<const uint8_t*>(data->data());
+    size_t bufferSize = data->size();
+
+    // If the file ends with .flat, we must strip off the CompiledFileHeader from it.
+    if (util::stringEndsWith<char>(file->getSource().path, ".flat")) {
+        CompiledFileInputStream inputStream(data->data(), data->size());
+        if (!inputStream.CompiledFile()) {
+            context->getDiagnostics()->error(DiagMessage(file->getSource())
+                                             << "invalid compiled file header");
+            return false;
+        }
+        buffer = reinterpret_cast<const uint8_t*>(inputStream.data());
+        bufferSize = inputStream.size();
     }
 
     if (context->verbose()) {
@@ -129,8 +160,7 @@ static bool copyFileToArchive(io::IFile* file, const std::string& outPath,
     }
 
     if (writer->startEntry(outPath, compressionFlags)) {
-        if (writer->writeEntry(reinterpret_cast<const uint8_t*>(inputStream.data()),
-                               inputStream.size())) {
+        if (writer->writeEntry(buffer, bufferSize)) {
             if (writer->finishEntry()) {
                 return true;
             }
@@ -156,7 +186,7 @@ static bool flattenXml(xml::XmlResource* xmlRes, const StringPiece& path, Maybe<
         DiagMessage msg;
         msg << "writing " << path << " to archive";
         if (maxSdkLevel) {
-            msg << " maxSdkLevel=" << maxSdkLevel.value();
+            msg << " maxSdkLevel=" << maxSdkLevel.value() << " keepRawValues=" << keepRawValues;
         }
         context->getDiagnostics()->note(msg);
     }
@@ -346,7 +376,7 @@ std::unique_ptr<xml::XmlResource> ResourceFileFlattener::linkAndVersionXmlFile(
                 }
 
                 ResourceFile versionedFileDesc = xmlRes->file;
-                versionedFileDesc.config.sdkVersion = sdkLevel;
+                versionedFileDesc.config.sdkVersion = (uint16_t) sdkLevel;
 
                 if (mContext->verbose()) {
                     mContext->getDiagnostics()->note(DiagMessage(versionedFileDesc.source)
@@ -474,39 +504,61 @@ bool ResourceFileFlattener::flatten(ResourceTable* table, IArchiveWriter* archiv
 class LinkCommand {
 public:
     LinkCommand(LinkContext* context, const LinkOptions& options) :
-            mOptions(options), mContext(context), mFinalTable(), mFileCollection(nullptr) {
-        std::unique_ptr<io::FileCollection> fileCollection =
-                util::make_unique<io::FileCollection>();
-
-        // Get a pointer to the FileCollection for convenience, but it will be owned by the vector.
-        mFileCollection = fileCollection.get();
-
-        // Move it to the collection.
-        mCollections.push_back(std::move(fileCollection));
+            mOptions(options), mContext(context), mFinalTable(),
+            mFileCollection(util::make_unique<io::FileCollection>()) {
     }
 
     /**
      * Creates a SymbolTable that loads symbols from the various APKs and caches the
      * results for faster lookup.
      */
-    std::unique_ptr<ISymbolTable> createSymbolTableFromIncludePaths() {
-        AssetManagerSymbolTableBuilder builder;
+    bool loadSymbolsFromIncludePaths() {
+        std::unique_ptr<AssetManagerSymbolSource> assetSource =
+                util::make_unique<AssetManagerSymbolSource>();
         for (const std::string& path : mOptions.includePaths) {
             if (mContext->verbose()) {
                 mContext->getDiagnostics()->note(DiagMessage(path) << "loading include path");
             }
 
-            std::unique_ptr<android::AssetManager> assetManager =
-                    util::make_unique<android::AssetManager>();
-            int32_t cookie = 0;
-            if (!assetManager->addAssetPath(android::String8(path.data(), path.size()), &cookie)) {
+            // First try to load the file as a static lib.
+            std::string errorStr;
+            std::unique_ptr<ResourceTable> staticInclude = loadStaticLibrary(path, &errorStr);
+            if (staticInclude) {
+                if (!mOptions.staticLib) {
+                    // Can't include static libraries when not building a static library.
+                    mContext->getDiagnostics()->error(
+                            DiagMessage(path) << "can't include static library when building app");
+                    return false;
+                }
+
+                // If we are using --no-static-lib-packages, we need to rename the package of this
+                // table to our compilation package.
+                if (mOptions.noStaticLibPackages) {
+                    if (ResourceTablePackage* pkg = staticInclude->findPackageById(0x7f)) {
+                        pkg->name = mContext->getCompilationPackage();
+                    }
+                }
+
+                mContext->getExternalSymbols()->appendSource(
+                        util::make_unique<ResourceTableSymbolSource>(staticInclude.get()));
+
+                mStaticTableIncludes.push_back(std::move(staticInclude));
+
+            } else if (!errorStr.empty()) {
+                // We had an error with reading, so fail.
+                mContext->getDiagnostics()->error(DiagMessage(path) << errorStr);
+                return false;
+            }
+
+            if (!assetSource->addAssetPath(path)) {
                 mContext->getDiagnostics()->error(
                         DiagMessage(path) << "failed to load include path");
-                return {};
+                return false;
             }
-            builder.add(std::move(assetManager));
         }
-        return builder.build();
+
+        mContext->getExternalSymbols()->appendSource(std::move(assetSource));
+        return true;
     }
 
     Maybe<AppInfo> extractAppInfoFromManifest(xml::XmlResource* xmlRes) {
@@ -571,6 +623,35 @@ public:
         return !error;
     }
 
+    /**
+     * Returns true if no IDs have been set, false otherwise.
+     */
+    bool verifyNoIdsSet() {
+        for (const auto& package : mFinalTable.packages) {
+            for (const auto& type : package->types) {
+                if (type->id) {
+                    mContext->getDiagnostics()->error(DiagMessage() << "type " << type->type
+                                                      << " has ID " << std::hex
+                                                      << (int) type->id.value()
+                                                      << std::dec << " assigned");
+                    return false;
+                }
+
+                for (const auto& entry : type->entries) {
+                    if (entry->id) {
+                        ResourceNameRef resName(package->name, type->type, entry->name);
+                        mContext->getDiagnostics()->error(DiagMessage() << "entry " << resName
+                                                          << " has ID " << std::hex
+                                                          << (int) entry->id.value()
+                                                          << std::dec << " assigned");
+                        return false;
+                    }
+                }
+            }
+        }
+        return true;
+    }
+
     std::unique_ptr<IArchiveWriter> makeArchiveWriter() {
         if (mOptions.outputToDirectory) {
             return createDirectoryArchiveWriter(mContext->getDiagnostics(), mOptions.outputPath);
@@ -599,6 +680,32 @@ public:
         return false;
     }
 
+    bool flattenTableToPb(ResourceTable* table, IArchiveWriter* writer) {
+        // Create the file/zip entry.
+        if (!writer->startEntry("resources.arsc.flat", 0)) {
+            mContext->getDiagnostics()->error(DiagMessage() << "failed to open");
+            return false;
+        }
+
+        std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table);
+
+        // Wrap our IArchiveWriter with an adaptor that implements the ZeroCopyOutputStream
+        // interface.
+        {
+            google::protobuf::io::CopyingOutputStreamAdaptor adaptor(writer);
+
+            if (!pbTable->SerializeToZeroCopyStream(&adaptor)) {
+                mContext->getDiagnostics()->error(DiagMessage() << "failed to write");
+                return false;
+            }
+        }
+
+        if (!writer->finishEntry()) {
+            mContext->getDiagnostics()->error(DiagMessage() << "failed to finish entry");
+            return false;
+        }
+        return true;
+    }
 
     bool writeJavaFile(ResourceTable* table, const StringPiece16& packageNameToGenerate,
                        const StringPiece16& outPackage, JavaClassGeneratorOptions javaOptions) {
@@ -674,18 +781,91 @@ public:
         return true;
     }
 
-    bool mergeStaticLibrary(const std::string& input) {
-        // TODO(adamlesinski): Load resources from a static library APK and merge the table into
-        // TableMerger.
-        mContext->getDiagnostics()->warn(DiagMessage()
-                                        << "linking static libraries not supported yet: "
-                                        << input);
+    std::unique_ptr<ResourceTable> loadStaticLibrary(const std::string& input,
+                                                     std::string* outError) {
+        std::unique_ptr<io::ZipFileCollection> collection = io::ZipFileCollection::create(
+                input, outError);
+        if (!collection) {
+            return {};
+        }
+        return loadTablePbFromCollection(collection.get());
+    }
+
+    std::unique_ptr<ResourceTable> loadTablePbFromCollection(io::IFileCollection* collection) {
+        io::IFile* file = collection->findFile("resources.arsc.flat");
+        if (!file) {
+            return {};
+        }
+
+        std::unique_ptr<io::IData> data = file->openAsData();
+        return loadTableFromPb(file->getSource(), data->data(), data->size(),
+                               mContext->getDiagnostics());
+    }
+
+    bool mergeStaticLibrary(const std::string& input, bool override) {
+        if (mContext->verbose()) {
+            mContext->getDiagnostics()->note(DiagMessage() << "merging static library " << input);
+        }
+
+        std::string errorStr;
+        std::unique_ptr<io::ZipFileCollection> collection =
+                io::ZipFileCollection::create(input, &errorStr);
+        if (!collection) {
+            mContext->getDiagnostics()->error(DiagMessage(input) << errorStr);
+            return false;
+        }
+
+        std::unique_ptr<ResourceTable> table = loadTablePbFromCollection(collection.get());
+        if (!table) {
+            mContext->getDiagnostics()->error(DiagMessage(input) << "invalid static library");
+            return false;
+        }
+
+        ResourceTablePackage* pkg = table->findPackageById(0x7f);
+        if (!pkg) {
+            mContext->getDiagnostics()->error(DiagMessage(input)
+                                              << "static library has no package");
+            return false;
+        }
+
+        bool result;
+        if (mOptions.noStaticLibPackages) {
+            // Merge all resources as if they were in the compilation package. This is the old
+            // behaviour of aapt.
+
+            // Add the package to the set of --extra-packages so we emit an R.java for each
+            // library package.
+            if (!pkg->name.empty()) {
+                mOptions.extraJavaPackages.insert(pkg->name);
+            }
+
+            pkg->name = u"";
+            if (override) {
+                result = mTableMerger->mergeOverlay(Source(input), table.get(), collection.get());
+            } else {
+                result = mTableMerger->merge(Source(input), table.get(), collection.get());
+            }
+
+        } else {
+            // This is the proper way to merge libraries, where the package name is preserved
+            // and resource names are mangled.
+            result = mTableMerger->mergeAndMangle(Source(input), pkg->name, table.get(),
+                                                  collection.get());
+        }
+
+        if (!result) {
+            return false;
+        }
+
+        // Make sure to move the collection into the set of IFileCollections.
+        mCollections.push_back(std::move(collection));
         return true;
     }
 
     bool mergeResourceTable(io::IFile* file, bool override) {
         if (mContext->verbose()) {
-            mContext->getDiagnostics()->note(DiagMessage() << "linking " << file->getSource());
+            mContext->getDiagnostics()->note(DiagMessage() << "merging resource table "
+                                             << file->getSource());
         }
 
         std::unique_ptr<io::IData> data = file->openAsData();
@@ -711,13 +891,14 @@ public:
         return result;
     }
 
-    bool mergeCompiledFile(io::IFile* file, std::unique_ptr<ResourceFile> fileDesc, bool overlay) {
+    bool mergeCompiledFile(io::IFile* file, ResourceFile* fileDesc, bool override) {
         if (mContext->verbose()) {
-            mContext->getDiagnostics()->note(DiagMessage() << "adding " << file->getSource());
+            mContext->getDiagnostics()->note(DiagMessage() << "merging compiled file "
+                                             << file->getSource());
         }
 
         bool result = false;
-        if (overlay) {
+        if (override) {
             result = mTableMerger->mergeFileOverlay(*fileDesc, file);
         } else {
             result = mTableMerger->mergeFile(*fileDesc, file);
@@ -730,7 +911,7 @@ public:
         // Add the exports of this file to the table.
         for (SourcedResourceName& exportedSymbol : fileDesc->exportedSymbols) {
             if (exportedSymbol.name.package.empty()) {
-                exportedSymbol.name.package = mContext->getCompilationPackage().toString();
+                exportedSymbol.name.package = mContext->getCompilationPackage();
             }
 
             ResourceNameRef resName = exportedSymbol.name;
@@ -743,11 +924,9 @@ public:
 
             std::unique_ptr<Id> id = util::make_unique<Id>();
             id->setSource(fileDesc->source.withLine(exportedSymbol.line));
-            bool result = mFinalTable.addResourceAllowMangled(resName,
-                                                              ConfigDescription::defaultConfig(),
-                                                              std::string(),
-                                                              std::move(id),
-                                                              mContext->getDiagnostics());
+            bool result = mFinalTable.addResourceAllowMangled(
+                    resName, ConfigDescription::defaultConfig(), std::string(), std::move(id),
+                    mContext->getDiagnostics());
             if (!result) {
                 return false;
             }
@@ -756,12 +935,21 @@ public:
     }
 
     /**
-     * Creates an io::IFileCollection from the ZIP archive and processes the files within.
+     * Takes a path to load as a ZIP file and merges the files within into the master ResourceTable.
+     * If override is true, conflicting resources are allowed to override each other, in order of
+     * last seen.
+     *
+     * An io::IFileCollection is created from the ZIP file and added to the set of
+     * io::IFileCollections that are open.
      */
     bool mergeArchive(const std::string& input, bool override) {
+        if (mContext->verbose()) {
+            mContext->getDiagnostics()->note(DiagMessage() << "merging archive " << input);
+        }
+
         std::string errorStr;
-        std::unique_ptr<io::ZipFileCollection> collection = io::ZipFileCollection::create(
-                input, &errorStr);
+        std::unique_ptr<io::ZipFileCollection> collection =
+                io::ZipFileCollection::create(input, &errorStr);
         if (!collection) {
             mContext->getDiagnostics()->error(DiagMessage(input) << errorStr);
             return false;
@@ -769,7 +957,7 @@ public:
 
         bool error = false;
         for (auto iter = collection->iterator(); iter->hasNext(); ) {
-            if (!processFile(iter->next(), override)) {
+            if (!mergeFile(iter->next(), override)) {
                 error = true;
             }
         }
@@ -779,22 +967,45 @@ public:
         return !error;
     }
 
-    bool processFile(const std::string& path, bool override) {
+    /**
+     * Takes a path to load and merge into the master ResourceTable. If override is true,
+     * conflicting resources are allowed to override each other, in order of last seen.
+     *
+     * If the file path ends with .flata, .jar, .jack, or .zip the file is treated as ZIP archive
+     * and the files within are merged individually.
+     *
+     * Otherwise the files is processed on its own.
+     */
+    bool mergePath(const std::string& path, bool override) {
         if (util::stringEndsWith<char>(path, ".flata") ||
                 util::stringEndsWith<char>(path, ".jar") ||
                 util::stringEndsWith<char>(path, ".jack") ||
                 util::stringEndsWith<char>(path, ".zip")) {
             return mergeArchive(path, override);
+        } else if (util::stringEndsWith<char>(path, ".apk")) {
+            return mergeStaticLibrary(path, override);
         }
 
         io::IFile* file = mFileCollection->insertFile(path);
-        return processFile(file, override);
+        return mergeFile(file, override);
     }
 
-    bool processFile(io::IFile* file, bool override) {
+    /**
+     * Takes a file to load and merge into the master ResourceTable. If override is true,
+     * conflicting resources are allowed to override each other, in order of last seen.
+     *
+     * If the file ends with .arsc.flat, then it is loaded as a ResourceTable and merged into the
+     * master ResourceTable. If the file ends with .flat, then it is treated like a compiled file
+     * and the header data is read and merged into the final ResourceTable.
+     *
+     * All other file types are ignored. This is because these files could be coming from a zip,
+     * where we could have other files like classes.dex.
+     */
+    bool mergeFile(io::IFile* file, bool override) {
         const Source& src = file->getSource();
         if (util::stringEndsWith<char>(src.path, ".arsc.flat")) {
             return mergeResourceTable(file, override);
+
         } else if (util::stringEndsWith<char>(src.path, ".flat")){
             // Try opening the file and looking for an Export header.
             std::unique_ptr<io::IData> data = file->openAsData();
@@ -806,9 +1017,8 @@ public:
             std::unique_ptr<ResourceFile> resourceFile = loadFileExportHeader(
                     src, data->data(), data->size(), mContext->getDiagnostics());
             if (resourceFile) {
-                return mergeCompiledFile(file, std::move(resourceFile), override);
+                return mergeCompiledFile(file, resourceFile.get(), override);
             }
-
             return false;
         }
 
@@ -826,32 +1036,30 @@ public:
         }
 
         if (Maybe<AppInfo> maybeAppInfo = extractAppInfoFromManifest(manifestXml.get())) {
-            mContext->mCompilationPackage = maybeAppInfo.value().package;
+            mContext->setCompilationPackage(maybeAppInfo.value().package);
         } else {
             mContext->getDiagnostics()->error(DiagMessage(mOptions.manifestPath)
                                              << "no package specified in <manifest> tag");
             return 1;
         }
 
-        if (!util::isJavaPackageName(mContext->mCompilationPackage)) {
+        if (!util::isJavaPackageName(mContext->getCompilationPackage())) {
             mContext->getDiagnostics()->error(DiagMessage(mOptions.manifestPath)
                                              << "invalid package name '"
-                                             << mContext->mCompilationPackage
+                                             << mContext->getCompilationPackage()
                                              << "'");
             return 1;
         }
 
-        mContext->mNameMangler = util::make_unique<NameMangler>(
-                NameManglerPolicy{ mContext->mCompilationPackage });
+        mContext->setNameManglerPolicy(NameManglerPolicy{ mContext->getCompilationPackage() });
 
-        if (mContext->mCompilationPackage == u"android") {
-            mContext->mPackageId = 0x01;
+        if (mContext->getCompilationPackage() == u"android") {
+            mContext->setPackageId(0x01);
         } else {
-            mContext->mPackageId = 0x7f;
+            mContext->setPackageId(0x7f);
         }
 
-        mContext->mSymbols = createSymbolTableFromIncludePaths();
-        if (!mContext->mSymbols) {
+        if (!loadSymbolsFromIncludePaths()) {
             return 1;
         }
 
@@ -861,20 +1069,21 @@ public:
 
         if (mContext->verbose()) {
             mContext->getDiagnostics()->note(
-                    DiagMessage() << "linking package '" << mContext->mCompilationPackage << "' "
-                                  << "with package ID " << std::hex << (int) mContext->mPackageId);
+                    DiagMessage() << "linking package '" << mContext->getCompilationPackage()
+                                  << "' with package ID " << std::hex
+                                  << (int) mContext->getPackageId());
         }
 
 
         for (const std::string& input : inputFiles) {
-            if (!processFile(input, false)) {
+            if (!mergePath(input, false)) {
                 mContext->getDiagnostics()->error(DiagMessage() << "failed parsing input");
                 return 1;
             }
         }
 
         for (const std::string& input : mOptions.overlayFiles) {
-            if (!processFile(input, true)) {
+            if (!mergePath(input, true)) {
                 mContext->getDiagnostics()->error(DiagMessage() << "failed parsing overlays");
                 return 1;
             }
@@ -893,20 +1102,28 @@ public:
             }
         }
 
-        {
+        if (!mOptions.staticLib) {
+            // Assign IDs if we are building a regular app.
             IdAssigner idAssigner;
             if (!idAssigner.consume(mContext, &mFinalTable)) {
                 mContext->getDiagnostics()->error(DiagMessage() << "failed assigning IDs");
                 return 1;
             }
+        } else {
+            // Static libs are merged with other apps, and ID collisions are bad, so verify that
+            // no IDs have been set.
+            if (!verifyNoIdsSet()) {
+                return 1;
+            }
         }
 
-        mContext->mNameMangler = util::make_unique<NameMangler>(NameManglerPolicy{
-                mContext->mCompilationPackage, mTableMerger->getMergedPackages() });
-        mContext->mSymbols = JoinedSymbolTableBuilder()
-                .addSymbolTable(util::make_unique<SymbolTableWrapper>(&mFinalTable))
-                .addSymbolTable(std::move(mContext->mSymbols))
-                .build();
+        // Add the names to mangle based on our source merge earlier.
+        mContext->setNameManglerPolicy(NameManglerPolicy{
+                mContext->getCompilationPackage(), mTableMerger->getMergedPackages() });
+
+        // Add our table to the symbol table.
+        mContext->getExternalSymbols()->prependSource(
+                        util::make_unique<ResourceTableSymbolSource>(&mFinalTable));
 
         {
             ReferenceLinker linker;
@@ -915,20 +1132,32 @@ public:
                 return 1;
             }
 
-            ProductFilter productFilter(mOptions.products);
-            if (!productFilter.consume(mContext, &mFinalTable)) {
-                mContext->getDiagnostics()->error(DiagMessage() << "failed stripping products");
-                return 1;
-            }
+            if (mOptions.staticLib) {
+                if (!mOptions.products.empty()) {
+                    mContext->getDiagnostics()->warn(
+                            DiagMessage() << "can't select products when building static library");
+                }
 
-            // TODO(adamlesinski): Actually pass in split constraints and handle splits at the file
-            // level.
-            TableSplitter tableSplitter({}, mOptions.tableSplitterOptions);
-            if (!tableSplitter.verifySplitConstraints(mContext)) {
-                return 1;
-            }
+                if (mOptions.tableSplitterOptions.configFilter != nullptr ||
+                        mOptions.tableSplitterOptions.preferredDensity) {
+                    mContext->getDiagnostics()->warn(
+                            DiagMessage() << "can't strip resources when building static library");
+                }
+            } else {
+                ProductFilter productFilter(mOptions.products);
+                if (!productFilter.consume(mContext, &mFinalTable)) {
+                    mContext->getDiagnostics()->error(DiagMessage() << "failed stripping products");
+                    return 1;
+                }
 
-            tableSplitter.splitTable(&mFinalTable);
+                // TODO(adamlesinski): Actually pass in split constraints and handle splits at the file
+                // level.
+                TableSplitter tableSplitter({}, mOptions.tableSplitterOptions);
+                if (!tableSplitter.verifySplitConstraints(mContext)) {
+                    return 1;
+                }
+                tableSplitter.splitTable(&mFinalTable);
+            }
         }
 
         proguard::KeepSet proguardKeepSet;
@@ -949,7 +1178,7 @@ public:
             // AndroidManifest.xml has no resource name, but the CallSite is built from the name
             // (aka, which package the AndroidManifest.xml is coming from).
             // So we give it a package name so it can see local resources.
-            manifestXml->file.name.package = mContext->getCompilationPackage().toString();
+            manifestXml->file.name.package = mContext->getCompilationPackage();
 
             XmlReferenceLinker manifestLinker;
             if (manifestLinker.consume(mContext, manifestXml.get())) {
@@ -993,7 +1222,7 @@ public:
             return 1;
         }
 
-        if (!mOptions.noAutoVersion) {
+        if (!mOptions.staticLib && !mOptions.noAutoVersion) {
             AutoVersioner versioner;
             if (!versioner.consume(mContext, &mFinalTable)) {
                 mContext->getDiagnostics()->error(DiagMessage() << "failed versioning styles");
@@ -1001,9 +1230,18 @@ public:
             }
         }
 
-        if (!flattenTable(&mFinalTable, archiveWriter.get())) {
-            mContext->getDiagnostics()->error(DiagMessage() << "failed to write resources.arsc");
-            return 1;
+        if (mOptions.staticLib) {
+            if (!flattenTableToPb(&mFinalTable, archiveWriter.get())) {
+                mContext->getDiagnostics()->error(DiagMessage()
+                                                  << "failed to write resources.arsc.flat");
+                return 1;
+            }
+        } else {
+            if (!flattenTable(&mFinalTable, archiveWriter.get())) {
+                mContext->getDiagnostics()->error(DiagMessage()
+                                                  << "failed to write resources.arsc");
+                return 1;
+            }
         }
 
         if (mOptions.generateJavaClassPath) {
@@ -1065,14 +1303,17 @@ private:
     LinkContext* mContext;
     ResourceTable mFinalTable;
 
-    ResourceTable mLocalFileTable;
     std::unique_ptr<TableMerger> mTableMerger;
 
     // A pointer to the FileCollection representing the filesystem (not archives).
-    io::FileCollection* mFileCollection;
+    std::unique_ptr<io::FileCollection> mFileCollection;
 
     // A vector of IFileCollections. This is mainly here to keep ownership of the collections.
     std::vector<std::unique_ptr<io::IFileCollection>> mCollections;
+
+    // A vector of ResourceTables. This is here to retain ownership, so that the SymbolTable
+    // can use these.
+    std::vector<std::unique_ptr<ResourceTable>> mStaticTableIncludes;
 };
 
 int link(const std::vector<StringPiece>& args) {
@@ -1089,6 +1330,7 @@ int link(const std::vector<StringPiece>& args) {
     Maybe<std::string> productList;
     bool legacyXFlag = false;
     bool requireLocalization = false;
+    bool verbose = false;
     Flags flags = Flags()
             .requiredFlag("-o", "Output path", &options.outputPath)
             .requiredFlag("--manifest", "Path to the Android manifest to build",
@@ -1104,6 +1346,10 @@ int link(const std::vector<StringPiece>& args) {
             .optionalSwitch("--no-auto-version",
                             "Disables automatic style and layout SDK versioning",
                             &options.noAutoVersion)
+            .optionalSwitch("--no-version-vectors",
+                            "Disables automatic versioning of vector drawables. Use this only\n"
+                            "when building with vector drawable support library",
+                            &options.noVersionVectors)
             .optionalSwitch("-x", "Legacy flag that specifies to use the package identifier 0x01",
                             &legacyXFlag)
             .optionalSwitch("-z", "Require localization of strings marked 'suggested'",
@@ -1127,6 +1373,9 @@ int link(const std::vector<StringPiece>& args) {
             .optionalFlag("--version-name", "Version name to inject into the AndroidManifest.xml "
                           "if none is present", &versionName)
             .optionalSwitch("--static-lib", "Generate a static Android library", &options.staticLib)
+            .optionalSwitch("--no-static-lib-packages",
+                            "Merge all library resources under the app's package",
+                            &options.noStaticLibPackages)
             .optionalSwitch("--non-final-ids", "Generates R.java without the final modifier.\n"
                             "This is implied when --static-lib is specified.",
                             &options.generateNonFinalIds)
@@ -1148,12 +1397,16 @@ int link(const std::vector<StringPiece>& args) {
                           &renameInstrumentationTargetPackage)
             .optionalFlagList("-0", "File extensions not to compress",
                               &options.extensionsToNotCompress)
-            .optionalSwitch("-v", "Enables verbose logging", &context.mVerbose);
+            .optionalSwitch("-v", "Enables verbose logging", &verbose);
 
     if (!flags.parse("aapt2 link", args, &std::cerr)) {
         return 1;
     }
 
+    if (verbose) {
+        context.setVerbose(verbose);
+    }
+
     if (privateSymbolsPackage) {
         options.privateSymbols = util::utf8ToUtf16(privateSymbolsPackage.value());
     }
index f40fbfb..18c47df 100644 (file)
@@ -30,7 +30,7 @@ struct ManifestFixerTest : public ::testing::Test {
                 .setCompilationPackage(u"android")
                 .setPackageId(0x01)
                 .setNameManglerPolicy(NameManglerPolicy{ u"android" })
-                .setSymbolTable(test::StaticSymbolTableBuilder()
+                .addSymbolSource(test::StaticSymbolSourceBuilder()
                         .addSymbol(u"@android:attr/package", ResourceId(0x01010000),
                                    test::AttributeBuilder()
                                         .setTypeMask(android::ResTable_map::TYPE_STRING)
index ef3fe4f..66eb0df 100644 (file)
@@ -14,9 +14,8 @@
  * limitations under the License.
  */
 
-#include "ReferenceLinker.h"
-
 #include "Diagnostics.h"
+#include "ReferenceLinker.h"
 #include "ResourceTable.h"
 #include "ResourceUtils.h"
 #include "ResourceValues.h"
@@ -43,45 +42,10 @@ namespace {
  * NOTE: All of the entries in the ResourceTable must be assigned IDs.
  */
 class ReferenceLinkerVisitor : public ValueVisitor {
-private:
-    IAaptContext* mContext;
-    ISymbolTable* mSymbols;
-    xml::IPackageDeclStack* mPackageDecls;
-    StringPool* mStringPool;
-    CallSite* mCallSite;
-    bool mError = false;
-
-    /**
-     * Transform a RawString value into a more specific, appropriate value, based on the
-     * Attribute. If a non RawString value is passed in, this is an identity transform.
-     */
-    std::unique_ptr<Item> parseValueWithAttribute(std::unique_ptr<Item> value,
-                                                  const Attribute* attr) {
-        if (RawString* rawString = valueCast<RawString>(value.get())) {
-            std::unique_ptr<Item> transformed =
-                    ResourceUtils::parseItemForAttribute(*rawString->value, attr);
-
-            // If we could not parse as any specific type, try a basic STRING.
-            if (!transformed && (attr->typeMask & android::ResTable_map::TYPE_STRING)) {
-                util::StringBuilder stringBuilder;
-                stringBuilder.append(*rawString->value);
-                if (stringBuilder) {
-                    transformed = util::make_unique<String>(
-                            mStringPool->makeRef(stringBuilder.str()));
-                }
-            }
-
-            if (transformed) {
-                return transformed;
-            }
-        };
-        return value;
-    }
-
 public:
     using ValueVisitor::visit;
 
-    ReferenceLinkerVisitor(IAaptContext* context, ISymbolTable* symbols, StringPool* stringPool,
+    ReferenceLinkerVisitor(IAaptContext* context, SymbolTable* symbols, StringPool* stringPool,
                            xml::IPackageDeclStack* decl,CallSite* callSite) :
             mContext(context), mSymbols(symbols), mPackageDecls(decl), mStringPool(stringPool),
             mCallSite(callSite) {
@@ -114,10 +78,11 @@ public:
                                             &transformedReference);
 
             // Find the attribute in the symbol table and check if it is visible from this callsite.
-            const ISymbolTable::Symbol* symbol = ReferenceLinker::resolveAttributeCheckVisibility(
+            const SymbolTable::Symbol* symbol = ReferenceLinker::resolveAttributeCheckVisibility(
                     transformedReference, mContext->getNameMangler(), mSymbols, mCallSite, &errStr);
             if (symbol) {
                 // Assign our style key the correct ID.
+                // The ID may not exist.
                 entry.key.id = symbol->id;
 
                 // Try to convert the value to a more specific, typed value based on the
@@ -156,6 +121,41 @@ public:
     bool hasError() {
         return mError;
     }
+
+private:
+    IAaptContext* mContext;
+    SymbolTable* mSymbols;
+    xml::IPackageDeclStack* mPackageDecls;
+    StringPool* mStringPool;
+    CallSite* mCallSite;
+    bool mError = false;
+
+    /**
+     * Transform a RawString value into a more specific, appropriate value, based on the
+     * Attribute. If a non RawString value is passed in, this is an identity transform.
+     */
+    std::unique_ptr<Item> parseValueWithAttribute(std::unique_ptr<Item> value,
+                                                  const Attribute* attr) {
+        if (RawString* rawString = valueCast<RawString>(value.get())) {
+            std::unique_ptr<Item> transformed =
+                    ResourceUtils::parseItemForAttribute(*rawString->value, attr);
+
+            // If we could not parse as any specific type, try a basic STRING.
+            if (!transformed && (attr->typeMask & android::ResTable_map::TYPE_STRING)) {
+                util::StringBuilder stringBuilder;
+                stringBuilder.append(*rawString->value);
+                if (stringBuilder) {
+                    transformed = util::make_unique<String>(
+                            mStringPool->makeRef(stringBuilder.str()));
+                }
+            }
+
+            if (transformed) {
+                return transformed;
+            }
+        };
+        return value;
+    }
 };
 
 } // namespace
@@ -164,13 +164,13 @@ public:
  * The symbol is visible if it is public, or if the reference to it is requesting private access
  * or if the callsite comes from the same package.
  */
-bool ReferenceLinker::isSymbolVisible(const ISymbolTable::Symbol& symbol, const Reference& ref,
+bool ReferenceLinker::isSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref,
                                       const CallSite& callSite) {
     if (!symbol.isPublic && !ref.privateReference) {
         if (ref.name) {
             return callSite.resource.package == ref.name.value().package;
-        } else if (ref.id) {
-            return ref.id.value().packageId() == symbol.id.packageId();
+        } else if (ref.id && symbol.id) {
+            return ref.id.value().packageId() == symbol.id.value().packageId();
         } else {
             return false;
         }
@@ -178,9 +178,9 @@ bool ReferenceLinker::isSymbolVisible(const ISymbolTable::Symbol& symbol, const
     return true;
 }
 
-const ISymbolTable::Symbol* ReferenceLinker::resolveSymbol(const Reference& reference,
-                                                           NameMangler* mangler,
-                                                           ISymbolTable* symbols) {
+const SymbolTable::Symbol* ReferenceLinker::resolveSymbol(const Reference& reference,
+                                                          NameMangler* mangler,
+                                                          SymbolTable* symbols) {
     if (reference.name) {
         Maybe<ResourceName> mangled = mangler->mangleName(reference.name.value());
         return symbols->findByName(mangled ? mangled.value() : reference.name.value());
@@ -191,10 +191,10 @@ const ISymbolTable::Symbol* ReferenceLinker::resolveSymbol(const Reference& refe
     }
 }
 
-const ISymbolTable::Symbol* ReferenceLinker::resolveSymbolCheckVisibility(
-        const Reference& reference, NameMangler* nameMangler, ISymbolTable* symbols,
+const SymbolTable::Symbol* ReferenceLinker::resolveSymbolCheckVisibility(
+        const Reference& reference, NameMangler* nameMangler, SymbolTable* symbols,
         CallSite* callSite, std::string* outError) {
-    const ISymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
+    const SymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
     if (!symbol) {
         if (outError) *outError = "not found";
         return nullptr;
@@ -207,12 +207,12 @@ const ISymbolTable::Symbol* ReferenceLinker::resolveSymbolCheckVisibility(
     return symbol;
 }
 
-const ISymbolTable::Symbol* ReferenceLinker::resolveAttributeCheckVisibility(
-        const Reference& reference, NameMangler* nameMangler, ISymbolTable* symbols,
+const SymbolTable::Symbol* ReferenceLinker::resolveAttributeCheckVisibility(
+        const Reference& reference, NameMangler* nameMangler, SymbolTable* symbols,
         CallSite* callSite, std::string* outError) {
-    const ISymbolTable::Symbol* symbol = resolveSymbolCheckVisibility(reference, nameMangler,
-                                                                      symbols, callSite,
-                                                                      outError);
+    const SymbolTable::Symbol* symbol = resolveSymbolCheckVisibility(reference, nameMangler,
+                                                                     symbols, callSite,
+                                                                     outError);
     if (!symbol) {
         return nullptr;
     }
@@ -226,10 +226,10 @@ const ISymbolTable::Symbol* ReferenceLinker::resolveAttributeCheckVisibility(
 
 Maybe<xml::AaptAttribute> ReferenceLinker::compileXmlAttribute(const Reference& reference,
                                                                NameMangler* nameMangler,
-                                                               ISymbolTable* symbols,
+                                                               SymbolTable* symbols,
                                                                CallSite* callSite,
                                                                std::string* outError) {
-    const ISymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
+    const SymbolTable::Symbol* symbol = resolveSymbol(reference, nameMangler, symbols);
     if (!symbol) {
         return {};
     }
@@ -256,7 +256,7 @@ void ReferenceLinker::writeResourceName(DiagMessage* outMsg, const Reference& or
 }
 
 bool ReferenceLinker::linkReference(Reference* reference, IAaptContext* context,
-                                    ISymbolTable* symbols, xml::IPackageDeclStack* decls,
+                                    SymbolTable* symbols, xml::IPackageDeclStack* decls,
                                     CallSite* callSite) {
     assert(reference);
     assert(reference->name || reference->id);
@@ -266,9 +266,12 @@ bool ReferenceLinker::linkReference(Reference* reference, IAaptContext* context,
                                     &transformedReference);
 
     std::string errStr;
-    const ISymbolTable::Symbol* s = resolveSymbolCheckVisibility(
+    const SymbolTable::Symbol* s = resolveSymbolCheckVisibility(
             transformedReference, context->getNameMangler(), symbols, callSite, &errStr);
     if (s) {
+        // The ID may not exist. This is fine because of the possibility of building against
+        // libraries without assigned IDs.
+        // Ex: Linking against own resources when building a static library.
         reference->id = s->id;
         return true;
     }
index a0eb00c..7993aaf 100644 (file)
@@ -38,36 +38,36 @@ struct ReferenceLinker : public IResourceTableConsumer {
     /**
      * Returns true if the symbol is visible by the reference and from the callsite.
      */
-    static bool isSymbolVisible(const ISymbolTable::Symbol& symbol, const Reference& ref,
+    static bool isSymbolVisible(const SymbolTable::Symbol& symbol, const Reference& ref,
                                 const CallSite& callSite);
 
     /**
      * Performs name mangling and looks up the resource in the symbol table. Returns nullptr
      * if the symbol was not found.
      */
-    static const ISymbolTable::Symbol* resolveSymbol(const Reference& reference,
-                                                     NameMangler* mangler, ISymbolTable* symbols);
+    static const SymbolTable::Symbol* resolveSymbol(const Reference& reference,
+                                                    NameMangler* mangler, SymbolTable* symbols);
 
     /**
      * Performs name mangling and looks up the resource in the symbol table. If the symbol is
      * not visible by the reference at the callsite, nullptr is returned. outError holds
      * the error message.
      */
-    static const ISymbolTable::Symbol* resolveSymbolCheckVisibility(const Reference& reference,
-                                                                    NameMangler* nameMangler,
-                                                                    ISymbolTable* symbols,
-                                                                    CallSite* callSite,
-                                                                    std::string* outError);
+    static const SymbolTable::Symbol* resolveSymbolCheckVisibility(const Reference& reference,
+                                                                   NameMangler* nameMangler,
+                                                                   SymbolTable* symbols,
+                                                                   CallSite* callSite,
+                                                                   std::string* outError);
 
     /**
      * Same as resolveSymbolCheckVisibility(), but also makes sure the symbol is an attribute.
      * That is, the return value will have a non-null value for ISymbolTable::Symbol::attribute.
      */
-    static const ISymbolTable::Symbol* resolveAttributeCheckVisibility(const Reference& reference,
-                                                                       NameMangler* nameMangler,
-                                                                       ISymbolTable* symbols,
-                                                                       CallSite* callSite,
-                                                                       std::string* outError);
+    static const SymbolTable::Symbol* resolveAttributeCheckVisibility(const Reference& reference,
+                                                                      NameMangler* nameMangler,
+                                                                      SymbolTable* symbols,
+                                                                      CallSite* callSite,
+                                                                      std::string* outError);
 
     /**
      * Resolves the attribute reference and returns an xml::AaptAttribute if successful.
@@ -75,7 +75,7 @@ struct ReferenceLinker : public IResourceTableConsumer {
      */
     static Maybe<xml::AaptAttribute> compileXmlAttribute(const Reference& reference,
                                                          NameMangler* nameMangler,
-                                                         ISymbolTable* symbols,
+                                                         SymbolTable* symbols,
                                                          CallSite* callSite,
                                                          std::string* outError);
 
@@ -92,7 +92,7 @@ struct ReferenceLinker : public IResourceTableConsumer {
      * to the reference at the callsite, the reference is updated with an ID.
      * Returns false on failure, and an error message is logged to the IDiagnostics in the context.
      */
-    static bool linkReference(Reference* reference, IAaptContext* context, ISymbolTable* symbols,
+    static bool linkReference(Reference* reference, IAaptContext* context, SymbolTable* symbols,
                               xml::IPackageDeclStack* decls, CallSite* callSite);
 
     /**
index 8d324fe..76b2309 100644 (file)
  */
 
 #include "link/ReferenceLinker.h"
-#include "process/SymbolTable.h"
+#include "test/Test.h"
 
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+using android::ResTable_map;
 
 namespace aapt {
 
@@ -41,12 +38,10 @@ TEST(ReferenceLinkerTest, LinkSimpleReferences) {
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
-            .setSymbolTable(JoinedSymbolTableBuilder()
-                            .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
-                            .addSymbolTable(test::StaticSymbolTableBuilder()
-                                    .addPublicSymbol(u"@android:string/ok", ResourceId(0x01040034))
-                                    .build())
-                            .build())
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addPublicSymbol(u"@android:string/ok", ResourceId(0x01040034))
+                                     .build())
             .build();
 
     ReferenceLinker linker;
@@ -91,19 +86,20 @@ TEST(ReferenceLinkerTest, LinkStyleAttributes) {
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
-            .setSymbolTable(test::StaticSymbolTableBuilder()
-                    .addPublicSymbol(u"@android:style/Theme.Material", ResourceId(0x01060000))
-                    .addPublicSymbol(u"@android:attr/foo", ResourceId(0x01010001),
-                               test::AttributeBuilder()
-                                    .setTypeMask(android::ResTable_map::TYPE_COLOR)
-                                    .build())
-                    .addPublicSymbol(u"@android:attr/bar", ResourceId(0x01010002),
-                               test::AttributeBuilder()
-                                    .setTypeMask(android::ResTable_map::TYPE_FLAGS)
-                                    .addItem(u"one", 0x01)
-                                    .addItem(u"two", 0x02)
-                                    .build())
-                    .build())
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addPublicSymbol(u"@android:style/Theme.Material",
+                                                      ResourceId(0x01060000))
+                                     .addPublicSymbol(u"@android:attr/foo", ResourceId(0x01010001),
+                                                      test::AttributeBuilder()
+                                                              .setTypeMask(ResTable_map::TYPE_COLOR)
+                                                              .build())
+                                     .addPublicSymbol(u"@android:attr/bar", ResourceId(0x01010002),
+                                                      test::AttributeBuilder()
+                                                              .setTypeMask(ResTable_map::TYPE_FLAGS)
+                                                              .addItem(u"one", 0x01)
+                                                              .addItem(u"two", 0x02)
+                                                              .build())
+                                     .build())
             .build();
 
     ReferenceLinker linker;
@@ -131,11 +127,13 @@ TEST(ReferenceLinkerTest, LinkMangledReferencesAndAttributes) {
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test", { u"com.android.support" } })
-            .setSymbolTable(test::StaticSymbolTableBuilder()
-                    .addPublicSymbol(u"@com.app.test:attr/com.android.support$foo",
-                               ResourceId(0x7f010000), test::AttributeBuilder()
-                                        .setTypeMask(android::ResTable_map::TYPE_COLOR).build())
-                    .build())
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addPublicSymbol(u"@com.app.test:attr/com.android.support$foo",
+                                                      ResourceId(0x7f010000),
+                                                      test::AttributeBuilder()
+                                                              .setTypeMask(ResTable_map::TYPE_COLOR)
+                                                              .build())
+                                     .build())
             .build();
 
     std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
@@ -167,12 +165,10 @@ TEST(ReferenceLinkerTest, FailToLinkPrivateSymbols) {
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
-            .setSymbolTable(JoinedSymbolTableBuilder()
-                            .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
-                            .addSymbolTable(test::StaticSymbolTableBuilder()
-                                    .addSymbol(u"@android:string/hidden", ResourceId(0x01040034))
-                                    .build())
-                            .build())
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addSymbol(u"@android:string/hidden", ResourceId(0x01040034))
+                                     .build())
             .build();
 
     ReferenceLinker linker;
@@ -190,13 +186,12 @@ TEST(ReferenceLinkerTest, FailToLinkPrivateMangledSymbols) {
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test", { u"com.app.lib" } })
-            .setSymbolTable(JoinedSymbolTableBuilder()
-                            .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
-                            .addSymbolTable(test::StaticSymbolTableBuilder()
-                                    .addSymbol(u"@com.app.test:string/com.app.lib$hidden",
-                                               ResourceId(0x7f040034))
-                                    .build())
-                            .build())
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addSymbol(u"@com.app.test:string/com.app.lib$hidden",
+                                                ResourceId(0x7f040034))
+                                     .build())
+
             .build();
 
     ReferenceLinker linker;
@@ -215,15 +210,14 @@ TEST(ReferenceLinkerTest, FailToLinkPrivateStyleAttributes) {
             .setCompilationPackage(u"com.app.test")
             .setPackageId(0x7f)
             .setNameManglerPolicy(NameManglerPolicy{ u"com.app.test" })
-            .setSymbolTable(JoinedSymbolTableBuilder()
-                            .addSymbolTable(util::make_unique<SymbolTableWrapper>(table.get()))
-                            .addSymbolTable(test::StaticSymbolTableBuilder()
-                                    .addSymbol(u"@android:attr/hidden", ResourceId(0x01010001),
-                                               test::AttributeBuilder()
-                                                    .setTypeMask(android::ResTable_map::TYPE_COLOR)
-                                                    .build())
-                                    .build())
-                            .build())
+            .addSymbolSource(util::make_unique<ResourceTableSymbolSource>(table.get()))
+            .addSymbolSource(test::StaticSymbolSourceBuilder()
+                                     .addSymbol(u"@android:attr/hidden", ResourceId(0x01010001),
+                                                test::AttributeBuilder()
+                                                        .setTypeMask(
+                                                                android::ResTable_map::TYPE_COLOR)
+                                                        .build())
+                                     .build())
             .build();
 
     ReferenceLinker linker;
index 5f11745..7471e15 100644 (file)
@@ -34,10 +34,21 @@ TableMerger::TableMerger(IAaptContext* context, ResourceTable* outTable,
     assert(mMasterPackage && "package name or ID already taken");
 }
 
+bool TableMerger::merge(const Source& src, ResourceTable* table,
+                        io::IFileCollection* collection) {
+    return mergeImpl(src, table, collection, false /* overlay */, true /* allow new */);
+}
+
+bool TableMerger::mergeOverlay(const Source& src, ResourceTable* table,
+                               io::IFileCollection* collection) {
+    return mergeImpl(src, table, collection, true /* overlay */, mOptions.autoAddOverlay);
+}
+
 /**
  * This will merge packages with the same package name (or no package name).
  */
 bool TableMerger::mergeImpl(const Source& src, ResourceTable* table,
+                            io::IFileCollection* collection,
                             bool overlay, bool allowNew) {
     const uint8_t desiredPackageId = mContext->getPackageId();
 
@@ -51,26 +62,36 @@ bool TableMerger::mergeImpl(const Source& src, ResourceTable* table,
         }
 
         if (package->name.empty() || mContext->getCompilationPackage() == package->name) {
+            FileMergeCallback callback;
+            if (collection) {
+                callback = [&](const ResourceNameRef& name, const ConfigDescription& config,
+                               FileReference* newFile, FileReference* oldFile) -> bool {
+                    // The old file's path points inside the APK, so we can use it as is.
+                    io::IFile* f = collection->findFile(util::utf16ToUtf8(*oldFile->path));
+                    if (!f) {
+                        mContext->getDiagnostics()->error(DiagMessage(src) << "file '"
+                                                          << *oldFile->path
+                                                          << "' not found");
+                        return false;
+                    }
+
+                    newFile->file = f;
+                    return true;
+                };
+            }
+
             // Merge here. Once the entries are merged and mangled, any references to
             // them are still valid. This is because un-mangled references are
             // mangled, then looked up at resolution time.
             // Also, when linking, we convert references with no package name to use
             // the compilation package name.
             error |= !doMerge(src, table, package.get(),
-                              false /* mangle */, overlay, allowNew, {});
+                              false /* mangle */, overlay, allowNew, callback);
         }
     }
     return !error;
 }
 
-bool TableMerger::merge(const Source& src, ResourceTable* table) {
-    return mergeImpl(src, table, false /* overlay */, true /* allow new */);
-}
-
-bool TableMerger::mergeOverlay(const Source& src, ResourceTable* table) {
-    return mergeImpl(src, table, true /* overlay */, mOptions.autoAddOverlay);
-}
-
 /**
  * This will merge and mangle resources from a static library.
  */
index b3c22dd..80c2a5e 100644 (file)
@@ -65,13 +65,17 @@ public:
 
     /**
      * Merges resources from the same or empty package. This is for local sources.
+     * An io::IFileCollection is optional and used to find the referenced Files and process them.
      */
-    bool merge(const Source& src, ResourceTable* table);
+    bool merge(const Source& src, ResourceTable* table,
+               io::IFileCollection* collection = nullptr);
 
     /**
      * Merges resources from an overlay ResourceTable.
+     * An io::IFileCollection is optional and used to find the referenced Files and process them.
      */
-    bool mergeOverlay(const Source& src, ResourceTable* table);
+    bool mergeOverlay(const Source& src, ResourceTable* table,
+                      io::IFileCollection* collection = nullptr);
 
     /**
      * Merges resources from the given package, mangling the name. This is for static libraries.
@@ -104,7 +108,7 @@ private:
 
     bool mergeFileImpl(const ResourceFile& fileDesc, io::IFile* file, bool overlay);
 
-    bool mergeImpl(const Source& src, ResourceTable* srcTable,
+    bool mergeImpl(const Source& src, ResourceTable* srcTable, io::IFileCollection* collection,
                    bool overlay, bool allowNew);
 
     bool doMerge(const Source& src, ResourceTable* srcTable, ResourceTablePackage* srcPackage,
index a26d763..568bc74 100644 (file)
@@ -34,17 +34,10 @@ namespace {
  * as needed.
  */
 class ReferenceVisitor : public ValueVisitor {
-private:
-    IAaptContext* mContext;
-    ISymbolTable* mSymbols;
-    xml::IPackageDeclStack* mDecls;
-    CallSite* mCallSite;
-    bool mError;
-
 public:
     using ValueVisitor::visit;
 
-    ReferenceVisitor(IAaptContext* context, ISymbolTable* symbols, xml::IPackageDeclStack* decls,
+    ReferenceVisitor(IAaptContext* context, SymbolTable* symbols, xml::IPackageDeclStack* decls,
                      CallSite* callSite) :
              mContext(context), mSymbols(symbols), mDecls(decls), mCallSite(callSite),
              mError(false) {
@@ -59,25 +52,23 @@ public:
     bool hasError() const {
         return mError;
     }
+
+private:
+    IAaptContext* mContext;
+    SymbolTable* mSymbols;
+    xml::IPackageDeclStack* mDecls;
+    CallSite* mCallSite;
+    bool mError;
 };
 
 /**
  * Visits each xml Element and compiles the attributes within.
  */
 class XmlVisitor : public xml::PackageAwareVisitor {
-private:
-    IAaptContext* mContext;
-    ISymbolTable* mSymbols;
-    Source mSource;
-    std::set<int>* mSdkLevelsFound;
-    CallSite* mCallSite;
-    ReferenceVisitor mReferenceVisitor;
-    bool mError = false;
-
 public:
     using xml::PackageAwareVisitor::visit;
 
-    XmlVisitor(IAaptContext* context, ISymbolTable* symbols, const Source& source,
+    XmlVisitor(IAaptContext* context, SymbolTable* symbols, const Source& source,
                std::set<int>* sdkLevelsFound, CallSite* callSite) :
             mContext(context), mSymbols(symbols), mSource(source), mSdkLevelsFound(sdkLevelsFound),
             mCallSite(callSite), mReferenceVisitor(context, symbols, this, callSite) {
@@ -105,10 +96,13 @@ public:
 
                 // Convert the string value into a compiled Value if this is a valid attribute.
                 if (attr.compiledAttribute) {
-                    // Record all SDK levels from which the attributes were defined.
-                    const int sdkLevel = findAttributeSdkLevel(attr.compiledAttribute.value().id);
-                    if (sdkLevel > 1) {
-                        mSdkLevelsFound->insert(sdkLevel);
+                    if (attr.compiledAttribute.value().id) {
+                        // Record all SDK levels from which the attributes were defined.
+                        const size_t sdkLevel = findAttributeSdkLevel(
+                                attr.compiledAttribute.value().id.value());
+                        if (sdkLevel > 1) {
+                            mSdkLevelsFound->insert(sdkLevel);
+                        }
                     }
 
                     const Attribute* attribute = &attr.compiledAttribute.value().attribute;
@@ -124,6 +118,7 @@ public:
                                                     << *attribute);
                         mError = true;
                     }
+
                 } else {
                     mContext->getDiagnostics()->error(DiagMessage(source)
                                                       << "attribute '" << package << ":"
@@ -150,6 +145,15 @@ public:
     bool hasError() {
         return mError || mReferenceVisitor.hasError();
     }
+
+private:
+    IAaptContext* mContext;
+    SymbolTable* mSymbols;
+    Source mSource;
+    std::set<int>* mSdkLevelsFound;
+    CallSite* mCallSite;
+    ReferenceVisitor mReferenceVisitor;
+    bool mError = false;
 };
 
 } // namespace
index 3bfaf91..af9098b 100644 (file)
  * limitations under the License.
  */
 
+#include <test/Context.h>
 #include "link/Linkers.h"
-
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
 
 namespace aapt {
 
@@ -30,7 +27,7 @@ public:
                 .setCompilationPackage(u"com.app.test")
                 .setNameManglerPolicy(
                         NameManglerPolicy{ u"com.app.test", { u"com.android.support" } })
-                .setSymbolTable(test::StaticSymbolTableBuilder()
+                .addSymbolSource(test::StaticSymbolSourceBuilder()
                         .addPublicSymbol(u"@android:attr/layout_width", ResourceId(0x01010000),
                                    test::AttributeBuilder()
                                         .setTypeMask(android::ResTable_map::TYPE_ENUM |
@@ -92,14 +89,16 @@ TEST_F(XmlReferenceLinkerTest, LinkBasicAttributes) {
                                                     u"layout_width");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x01010000));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010000));
     ASSERT_NE(xmlAttr->compiledValue, nullptr);
     ASSERT_NE(valueCast<BinaryPrimitive>(xmlAttr->compiledValue.get()), nullptr);
 
     xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/android", u"background");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x01010001));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010001));
     ASSERT_NE(xmlAttr->compiledValue, nullptr);
     Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
     ASSERT_NE(ref, nullptr);
@@ -163,7 +162,8 @@ TEST_F(XmlReferenceLinkerTest, LinkMangledAttributes) {
             u"http://schemas.android.com/apk/res/com.android.support", u"colorAccent");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010001));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010001));
     ASSERT_NE(valueCast<BinaryPrimitive>(xmlAttr->compiledValue.get()), nullptr);
 }
 
@@ -182,7 +182,8 @@ TEST_F(XmlReferenceLinkerTest, LinkAutoResReference) {
                                                     u"colorAccent");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010000));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010000));
     Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
     ASSERT_NE(ref, nullptr);
     AAPT_ASSERT_TRUE(ref->name);
@@ -209,7 +210,8 @@ TEST_F(XmlReferenceLinkerTest, LinkViewWithShadowedPackageAlias) {
                                                     u"attr");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x01010002));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x01010002));
     Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
     ASSERT_NE(ref, nullptr);
     AAPT_ASSERT_TRUE(ref->id);
@@ -223,7 +225,8 @@ TEST_F(XmlReferenceLinkerTest, LinkViewWithShadowedPackageAlias) {
     xmlAttr = viewEl->findAttribute(u"http://schemas.android.com/apk/res/com.app.test", u"attr");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010002));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010002));
     ref = valueCast<Reference>(xmlAttr->compiledValue.get());
     ASSERT_NE(ref, nullptr);
     AAPT_ASSERT_TRUE(ref->id);
@@ -246,7 +249,8 @@ TEST_F(XmlReferenceLinkerTest, LinkViewWithLocalPackageAndAliasOfTheSameName) {
             u"http://schemas.android.com/apk/res/com.app.test", u"attr");
     ASSERT_NE(xmlAttr, nullptr);
     AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute);
-    EXPECT_EQ(xmlAttr->compiledAttribute.value().id, ResourceId(0x7f010002));
+    AAPT_ASSERT_TRUE(xmlAttr->compiledAttribute.value().id);
+    EXPECT_EQ(xmlAttr->compiledAttribute.value().id.value(), ResourceId(0x7f010002));
     Reference* ref = valueCast<Reference>(xmlAttr->compiledValue.get());
     ASSERT_NE(ref, nullptr);
     AAPT_ASSERT_TRUE(ref->id);
index 3a88044..9affb83 100644 (file)
 namespace aapt {
 
 class ResourceTable;
-struct ISymbolTable;
+class SymbolTable;
 
 struct IAaptContext {
     virtual ~IAaptContext() = default;
 
-    virtual ISymbolTable* getExternalSymbols() = 0;
+    virtual SymbolTable* getExternalSymbols() = 0;
     virtual IDiagnostics* getDiagnostics() = 0;
-    virtual StringPiece16 getCompilationPackage() = 0;
+    virtual const std::u16string& getCompilationPackage() = 0;
     virtual uint8_t getPackageId() = 0;
     virtual NameMangler* getNameMangler() = 0;
     virtual bool verbose() = 0;
index b6030a2..a8f9bfe 100644 (file)
 
 namespace aapt {
 
-const ISymbolTable::Symbol* SymbolTableWrapper::findByName(const ResourceName& name) {
+void SymbolTable::appendSource(std::unique_ptr<ISymbolSource> source) {
+    mSources.push_back(std::move(source));
+
+    // We do not clear the cache, because sources earlier in the list take precedent.
+}
+
+void SymbolTable::prependSource(std::unique_ptr<ISymbolSource> source) {
+    mSources.insert(mSources.begin(), std::move(source));
+
+    // We must clear the cache in case we did a lookup before adding this resource.
+    mCache.clear();
+}
+
+const SymbolTable::Symbol* SymbolTable::findByName(const ResourceName& name) {
     if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
         return s.get();
     }
 
+    // We did not find it in the cache, so look through the sources.
+    for (auto& symbolSource : mSources) {
+        std::unique_ptr<Symbol> symbol = symbolSource->findByName(name);
+        if (symbol) {
+            // Take ownership of the symbol into a shared_ptr. We do this because LruCache
+            // doesn't support unique_ptr.
+            std::shared_ptr<Symbol> sharedSymbol = std::shared_ptr<Symbol>(symbol.release());
+            mCache.put(name, sharedSymbol);
+            return sharedSymbol.get();
+        }
+    }
+    return nullptr;
+}
+
+const SymbolTable::Symbol* SymbolTable::findById(ResourceId id) {
+    if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) {
+        return s.get();
+    }
+
+    // We did not find it in the cache, so look through the sources.
+    for (auto& symbolSource : mSources) {
+        std::unique_ptr<Symbol> symbol = symbolSource->findById(id);
+        if (symbol) {
+            // Take ownership of the symbol into a shared_ptr. We do this because LruCache
+            // doesn't support unique_ptr.
+            std::shared_ptr<Symbol> sharedSymbol = std::shared_ptr<Symbol>(symbol.release());
+            mIdCache.put(id, sharedSymbol);
+            return sharedSymbol.get();
+        }
+    }
+    return nullptr;
+}
+
+std::unique_ptr<SymbolTable::Symbol> ResourceTableSymbolSource::findByName(
+        const ResourceName& name) {
     Maybe<ResourceTable::SearchResult> result = mTable->findResource(name);
     if (!result) {
         if (name.type == ResourceType::kAttr) {
@@ -41,16 +89,13 @@ const ISymbolTable::Symbol* SymbolTableWrapper::findByName(const ResourceName& n
 
     ResourceTable::SearchResult sr = result.value();
 
-    // If no ID exists, we treat the symbol as missing. SymbolTables are used to
-    // find symbols to link.
-    if (!sr.package->id || !sr.type->id || !sr.entry->id) {
-        return {};
-    }
-
-    std::shared_ptr<Symbol> symbol = std::make_shared<Symbol>();
-    symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value());
+    std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>();
     symbol->isPublic = (sr.entry->symbolStatus.state == SymbolState::kPublic);
 
+    if (sr.package->id && sr.type->id && sr.entry->id) {
+        symbol->id = ResourceId(sr.package->id.value(), sr.type->id.value(), sr.entry->id.value());
+    }
+
     if (name.type == ResourceType::kAttr || name.type == ResourceType::kAttrPrivate) {
         const ConfigDescription kDefaultConfig;
         ResourceConfigValue* configValue = sr.entry->findValue(kDefaultConfig);
@@ -63,18 +108,16 @@ const ISymbolTable::Symbol* SymbolTableWrapper::findByName(const ResourceName& n
             }
         }
     }
+    return symbol;
+}
 
-    if (name.type == ResourceType::kAttrPrivate) {
-        // Masquerade this entry as kAttr.
-        mCache.put(ResourceName(name.package, ResourceType::kAttr, name.entry), symbol);
-    } else {
-        mCache.put(name, symbol);
-    }
-    return symbol.get();
+bool AssetManagerSymbolSource::addAssetPath(const StringPiece& path) {
+    int32_t cookie = 0;
+    return mAssets.addAssetPath(android::String8(path.data(), path.size()), &cookie);
 }
 
-static std::shared_ptr<ISymbolTable::Symbol> lookupAttributeInTable(const android::ResTable& table,
-                                                                    ResourceId id) {
+static std::unique_ptr<SymbolTable::Symbol> lookupAttributeInTable(const android::ResTable& table,
+                                                                   ResourceId id) {
     // Try as a bag.
     const android::ResTable::bag_entry* entry;
     ssize_t count = table.lockBag(id.id, &entry);
@@ -84,7 +127,7 @@ static std::shared_ptr<ISymbolTable::Symbol> lookupAttributeInTable(const androi
     }
 
     // We found a resource.
-    std::shared_ptr<ISymbolTable::Symbol> s = std::make_shared<ISymbolTable::Symbol>();
+    std::unique_ptr<SymbolTable::Symbol> s = util::make_unique<SymbolTable::Symbol>();
     s->id = id;
 
     // Check to see if it is an attribute.
@@ -138,43 +181,36 @@ static std::shared_ptr<ISymbolTable::Symbol> lookupAttributeInTable(const androi
     return s;
 }
 
-const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findByName(
+std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findByName(
         const ResourceName& name) {
-    if (const std::shared_ptr<Symbol>& s = mCache.get(name)) {
-        return s.get();
+    const android::ResTable& table = mAssets.getResources(false);
+    StringPiece16 typeStr = toString(name.type);
+    uint32_t typeSpecFlags = 0;
+    ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(),
+                                               typeStr.data(), typeStr.size(),
+                                               name.package.data(), name.package.size(),
+                                               &typeSpecFlags);
+    if (!resId.isValid()) {
+        return {};
     }
 
-    for (const auto& asset : mAssets) {
-        const android::ResTable& table = asset->getResources(false);
-        StringPiece16 typeStr = toString(name.type);
-        uint32_t typeSpecFlags = 0;
-        ResourceId resId = table.identifierForName(name.entry.data(), name.entry.size(),
-                                                   typeStr.data(), typeStr.size(),
-                                                   name.package.data(), name.package.size(),
-                                                   &typeSpecFlags);
-        if (!resId.isValid()) {
-            continue;
-        }
-
-        std::shared_ptr<Symbol> s;
-        if (name.type == ResourceType::kAttr) {
-            s = lookupAttributeInTable(table, resId);
-        } else {
-            s = std::make_shared<Symbol>();
-            s->id = resId;
-        }
+    std::unique_ptr<SymbolTable::Symbol> s;
+    if (name.type == ResourceType::kAttr) {
+        s = lookupAttributeInTable(table, resId);
+    } else {
+        s = util::make_unique<SymbolTable::Symbol>();
+        s->id = resId;
+    }
 
-        if (s) {
-            s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
-            mCache.put(name, s);
-            return s.get();
-        }
+    if (s) {
+        s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+        return s;
     }
-    return nullptr;
+    return {};
 }
 
 static Maybe<ResourceName> getResourceName(const android::ResTable& table, ResourceId id) {
-    android::ResTable::resource_name resName;
+    android::ResTable::resource_name resName = {};
     if (!table.getResourceName(id.id, true, &resName)) {
         return {};
     }
@@ -211,55 +247,27 @@ static Maybe<ResourceName> getResourceName(const android::ResTable& table, Resou
     return name;
 }
 
-const ISymbolTable::Symbol* AssetManagerSymbolTableBuilder::AssetManagerSymbolTable::findById(
-        ResourceId id) {
-    if (const std::shared_ptr<Symbol>& s = mIdCache.get(id)) {
-        return s.get();
+std::unique_ptr<SymbolTable::Symbol> AssetManagerSymbolSource::findById(ResourceId id) {
+    const android::ResTable& table = mAssets.getResources(false);
+    Maybe<ResourceName> maybeName = getResourceName(table, id);
+    if (!maybeName) {
+        return {};
     }
 
-    for (const auto& asset : mAssets) {
-        const android::ResTable& table = asset->getResources(false);
-
-        Maybe<ResourceName> maybeName = getResourceName(table, id);
-        if (!maybeName) {
-            continue;
-        }
-
-        uint32_t typeSpecFlags = 0;
-        table.getResourceFlags(id.id, &typeSpecFlags);
-
-        std::shared_ptr<Symbol> s;
-        if (maybeName.value().type == ResourceType::kAttr) {
-            s = lookupAttributeInTable(table, id);
-        } else {
-            s = std::make_shared<Symbol>();
-            s->id = id;
-        }
+    uint32_t typeSpecFlags = 0;
+    table.getResourceFlags(id.id, &typeSpecFlags);
 
-        if (s) {
-            s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
-            mIdCache.put(id, s);
-            return s.get();
-        }
-    }
-    return nullptr;
-}
-
-const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findByName(
-        const ResourceName& name) {
-    for (auto& symbolTable : mSymbolTables) {
-        if (const Symbol* s = symbolTable->findByName(name)) {
-            return s;
-        }
+    std::unique_ptr<SymbolTable::Symbol> s;
+    if (maybeName.value().type == ResourceType::kAttr) {
+        s = lookupAttributeInTable(table, id);
+    } else {
+        s = util::make_unique<SymbolTable::Symbol>();
+        s->id = id;
     }
-    return {};
-}
 
-const ISymbolTable::Symbol* JoinedSymbolTableBuilder::JoinedSymbolTable::findById(ResourceId id) {
-    for (auto& symbolTable : mSymbolTables) {
-        if (const Symbol* s = symbolTable->findById(id)) {
-            return s;
-        }
+    if (s) {
+        s->isPublic = (typeSpecFlags & android::ResTable_typeSpec::SPEC_PUBLIC) != 0;
+        return s;
     }
     return {};
 }
index 22096ed..8ea1c75 100644 (file)
 #include <utils/JenkinsHash.h>
 #include <utils/LruCache.h>
 
+#include <android-base/macros.h>
 #include <androidfw/AssetManager.h>
 #include <algorithm>
-#include <map>
 #include <memory>
 #include <vector>
 
 namespace aapt {
 
-struct ISymbolTable {
-    virtual ~ISymbolTable() = default;
-
-    struct Symbol {
-        ResourceId id;
-        std::unique_ptr<Attribute> attribute;
-        bool isPublic;
-    };
-
-    /**
-     * Never hold on to the result between calls to findByName or findById. The results
-     * are typically stored in a cache which may evict entries.
-     */
-    virtual const Symbol* findByName(const ResourceName& name) = 0;
-    virtual const Symbol* findById(ResourceId id) = 0;
-};
-
 inline android::hash_t hash_type(const ResourceName& name) {
     std::hash<std::u16string> strHash;
     android::hash_t hash = 0;
-    hash = android::JenkinsHashMix(hash, strHash(name.package));
+    hash = android::JenkinsHashMix(hash, (uint32_t) strHash(name.package));
     hash = android::JenkinsHashMix(hash, (uint32_t) name.type);
-    hash = android::JenkinsHashMix(hash, strHash(name.entry));
+    hash = android::JenkinsHashMix(hash, (uint32_t) strHash(name.entry));
     return hash;
 }
 
@@ -63,88 +46,87 @@ inline android::hash_t hash_type(const ResourceId& id) {
     return android::hash_type(id.id);
 }
 
-/**
- * Presents a ResourceTable as an ISymbolTable, caching results.
- * Instances of this class must outlive the encompassed ResourceTable.
- * Since symbols are cached, the ResourceTable should not change during the
- * lifetime of this SymbolTableWrapper.
- *
- * If a resource in the ResourceTable does not have a ResourceID assigned to it,
- * it is ignored.
- *
- * Lookups by ID are ignored.
- */
-class SymbolTableWrapper : public ISymbolTable {
-private:
-    ResourceTable* mTable;
-
-    // We use shared_ptr because unique_ptr is not supported and
-    // we need automatic deletion.
-    android::LruCache<ResourceName, std::shared_ptr<Symbol>> mCache;
+class ISymbolSource;
 
+class SymbolTable {
 public:
-    SymbolTableWrapper(ResourceTable* table) : mTable(table), mCache(200) {
+    struct Symbol {
+        Maybe<ResourceId> id;
+        std::unique_ptr<Attribute> attribute;
+        bool isPublic;
+    };
+
+    SymbolTable() : mCache(200), mIdCache(200) {
     }
 
-    const Symbol* findByName(const ResourceName& name) override;
+    void appendSource(std::unique_ptr<ISymbolSource> source);
+    void prependSource(std::unique_ptr<ISymbolSource> source);
 
-    // Unsupported, all queries to ResourceTable should be done by name.
-    const Symbol* findById(ResourceId id) override {
-        return {};
-    }
-};
+    /**
+     * Never hold on to the result between calls to findByName or findById. The results
+     * are typically stored in a cache which may evict entries.
+     */
+    const Symbol* findByName(const ResourceName& name);
+    const Symbol* findById(ResourceId id);
 
-class AssetManagerSymbolTableBuilder {
 private:
-    struct AssetManagerSymbolTable : public ISymbolTable {
-        std::vector<std::unique_ptr<android::AssetManager>> mAssets;
+    std::vector<std::unique_ptr<ISymbolSource>> mSources;
 
-        // We use shared_ptr because unique_ptr is not supported and
-        // we need automatic deletion.
-        android::LruCache<ResourceName, std::shared_ptr<Symbol>> mCache;
-        android::LruCache<ResourceId, std::shared_ptr<Symbol>> mIdCache;
+    // We use shared_ptr because unique_ptr is not supported and
+    // we need automatic deletion.
+    android::LruCache<ResourceName, std::shared_ptr<Symbol>> mCache;
+    android::LruCache<ResourceId, std::shared_ptr<Symbol>> mIdCache;
 
-        AssetManagerSymbolTable() : mCache(200), mIdCache(200) {
-        }
+    DISALLOW_COPY_AND_ASSIGN(SymbolTable);
+};
 
-        const Symbol* findByName(const ResourceName& name) override;
-        const Symbol* findById(ResourceId id) override;
-    };
+/**
+ * An interface that a symbol source implements in order to surface symbol information
+ * to the symbol table.
+ */
+class ISymbolSource {
+public:
+    virtual ~ISymbolSource() = default;
 
-    std::unique_ptr<AssetManagerSymbolTable> mSymbolTable =
-            util::make_unique<AssetManagerSymbolTable>();
+    virtual std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) = 0;
+    virtual std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) = 0;
+};
 
+/**
+ * Exposes the resources in a ResourceTable as symbols for SymbolTable.
+ * Instances of this class must outlive the encompassed ResourceTable.
+ * Lookups by ID are ignored.
+ */
+class ResourceTableSymbolSource : public ISymbolSource {
 public:
-    AssetManagerSymbolTableBuilder& add(std::unique_ptr<android::AssetManager> assetManager) {
-        mSymbolTable->mAssets.push_back(std::move(assetManager));
-        return *this;
+    explicit ResourceTableSymbolSource(ResourceTable* table) : mTable(table) {
     }
 
-    std::unique_ptr<ISymbolTable> build() {
-        return std::move(mSymbolTable);
+    std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) override;
+
+    std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) override {
+        return {};
     }
-};
 
-class JoinedSymbolTableBuilder {
 private:
-    struct JoinedSymbolTable : public ISymbolTable {
-        std::vector<std::unique_ptr<ISymbolTable>> mSymbolTables;
-
-        const Symbol* findByName(const ResourceName& name) override;
-        const Symbol* findById(ResourceId id) override;
-    };
+    ResourceTable* mTable;
 
-    std::unique_ptr<JoinedSymbolTable> mSymbolTable = util::make_unique<JoinedSymbolTable>();
+    DISALLOW_COPY_AND_ASSIGN(ResourceTableSymbolSource);
+};
 
+class AssetManagerSymbolSource : public ISymbolSource {
 public:
-    JoinedSymbolTableBuilder& addSymbolTable(std::unique_ptr<ISymbolTable> table) {
-        mSymbolTable->mSymbolTables.push_back(std::move(table));
-        return *this;
-    }
+    AssetManagerSymbolSource() = default;
 
-    std::unique_ptr<ISymbolTable> build() {
-        return std::move(mSymbolTable);
-    }
+    bool addAssetPath(const StringPiece& path);
+
+    std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) override;
+    std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) override;
+
+private:
+    android::AssetManager mAssets;
+
+    DISALLOW_COPY_AND_ASSIGN(AssetManagerSymbolSource);
 };
 
 } // namespace aapt
index 1dc3b4f..34f31be 100644 (file)
  */
 
 #include "process/SymbolTable.h"
-#include "test/Builders.h"
-#include "test/Context.h"
-
-#include <gtest/gtest.h>
+#include "test/Test.h"
 
 namespace aapt {
 
-TEST(SymbolTableWrapperTest, FindSymbolsWithIds) {
+TEST(ResourceTableSymbolSourceTest, FindSymbols) {
     std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
             .addSimple(u"@android:id/foo", ResourceId(0x01020000))
             .addSimple(u"@android:id/bar")
@@ -30,27 +27,27 @@ TEST(SymbolTableWrapperTest, FindSymbolsWithIds) {
                       test::AttributeBuilder().build())
             .build();
 
-    SymbolTableWrapper symbolTable(table.get());
-    EXPECT_NE(symbolTable.findByName(test::parseNameOrDie(u"@android:id/foo")), nullptr);
-    EXPECT_EQ(symbolTable.findByName(test::parseNameOrDie(u"@android:id/bar")), nullptr);
+    ResourceTableSymbolSource symbolSource(table.get());
+    EXPECT_NE(nullptr, symbolSource.findByName(test::parseNameOrDie(u"@android:id/foo")));
+    EXPECT_NE(nullptr, symbolSource.findByName(test::parseNameOrDie(u"@android:id/bar")));
 
-    const ISymbolTable::Symbol* s = symbolTable.findByName(
+    std::unique_ptr<SymbolTable::Symbol> s = symbolSource.findByName(
             test::parseNameOrDie(u"@android:attr/foo"));
-    ASSERT_NE(s, nullptr);
-    EXPECT_NE(s->attribute, nullptr);
+    ASSERT_NE(nullptr, s);
+    EXPECT_NE(nullptr, s->attribute);
 }
 
-TEST(SymbolTableWrapperTest, FindPrivateAttrSymbol) {
+TEST(ResourceTableSymbolSourceTest, FindPrivateAttrSymbol) {
     std::unique_ptr<ResourceTable> table = test::ResourceTableBuilder()
             .addValue(u"@android:^attr-private/foo", ResourceId(0x01010000),
                       test::AttributeBuilder().build())
             .build();
 
-    SymbolTableWrapper symbolTable(table.get());
-    const ISymbolTable::Symbol* s = symbolTable.findByName(
+    ResourceTableSymbolSource symbolSource(table.get());
+    std::unique_ptr<SymbolTable::Symbol> s = symbolSource.findByName(
                 test::parseNameOrDie(u"@android:attr/foo"));
-    ASSERT_NE(s, nullptr);
-    EXPECT_NE(s->attribute, nullptr);
+    ASSERT_NE(nullptr, s);
+    EXPECT_NE(nullptr, s->attribute);
 }
 
 } // namespace aapt
index 9856a00..86883f8 100644 (file)
@@ -483,8 +483,13 @@ const pb::CompiledFile* CompiledFileInputStream::CompiledFile() {
         }
 
         const size_t padding = 4 - (pbSize & 0x03);
-        mData += sizeof(uint64_t) + pbSize + padding;
-        mSize -= sizeof(uint64_t) + pbSize + padding;
+        const size_t offset = sizeof(uint64_t) + pbSize + padding;
+        if (offset > mSize) {
+            return nullptr;
+        }
+
+        mData += offset;
+        mSize -= offset;
         mPbFile = std::move(pbFile);
     }
     return mPbFile.get();
index b3d87d8..5d1b72b 100644 (file)
@@ -178,10 +178,13 @@ private:
     void serializeReferenceToPb(const Reference& ref, pb::Reference* pbRef) {
         if (ref.id) {
             pbRef->set_id(ref.id.value().id);
-        } else if (ref.name) {
+        }
+
+        if (ref.name) {
             StringPool::Ref symbolRef = mSymbolPool->makeRef(ref.name.value().toString());
             pbRef->set_symbol_idx(static_cast<uint32_t>(symbolRef.getIndex()));
         }
+
         pbRef->set_private_(ref.privateReference);
         pbRef->set_type(serializeReferenceTypeToPb(ref.referenceType));
     }
index 70a33f7..dd995d8 100644 (file)
@@ -62,6 +62,17 @@ TEST(TableProtoSerializer, SerializeSinglePackage) {
                                        test::buildPrimitive(android::Res_value::TYPE_INT_DEC, 321u),
                                        context->getDiagnostics()));
 
+    // Make a reference with both resource name and resource ID.
+    // The reference should point to a resource outside of this table to test that both
+    // name and id get serialized.
+    Reference expectedRef;
+    expectedRef.name = test::parseNameOrDie(u"@android:layout/main");
+    expectedRef.id = ResourceId(0x01020000);
+    ASSERT_TRUE(table->addResource(test::parseNameOrDie(u"@com.app.a:layout/abc"),
+                                   ConfigDescription::defaultConfig(), std::string(),
+                                   util::make_unique<Reference>(expectedRef),
+                                   context->getDiagnostics()));
+
     std::unique_ptr<pb::ResourceTable> pbTable = serializeTableToPb(table.get());
     ASSERT_NE(nullptr, pbTable);
 
@@ -90,6 +101,13 @@ TEST(TableProtoSerializer, SerializeSinglePackage) {
             newTable.get(), u"@com.app.a:integer/one", test::parseConfigOrDie("land"), "tablet");
     ASSERT_NE(nullptr, prim);
     EXPECT_EQ(321u, prim->value.data);
+
+    Reference* actualRef = test::getValue<Reference>(newTable.get(), u"@com.app.a:layout/abc");
+    ASSERT_NE(nullptr, actualRef);
+    AAPT_ASSERT_TRUE(actualRef->name);
+    AAPT_ASSERT_TRUE(actualRef->id);
+    EXPECT_EQ(expectedRef.name.value(), actualRef->name.value());
+    EXPECT_EQ(expectedRef.id.value(), actualRef->id.value());
 }
 
 TEST(TableProtoSerializer, SerializeFileHeader) {
@@ -130,4 +148,27 @@ TEST(TableProtoSerializer, SerializeFileHeader) {
     EXPECT_EQ(test::parseNameOrDie(u"@+id/unchecked"), file->exportedSymbols[0].name);
 }
 
+TEST(TableProtoSerializer, DeserializeCorruptHeaderSafely) {
+    ResourceFile f;
+    std::unique_ptr<pb::CompiledFile> pbFile = serializeCompiledFileToPb(f);
+
+    const std::string expectedData = "1234";
+
+    std::string outputStr;
+    {
+        google::protobuf::io::StringOutputStream outStream(&outputStr);
+        CompiledFileOutputStream outFileStream(&outStream, pbFile.get());
+
+        ASSERT_TRUE(outFileStream.Write(expectedData.data(), expectedData.size()));
+        ASSERT_TRUE(outFileStream.Finish());
+    }
+
+    outputStr[0] = 0xff;
+
+    CompiledFileInputStream inFileStream(outputStr.data(), outputStr.size());
+    EXPECT_EQ(nullptr, inFileStream.CompiledFile());
+    EXPECT_EQ(nullptr, inFileStream.data());
+    EXPECT_EQ(0u, inFileStream.size());
+}
+
 } // namespace aapt
index 834caf8..8c56ebc 100644 (file)
@@ -246,7 +246,7 @@ inline std::unique_ptr<xml::XmlResource> buildXmlDom(const StringPiece& str) {
 inline std::unique_ptr<xml::XmlResource> buildXmlDomForPackageName(IAaptContext* context,
                                                                    const StringPiece& str) {
     std::unique_ptr<xml::XmlResource> doc = buildXmlDom(str);
-    doc->file.name.package = context->getCompilationPackage().toString();
+    doc->file.name.package = context->getCompilationPackage();
     return doc;
 }
 
index e540cd7..96752d3 100644 (file)
@@ -31,33 +31,16 @@ namespace aapt {
 namespace test {
 
 class Context : public IAaptContext {
-private:
-    friend class ContextBuilder;
-
-    Context() = default;
-
-    Maybe<std::u16string> mCompilationPackage;
-    Maybe<uint8_t> mPackageId;
-    std::unique_ptr<IDiagnostics> mDiagnostics = util::make_unique<StdErrDiagnostics>();
-    std::unique_ptr<ISymbolTable> mSymbols;
-    std::unique_ptr<NameMangler> mNameMangler;
-
 public:
-    ISymbolTable* getExternalSymbols() override {
-        assert(mSymbols && "test symbols not set");
-        return mSymbols.get();
-    }
-
-    void setSymbolTable(std::unique_ptr<ISymbolTable> symbols) {
-        mSymbols = std::move(symbols);
+    SymbolTable* getExternalSymbols() override {
+        return &mSymbols;
     }
 
     IDiagnostics* getDiagnostics() override {
-        assert(mDiagnostics && "test diagnostics not set");
-        return mDiagnostics.get();
+        return &mDiagnostics;
     }
 
-    StringPiece16 getCompilationPackage() override {
+    const std::u16string& getCompilationPackage() override {
         assert(mCompilationPackage && "package name not set");
         return mCompilationPackage.value();
     }
@@ -68,13 +51,24 @@ public:
     }
 
     NameMangler* getNameMangler() override {
-        assert(mNameMangler && "test name mangler not set");
-        return mNameMangler.get();
+        return &mNameMangler;
     }
 
     bool verbose() override {
         return false;
     }
+
+private:
+    friend class ContextBuilder;
+
+    Context() : mNameMangler({}) {
+    }
+
+    Maybe<std::u16string> mCompilationPackage;
+    Maybe<uint8_t> mPackageId;
+    StdErrDiagnostics mDiagnostics;
+    SymbolTable mSymbols;
+    NameMangler mNameMangler;
 };
 
 class ContextBuilder {
@@ -92,18 +86,13 @@ public:
         return *this;
     }
 
-    ContextBuilder& setSymbolTable(std::unique_ptr<ISymbolTable> symbols) {
-        mContext->mSymbols = std::move(symbols);
+    ContextBuilder& setNameManglerPolicy(NameManglerPolicy policy) {
+        mContext->mNameMangler = NameMangler(policy);
         return *this;
     }
 
-    ContextBuilder& setDiagnostics(std::unique_ptr<IDiagnostics> diag) {
-        mContext->mDiagnostics = std::move(diag);
-        return *this;
-    }
-
-    ContextBuilder& setNameManglerPolicy(NameManglerPolicy policy) {
-        mContext->mNameMangler = util::make_unique<NameMangler>(policy);
+    ContextBuilder& addSymbolSource(std::unique_ptr<ISymbolSource> src) {
+        mContext->getExternalSymbols()->appendSource(std::move(src));
         return *this;
     }
 
@@ -112,57 +101,72 @@ public:
     }
 };
 
-class StaticSymbolTableBuilder {
+class StaticSymbolSourceBuilder {
+public:
+    StaticSymbolSourceBuilder& addPublicSymbol(const StringPiece16& name, ResourceId id,
+                                               std::unique_ptr<Attribute> attr = {}) {
+        std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>(
+                id, std::move(attr), true);
+        mSymbolSource->mNameMap[parseNameOrDie(name)] = symbol.get();
+        mSymbolSource->mIdMap[id] = symbol.get();
+        mSymbolSource->mSymbols.push_back(std::move(symbol));
+        return *this;
+    }
+
+    StaticSymbolSourceBuilder& addSymbol(const StringPiece16& name, ResourceId id,
+                                         std::unique_ptr<Attribute> attr = {}) {
+        std::unique_ptr<SymbolTable::Symbol> symbol = util::make_unique<SymbolTable::Symbol>(
+                id, std::move(attr), false);
+        mSymbolSource->mNameMap[parseNameOrDie(name)] = symbol.get();
+        mSymbolSource->mIdMap[id] = symbol.get();
+        mSymbolSource->mSymbols.push_back(std::move(symbol));
+        return *this;
+    }
+
+    std::unique_ptr<ISymbolSource> build() {
+        return std::move(mSymbolSource);
+    }
+
 private:
-    struct SymbolTable : public ISymbolTable {
-        std::list<std::unique_ptr<Symbol>> mSymbols;
-        std::map<ResourceName, Symbol*> mNameMap;
-        std::map<ResourceId, Symbol*> mIdMap;
+    class StaticSymbolSource : public ISymbolSource {
+    public:
+        StaticSymbolSource() = default;
 
-        const Symbol* findByName(const ResourceName& name) override {
+        std::unique_ptr<SymbolTable::Symbol> findByName(const ResourceName& name) override {
             auto iter = mNameMap.find(name);
             if (iter != mNameMap.end()) {
-                return iter->second;
+                return cloneSymbol(iter->second);
             }
             return nullptr;
         }
 
-        const Symbol* findById(ResourceId id) override {
+        std::unique_ptr<SymbolTable::Symbol> findById(ResourceId id) override {
             auto iter = mIdMap.find(id);
             if (iter != mIdMap.end()) {
-                return iter->second;
+                return cloneSymbol(iter->second);
             }
             return nullptr;
         }
-    };
 
-    std::unique_ptr<SymbolTable> mSymbolTable = util::make_unique<SymbolTable>();
+        std::list<std::unique_ptr<SymbolTable::Symbol>> mSymbols;
+        std::map<ResourceName, SymbolTable::Symbol*> mNameMap;
+        std::map<ResourceId, SymbolTable::Symbol*> mIdMap;
 
-public:
-    StaticSymbolTableBuilder& addPublicSymbol(const StringPiece16& name, ResourceId id,
-                                              std::unique_ptr<Attribute> attr = {}) {
-        std::unique_ptr<ISymbolTable::Symbol> symbol = util::make_unique<ISymbolTable::Symbol>(
-                id, std::move(attr));
-        symbol->isPublic = true;
-        mSymbolTable->mNameMap[parseNameOrDie(name)] = symbol.get();
-        mSymbolTable->mIdMap[id] = symbol.get();
-        mSymbolTable->mSymbols.push_back(std::move(symbol));
-        return *this;
-    }
+    private:
+        std::unique_ptr<SymbolTable::Symbol> cloneSymbol(SymbolTable::Symbol* sym) {
+            std::unique_ptr<SymbolTable::Symbol> clone = util::make_unique<SymbolTable::Symbol>();
+            clone->id = sym->id;
+            if (sym->attribute) {
+                clone->attribute = std::unique_ptr<Attribute>(sym->attribute->clone(nullptr));
+            }
+            clone->isPublic = sym->isPublic;
+            return clone;
+        }
 
-    StaticSymbolTableBuilder& addSymbol(const StringPiece16& name, ResourceId id,
-                                        std::unique_ptr<Attribute> attr = {}) {
-        std::unique_ptr<ISymbolTable::Symbol> symbol = util::make_unique<ISymbolTable::Symbol>(
-                id, std::move(attr));
-        mSymbolTable->mNameMap[parseNameOrDie(name)] = symbol.get();
-        mSymbolTable->mIdMap[id] = symbol.get();
-        mSymbolTable->mSymbols.push_back(std::move(symbol));
-        return *this;
-    }
+        DISALLOW_COPY_AND_ASSIGN(StaticSymbolSource);
+    };
 
-    std::unique_ptr<ISymbolTable> build() {
-        return std::move(mSymbolTable);
-    }
+    std::unique_ptr<StaticSymbolSource> mSymbolSource = util::make_unique<StaticSymbolSource>();
 };
 
 } // namespace test
similarity index 64%
rename from core/java/android/hardware/camera2/CaptureRequest.aidl
rename to tools/aapt2/test/Test.h
index 0b7d5ba..d4845cf 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.
  * limitations under the License.
  */
 
-package android.hardware.camera2;
+#ifndef AAPT_TEST_TEST_H
+#define AAPT_TEST_TEST_H
 
-/** @hide */
-parcelable CaptureRequest;
+#include "test/Builders.h"
+#include "test/Common.h"
+#include "test/Context.h"
+
+#include <gtest/gtest.h>
+
+namespace aapt {
+namespace test {
+
+} // namespace test
+} // namespace aapt
+
+#endif // AAPT_TEST_TEST_H
index 033b0a4..b374d20 100644 (file)
@@ -68,7 +68,7 @@ struct Namespace : public BaseNode<Namespace> {
 };
 
 struct AaptAttribute {
-    ResourceId id;
+    Maybe<ResourceId> id;
     aapt::Attribute attribute;
 };
 
index df76bc9..a8a8c5c 100644 (file)
@@ -264,6 +264,9 @@ def verify_constants(clazz):
         if "static" in f.split and "final" in f.split:
             if re.match("[A-Z0-9_]+", f.name) is None:
                 error(clazz, f, "C2", "Constant field names must be FOO_NAME")
+            elif f.typ != "java.lang.String":
+                if f.name.startswith("MIN_") or f.name.startswith("MAX_"):
+                    warn(clazz, f, "C8", "If min/max could change in future, make them dynamic methods")
 
 
 def verify_enums(clazz):
@@ -417,6 +420,9 @@ def verify_parcelable(clazz):
         if len(creator) == 0 or len(write) == 0 or len(describe) == 0:
             error(clazz, None, "FW3", "Parcelable requires CREATOR, writeToParcel, and describeContents; missing one")
 
+        if " final class " not in clazz.raw:
+            error(clazz, None, "FW8", "Parcelable classes must be final")
+
 
 def verify_protected(clazz):
     """Verify that no protected methods or fields are allowed."""
@@ -730,6 +736,13 @@ def verify_exception(clazz):
         if "throws java.lang.Exception" in m.raw or "throws java.lang.Throwable" in m.raw or "throws java.lang.Error" in m.raw:
             error(clazz, m, "S1", "Methods must not throw generic exceptions")
 
+        if "throws android.os.RemoteException" in m.raw:
+            if clazz.name == "android.content.ContentProviderClient": continue
+            if clazz.name == "android.os.Binder": continue
+            if clazz.name == "android.os.IBinder": continue
+
+            error(clazz, m, "FW9", "Methods calling into system server should rethrow RemoteException as RuntimeException")
+
 
 def verify_google(clazz):
     """Verifies that APIs never reference Google."""
@@ -946,6 +959,27 @@ def verify_resource_names(clazz):
             error(clazz, f, "C7", "Expected resource name in this class to be FooBar_Baz style")
 
 
+def verify_files(clazz):
+    """Verifies that methods accepting File also accept streams."""
+
+    has_file = set()
+    has_stream = set()
+
+    test = []
+    test.extend(clazz.ctors)
+    test.extend(clazz.methods)
+
+    for m in test:
+        if "java.io.File" in m.args:
+            has_file.add(m)
+        if "java.io.FileDescriptor" in m.args or "android.os.ParcelFileDescriptor" in m.args or "java.io.InputStream" in m.args or "java.io.OutputStream" in m.args:
+            has_stream.add(m.name)
+
+    for m in has_file:
+        if m.name not in has_stream:
+            warn(clazz, m, "M10", "Methods accepting File should also accept FileDescriptor or streams")
+
+
 def examine_clazz(clazz):
     """Find all style issues in the given class."""
     if clazz.pkg.name.startswith("java"): return
@@ -954,6 +988,7 @@ def examine_clazz(clazz):
     if clazz.pkg.name.startswith("org.xml"): return
     if clazz.pkg.name.startswith("org.json"): return
     if clazz.pkg.name.startswith("org.w3c"): return
+    if clazz.pkg.name.startswith("android.icu."): return
 
     verify_constants(clazz)
     verify_enums(clazz)
@@ -989,6 +1024,7 @@ def examine_clazz(clazz):
     verify_context_first(clazz)
     verify_listener_last(clazz)
     verify_resource_names(clazz)
+    verify_files(clazz)
 
 
 def examine_stream(stream):
diff --git a/tools/layoutlib/.idea/libraries/junit.xml b/tools/layoutlib/.idea/libraries/junit.xml
new file mode 100644 (file)
index 0000000..c889f5f
--- /dev/null
@@ -0,0 +1,11 @@
+<component name="libraryTable">
+  <library name="junit">
+    <CLASSES>
+      <root url="jar://$PROJECT_DIR$/../../../../out/host/common/obj/JAVA_LIBRARIES/junit_intermediates/javalib.jar!/" />
+    </CLASSES>
+    <JAVADOC />
+    <SOURCES>
+      <root url="file://$PROJECT_DIR$/../../../../external/junit/src" />
+    </SOURCES>
+  </library>
+</component>
\ No newline at end of file
index 58f057a..fb798b6 100644 (file)
@@ -2,7 +2,7 @@
   <configuration default="false" name="Create" type="Application" factoryName="Application" singleton="true">
     <extension name="coverage" enabled="false" merge="false" sample_coverage="true" runner="idea" />
     <option name="MAIN_CLASS_NAME" value="com.android.tools.layoutlib.create.Main" />
-    <option name="VM_PARAMETERS" value="" />
+    <option name="VM_PARAMETERS" value="-ea" />
     <option name="PROGRAM_PARAMETERS" value="out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar out/target/common/obj/JAVA_LIBRARIES/core-libart_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/framework_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/icu4j-icudata-jarjar_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/icu4j-icutzdata-jarjar_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/classes.jar out/target/common/obj/JAVA_LIBRARIES/ext_intermediates/javalib.jar" />
     <option name="WORKING_DIRECTORY" value="file://$PROJECT_DIR$/../../../../" />
     <option name="ALTERNATIVE_JRE_PATH_ENABLED" value="false" />
index c2ad9ef..663e1e2 100644 (file)
@@ -40,10 +40,8 @@ built_ext_dep := $(call java-lib-deps,ext)
 built_ext_classes := $(call java-lib-files,ext)
 built_ext_data := $(call intermediates-dir-for, \
                        JAVA_LIBRARIES,ext,,COMMON)/javalib.jar
-built_icudata_dep := $(call java-lib-deps,icu4j-icudata-jarjar)
-built_icudata_data := $(call java-lib-files,icu4j-icudata-jarjar)
-built_icutzdata_dep := $(call java-lib-deps,icu4j-icutzdata-jarjar)
-built_icutzdata_data := $(call java-lib-files,icu4j-icutzdata-jarjar)
+built_icudata_dep := $(call java-lib-deps,icu4j-icudata-host-jarjar,HOST)
+built_icutzdata_dep := $(call java-lib-deps,icu4j-icutzdata-host-jarjar,HOST)
 
 built_layoutlib_create_jar := $(call intermediates-dir-for, \
                        JAVA_LIBRARIES,layoutlib_create,HOST)/javalib.jar
@@ -77,8 +75,8 @@ $(LOCAL_BUILT_MODULE): $(built_oj_dep) \
                     $(built_core_classes) \
                     $(built_framework_classes) \
                     $(built_ext_classes) \
-                    $(built_icudata_data) \
-                    $(built_icutzdata_data) \
+                    $(built_icudata_dep) \
+                    $(built_icutzdata_dep) \
                     $(built_ext_data)
        $(hide) ls -l $(built_framework_classes)
 
index ccc10b3..57d08cb 100644 (file)
@@ -84,6 +84,6 @@
         </SOURCES>
       </library>
     </orderEntry>
-    <orderEntry type="library" scope="TEST" name="JUnit4" level="application" />
+    <orderEntry type="library" scope="TEST" name="junit" level="project" />
   </component>
 </module>
\ No newline at end of file
index db4c6dc..ae42ba6 100644 (file)
@@ -305,6 +305,12 @@ public final class BridgeTypedArray extends TypedArray {
         return defValue;
     }
 
+    @Override
+    public ComplexColor getComplexColor(int index) {
+        // TODO: Support GradientColor
+        return getColorStateList(index);
+    }
+
     /**
      * Retrieve the ColorStateList for the attribute at <var>index</var>.
      * The value may be either a single solid color or a reference to
index c4fbd56..fa880f0 100644 (file)
@@ -142,7 +142,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setBitmap(long canvas, Bitmap bitmap) {
+    public static void native_setBitmap(long canvas, Bitmap bitmap) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
         Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
         if (canvasDelegate == null || bitmapDelegate==null) {
@@ -153,7 +153,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_isOpaque(long nativeCanvas) {
+    public static boolean native_isOpaque(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -164,10 +164,10 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setHighContrastText(long nativeCanvas, boolean highContrastText){}
+    public static void native_setHighContrastText(long nativeCanvas, boolean highContrastText){}
 
     @LayoutlibDelegate
-    /*package*/ static int native_getWidth(long nativeCanvas) {
+    public static int native_getWidth(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -178,7 +178,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_getHeight(long nativeCanvas) {
+    public static int native_getHeight(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -189,7 +189,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_save(long nativeCanvas, int saveFlags) {
+    public static int native_save(long nativeCanvas, int saveFlags) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -200,7 +200,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_saveLayer(long nativeCanvas, float l,
+    public static int native_saveLayer(long nativeCanvas, float l,
                                                float t, float r, float b,
                                                long paint, int layerFlags) {
         // get the delegate from the native int.
@@ -219,7 +219,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_saveLayerAlpha(long nativeCanvas, float l,
+    public static int native_saveLayerAlpha(long nativeCanvas, float l,
                                                     float t, float r, float b,
                                                     int alpha, int layerFlags) {
         // get the delegate from the native int.
@@ -232,7 +232,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_restore(long nativeCanvas, boolean throwOnUnderflow) {
+    public static void native_restore(long nativeCanvas, boolean throwOnUnderflow) {
         // FIXME: implement throwOnUnderflow.
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -244,7 +244,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_restoreToCount(long nativeCanvas, int saveCount,
+    public static void native_restoreToCount(long nativeCanvas, int saveCount,
             boolean throwOnUnderflow) {
         // FIXME: implement throwOnUnderflow.
         // get the delegate from the native int.
@@ -257,7 +257,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static int native_getSaveCount(long nativeCanvas) {
+    public static int native_getSaveCount(long nativeCanvas) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -268,7 +268,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-   /*package*/ static void native_translate(long nativeCanvas, float dx, float dy) {
+   public static void native_translate(long nativeCanvas, float dx, float dy) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -279,7 +279,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-       /*package*/ static void native_scale(long nativeCanvas, float sx, float sy) {
+       public static void native_scale(long nativeCanvas, float sx, float sy) {
             // get the delegate from the native int.
             Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
             if (canvasDelegate == null) {
@@ -290,7 +290,7 @@ public final class Canvas_Delegate {
         }
 
     @LayoutlibDelegate
-    /*package*/ static void native_rotate(long nativeCanvas, float degrees) {
+    public static void native_rotate(long nativeCanvas, float degrees) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -301,7 +301,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-   /*package*/ static void native_skew(long nativeCanvas, float kx, float ky) {
+   public static void native_skew(long nativeCanvas, float kx, float ky) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -325,7 +325,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_concat(long nCanvas, long nMatrix) {
+    public static void native_concat(long nCanvas, long nMatrix) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
@@ -353,7 +353,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_setMatrix(long nCanvas, long nMatrix) {
+    public static void native_setMatrix(long nCanvas, long nMatrix) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
         if (canvasDelegate == null) {
@@ -383,7 +383,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_clipRect(long nCanvas,
+    public static boolean native_clipRect(long nCanvas,
                                                   float left, float top,
                                                   float right, float bottom,
                                                   int regionOp) {
@@ -397,7 +397,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_clipPath(long nativeCanvas,
+    public static boolean native_clipPath(long nativeCanvas,
                                                   long nativePath,
                                                   int regionOp) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -414,7 +414,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_clipRegion(long nativeCanvas,
+    public static boolean native_clipRegion(long nativeCanvas,
                                                     long nativeRegion,
                                                     int regionOp) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -431,7 +431,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) {
+    public static void nativeSetDrawFilter(long nativeCanvas, long nativeFilter) {
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
             return;
@@ -446,7 +446,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_getClipBounds(long nativeCanvas,
+    public static boolean native_getClipBounds(long nativeCanvas,
                                                        Rect bounds) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -467,7 +467,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_getCTM(long canvas, long matrix) {
+    public static void native_getCTM(long canvas, long matrix) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
         if (canvasDelegate == null) {
@@ -484,13 +484,13 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_quickReject(long nativeCanvas, long path) {
+    public static boolean native_quickReject(long nativeCanvas, long path) {
         // FIXME properly implement quickReject
         return false;
     }
 
     @LayoutlibDelegate
-    /*package*/ static boolean native_quickReject(long nativeCanvas,
+    public static boolean native_quickReject(long nativeCanvas,
                                                      float left, float top,
                                                      float right, float bottom) {
         // FIXME properly implement quickReject
@@ -498,7 +498,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawColor(long nativeCanvas, final int color, final int mode) {
+    public static void native_drawColor(long nativeCanvas, final int color, final int mode) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
         if (canvasDelegate == null) {
@@ -529,14 +529,14 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawPaint(long nativeCanvas, long paint) {
+    public static void native_drawPaint(long nativeCanvas, long paint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
                 "Canvas.drawPaint is not supported.", null, null /*data*/);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawPoint(long nativeCanvas, float x, float y,
+    public static void native_drawPoint(long nativeCanvas, float x, float y,
             long nativePaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -544,7 +544,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count,
+    public static void native_drawPoints(long nativeCanvas, float[] pts, int offset, int count,
             long nativePaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -552,7 +552,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawLine(long nativeCanvas,
+    public static void native_drawLine(long nativeCanvas,
             final float startX, final float startY, final float stopX, final float stopY,
             long paint) {
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -565,7 +565,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawLines(long nativeCanvas,
+    public static void native_drawLines(long nativeCanvas,
             final float[] pts, final int offset, final int count,
             long nativePaint) {
         draw(nativeCanvas, nativePaint, false /*compositeOnly*/,
@@ -581,7 +581,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawRect(long nativeCanvas,
+    public static void native_drawRect(long nativeCanvas,
             final float left, final float top, final float right, final float bottom, long paint) {
 
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -607,7 +607,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawOval(long nativeCanvas, final float left,
+    public static void native_drawOval(long nativeCanvas, final float left,
             final float top, final float right, final float bottom, long paint) {
         if (right > left && bottom > top) {
             draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -634,7 +634,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawCircle(long nativeCanvas,
+    public static void native_drawCircle(long nativeCanvas,
             float cx, float cy, float radius, long paint) {
         native_drawOval(nativeCanvas,
                 cx - radius, cy - radius, cx + radius, cy + radius,
@@ -642,7 +642,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawArc(long nativeCanvas,
+    public static void native_drawArc(long nativeCanvas,
             final float left, final float top, final float right, final float bottom,
             final float startAngle, final float sweep,
             final boolean useCenter, long paint) {
@@ -674,7 +674,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawRoundRect(long nativeCanvas,
+    public static void native_drawRoundRect(long nativeCanvas,
             final float left, final float top, final float right, final float bottom,
             final float rx, final float ry, long paint) {
         draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -704,7 +704,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawPath(long nativeCanvas, long path, long paint) {
+    public static void native_drawPath(long nativeCanvas, long path, long paint) {
         final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
         if (pathDelegate == null) {
             return;
@@ -756,7 +756,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawRegion(long nativeCanvas, long nativeRegion,
+    public static void native_drawRegion(long nativeCanvas, long nativeRegion,
             long nativePaint) {
         // FIXME
         Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
@@ -764,7 +764,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawNinePatch(Canvas thisCanvas, long nativeCanvas,
+    public static void native_drawNinePatch(Canvas thisCanvas, long nativeCanvas,
             long nativeBitmap, long ninePatch, final float dstLeft, final float dstTop,
             final float dstRight, final float dstBottom, long nativePaintOrZero,
             final int screenDensity, final int bitmapDensity) {
@@ -811,7 +811,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
+    public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
                                                  float left, float top,
                                                  long nativePaintOrZero,
                                                  int canvasDensity,
@@ -833,7 +833,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
+    public static void native_drawBitmap(Canvas thisCanvas, long nativeCanvas, Bitmap bitmap,
                                  float srcLeft, float srcTop, float srcRight, float srcBottom,
                                  float dstLeft, float dstTop, float dstRight, float dstBottom,
                                  long nativePaintOrZero, int screenDensity, int bitmapDensity) {
@@ -849,7 +849,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawBitmap(long nativeCanvas, int[] colors,
+    public static void native_drawBitmap(long nativeCanvas, int[] colors,
                                                 int offset, int stride, final float x,
                                                  final float y, int width, int height,
                                                  boolean hasAlpha,
@@ -874,7 +874,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeDrawBitmapMatrix(long nCanvas, Bitmap bitmap,
+    public static void nativeDrawBitmapMatrix(long nCanvas, Bitmap bitmap,
                                                       long nMatrix, long nPaint) {
         // get the delegate from the native int.
         Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
@@ -915,7 +915,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeDrawBitmapMesh(long nCanvas, Bitmap bitmap,
+    public static void nativeDrawBitmapMesh(long nCanvas, Bitmap bitmap,
             int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors,
             int colorOffset, long nPaint) {
         // FIXME
@@ -924,7 +924,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void nativeDrawVertices(long nCanvas, int mode, int n,
+    public static void nativeDrawVertices(long nCanvas, int mode, int n,
             float[] verts, int vertOffset,
             float[] texs, int texOffset,
             int[] colors, int colorOffset,
@@ -936,14 +936,14 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawText(long nativeCanvas, char[] text, int index, int count,
+    public static void native_drawText(long nativeCanvas, char[] text, int index, int count,
             float startX, float startY, int flags, long paint, long typeface) {
         drawText(nativeCanvas, text, index, count, startX, startY, (flags & 1) != 0,
                 paint, typeface);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawText(long nativeCanvas, String text,
+    public static void native_drawText(long nativeCanvas, String text,
             int start, int end, float x, float y, final int flags, long paint,
             long typeface) {
         int count = end - start;
@@ -954,7 +954,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawTextRun(long nativeCanvas, String text,
+    public static void native_drawTextRun(long nativeCanvas, String text,
             int start, int end, int contextStart, int contextEnd,
             float x, float y, boolean isRtl, long paint, long typeface) {
         int count = end - start;
@@ -965,14 +965,14 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawTextRun(long nativeCanvas, char[] text,
+    public static void native_drawTextRun(long nativeCanvas, char[] text,
             int start, int count, int contextStart, int contextCount,
             float x, float y, boolean isRtl, long paint, long typeface) {
         drawText(nativeCanvas, text, start, count, x, y, isRtl, paint, typeface);
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawTextOnPath(long nativeCanvas,
+    public static void native_drawTextOnPath(long nativeCanvas,
                                                      char[] text, int index,
                                                      int count, long path,
                                                      float hOffset,
@@ -984,7 +984,7 @@ public final class Canvas_Delegate {
     }
 
     @LayoutlibDelegate
-    /*package*/ static void native_drawTextOnPath(long nativeCanvas,
+    public static void native_drawTextOnPath(long nativeCanvas,
                                                      String text, long path,
                                                      float hOffset,
                                                      float vOffset,
index 514d785..839c182 100644 (file)
@@ -223,6 +223,10 @@ public class Paint_Delegate {
         return mColorFilter;
     }
 
+    public void setColorFilter(long colorFilterPtr) {
+        mColorFilter = ColorFilter_Delegate.getDelegate(colorFilterPtr);
+    }
+
     /**
      * Returns the {@link Shader} delegate or null if none have been set
      *
index e1da27b..08f0cb4 100644 (file)
@@ -572,7 +572,7 @@ public final class Path_Delegate {
         return null;
     }
 
-    private static void addPath(long destPath, long srcPath, AffineTransform transform) {
+    public static void addPath(long destPath, long srcPath, AffineTransform transform) {
         Path_Delegate destPathDelegate = sManager.getDelegate(destPath);
         if (destPathDelegate == null) {
             return;
@@ -630,7 +630,7 @@ public final class Path_Delegate {
      * Fills the given {@link RectF} with the path bounds.
      * @param bounds the RectF to be filled.
      */
-    private void fillBounds(RectF bounds) {
+    public void fillBounds(RectF bounds) {
         Rectangle2D rect = mPath.getBounds2D();
         bounds.left = (float)rect.getMinX();
         bounds.right = (float)rect.getMaxX();
@@ -644,7 +644,7 @@ public final class Path_Delegate {
      * @param x The x-coordinate of the start of a new contour
      * @param y The y-coordinate of the start of a new contour
      */
-    private void moveTo(float x, float y) {
+    public void moveTo(float x, float y) {
         mPath.moveTo(mLastX = x, mLastY = y);
     }
 
@@ -658,7 +658,7 @@ public final class Path_Delegate {
      * @param dy The amount to add to the y-coordinate of the end of the
      *           previous contour, to specify the start of a new contour
      */
-    private void rMoveTo(float dx, float dy) {
+    public void rMoveTo(float dx, float dy) {
         dx += mLastX;
         dy += mLastY;
         mPath.moveTo(mLastX = dx, mLastY = dy);
@@ -672,7 +672,7 @@ public final class Path_Delegate {
      * @param x The x-coordinate of the end of a line
      * @param y The y-coordinate of the end of a line
      */
-    private void lineTo(float x, float y) {
+    public void lineTo(float x, float y) {
         if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
         }
@@ -689,7 +689,7 @@ public final class Path_Delegate {
      * @param dy The amount to add to the y-coordinate of the previous point on
      *           this contour, to specify a line
      */
-    private void rLineTo(float dx, float dy) {
+    public void rLineTo(float dx, float dy) {
         if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
         }
@@ -714,7 +714,7 @@ public final class Path_Delegate {
      * @param x2 The x-coordinate of the end point on a quadratic curve
      * @param y2 The y-coordinate of the end point on a quadratic curve
      */
-    private void quadTo(float x1, float y1, float x2, float y2) {
+    public void quadTo(float x1, float y1, float x2, float y2) {
         mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2);
     }
 
@@ -732,7 +732,7 @@ public final class Path_Delegate {
      * @param dy2 The amount to add to the y-coordinate of the last point on
      *            this contour, for the end point of a quadratic curve
      */
-    private void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
+    public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
         if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
         }
@@ -755,7 +755,7 @@ public final class Path_Delegate {
      * @param x3 The x-coordinate of the end point on a cubic curve
      * @param y3 The y-coordinate of the end point on a cubic curve
      */
-    private void cubicTo(float x1, float y1, float x2, float y2,
+    public void cubicTo(float x1, float y1, float x2, float y2,
                         float x3, float y3) {
         if (!hasPoints()) {
             mPath.moveTo(0, 0);
@@ -768,7 +768,7 @@ public final class Path_Delegate {
      * current point on this contour. If there is no previous point, then a
      * moveTo(0,0) is inserted automatically.
      */
-    private void rCubicTo(float dx1, float dy1, float dx2, float dy2,
+    public void rCubicTo(float dx1, float dy1, float dx2, float dy2,
                          float dx3, float dy3) {
         if (!hasPoints()) {
             mPath.moveTo(mLastX = 0, mLastY = 0);
@@ -798,7 +798,7 @@ public final class Path_Delegate {
      *                    mod 360.
      * @param forceMoveTo If true, always begin a new contour with the arc
      */
-    private void arcTo(float left, float top, float right, float bottom, float startAngle,
+    public void arcTo(float left, float top, float right, float bottom, float startAngle,
             float sweepAngle,
             boolean forceMoveTo) {
         Arc2D arc = new Arc2D.Float(left, top, right - left, bottom - top, -startAngle,
@@ -812,7 +812,7 @@ public final class Path_Delegate {
      * Close the current contour. If the current point is not equal to the
      * first point of the contour, a line segment is automatically added.
      */
-    private void close() {
+    public void close() {
         mPath.closePath();
     }
 
@@ -831,7 +831,7 @@ public final class Path_Delegate {
      * @param bottom The bottom of a rectangle to add to the path
      * @param dir    The direction to wind the rectangle's contour
      */
-    private void addRect(float left, float top, float right, float bottom,
+    public void addRect(float left, float top, float right, float bottom,
                         int dir) {
         moveTo(left, top);
 
diff --git a/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/drawable/VectorDrawable_Delegate.java
new file mode 100644 (file)
index 0000000..eef8235
--- /dev/null
@@ -0,0 +1,1122 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics.drawable;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas_Delegate;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Cap;
+import android.graphics.Paint.Join;
+import android.graphics.Paint_Delegate;
+import android.graphics.Path;
+import android.graphics.PathMeasure;
+import android.graphics.Path_Delegate;
+import android.graphics.Rect;
+import android.graphics.Region.Op;
+import android.util.ArrayMap;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.MathUtils;
+import android.util.PathParser_Delegate;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.FloatBuffer;
+import java.util.ArrayList;
+
+import static android.graphics.Canvas.CLIP_SAVE_FLAG;
+import static android.graphics.Canvas.MATRIX_SAVE_FLAG;
+import static android.graphics.Paint.Cap.BUTT;
+import static android.graphics.Paint.Cap.ROUND;
+import static android.graphics.Paint.Cap.SQUARE;
+import static android.graphics.Paint.Join.BEVEL;
+import static android.graphics.Paint.Join.MITER;
+import static android.graphics.Paint.Style;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link VectorDrawable}
+ * <p>
+ * Through the layoutlib_create tool, the original  methods of VectorDrawable have been replaced by
+ * calls to methods of the same name in this delegate class.
+ */
+@SuppressWarnings("unused")
+public class VectorDrawable_Delegate {
+    private static final String LOGTAG = VectorDrawable_Delegate.class.getSimpleName();
+    private static final boolean DBG_VECTOR_DRAWABLE = false;
+
+    private static final DelegateManager<VNativeObject> sPathManager =
+            new DelegateManager<>(VNativeObject.class);
+
+    private static <T> T getDelegate(long nativePtr) {
+        //noinspection unchecked
+        T object = (T) sPathManager.getDelegate(nativePtr);
+        assert object != null;
+
+        return object;
+    }
+
+    /**
+     * Obtains styled attributes from the theme, if available, or unstyled resources if the theme is
+     * null.
+     */
+    private static TypedArray obtainAttributes(
+            Resources res, Theme theme, AttributeSet set, int[] attrs) {
+        if (theme == null) {
+            return res.obtainAttributes(set, attrs);
+        }
+        return theme.obtainStyledAttributes(set, attrs, 0, 0);
+    }
+
+    private static int applyAlpha(int color, float alpha) {
+        int alphaBytes = Color.alpha(color);
+        color &= 0x00FFFFFF;
+        color |= ((int) (alphaBytes * alpha)) << 24;
+        return color;
+    }
+
+    @LayoutlibDelegate
+    static long nCreateRenderer(long rootGroupPtr) {
+        VGroup_Delegate rootGroup = getDelegate(rootGroupPtr);
+        return sPathManager.addNewDelegate(new VPathRenderer_Delegate(rootGroup));
+    }
+
+    @LayoutlibDelegate
+    static void nSetRendererViewportSize(long rendererPtr, float viewportWidth,
+            float viewportHeight) {
+        VPathRenderer_Delegate nativePathRenderer = getDelegate(rendererPtr);
+        nativePathRenderer.mViewportWidth = viewportWidth;
+        nativePathRenderer.mViewportHeight = viewportHeight;
+    }
+
+    @LayoutlibDelegate
+    static boolean nSetRootAlpha(long rendererPtr, float alpha) {
+        VPathRenderer_Delegate nativePathRenderer = getDelegate(rendererPtr);
+        nativePathRenderer.setRootAlpha(alpha);
+
+        return true;
+    }
+
+    @LayoutlibDelegate
+    static float nGetRootAlpha(long rendererPtr) {
+        VPathRenderer_Delegate nativePathRenderer = getDelegate(rendererPtr);
+
+        return nativePathRenderer.getRootAlpha();
+    }
+
+    @LayoutlibDelegate
+    static void nSetAllowCaching(long rendererPtr, boolean allowCaching) {
+        // ignored
+    }
+
+    @LayoutlibDelegate
+    static void nDraw(long rendererPtr, long canvasWrapperPtr,
+            long colorFilterPtr, Rect bounds, boolean needsMirroring, boolean canReuseCache) {
+        VPathRenderer_Delegate nativePathRenderer =
+                getDelegate(rendererPtr);
+
+        Canvas_Delegate.native_save(canvasWrapperPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+        Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.left, bounds.top);
+
+        if (needsMirroring) {
+            Canvas_Delegate.native_translate(canvasWrapperPtr, bounds.width(), 0);
+            Canvas_Delegate.native_scale(canvasWrapperPtr, -1.0f, 1.0f);
+        }
+
+        // At this point, canvas has been translated to the right position.
+        // And we use this bound for the destination rect for the drawBitmap, so
+        // we offset to (0, 0);
+        bounds.offsetTo(0, 0);
+        nativePathRenderer.draw(canvasWrapperPtr, colorFilterPtr, bounds.width(), bounds.height());
+
+        Canvas_Delegate.native_restore(canvasWrapperPtr, true);
+    }
+
+    @LayoutlibDelegate
+    static long nCreateFullPath() {
+        return sPathManager.addNewDelegate(new VFullPath_Delegate());
+    }
+
+    @LayoutlibDelegate
+    static long nCreateFullPath(long nativeFullPathPtr) {
+        VFullPath_Delegate original = getDelegate(nativeFullPathPtr);
+
+        return sPathManager.addNewDelegate(new VFullPath_Delegate(original));
+    }
+
+    @LayoutlibDelegate
+    static boolean nGetFullPathProperties(long pathPtr, byte[] propertiesData,
+            int length) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+
+        ByteBuffer properties = ByteBuffer.wrap(propertiesData);
+        properties.order(ByteOrder.nativeOrder());
+
+        properties.putFloat(VFullPath_Delegate.STROKE_WIDTH_INDEX * 4, path.getStrokeWidth());
+        properties.putInt(VFullPath_Delegate.STROKE_COLOR_INDEX * 4, path.getStrokeColor());
+        properties.putFloat(VFullPath_Delegate.STROKE_ALPHA_INDEX * 4, path.getStrokeAlpha());
+        properties.putInt(VFullPath_Delegate.FILL_COLOR_INDEX * 4, path.getFillColor());
+        properties.putFloat(VFullPath_Delegate.FILL_ALPHA_INDEX * 4, path.getStrokeAlpha());
+        properties.putFloat(VFullPath_Delegate.TRIM_PATH_START_INDEX * 4, path.getTrimPathStart());
+        properties.putFloat(VFullPath_Delegate.TRIM_PATH_END_INDEX * 4, path.getTrimPathEnd());
+        properties.putFloat(VFullPath_Delegate.TRIM_PATH_OFFSET_INDEX * 4,
+                path.getTrimPathOffset());
+        properties.putInt(VFullPath_Delegate.STROKE_LINE_CAP_INDEX * 4, path.getStrokeLineCap());
+        properties.putInt(VFullPath_Delegate.STROKE_LINE_JOIN_INDEX * 4, path.getStrokeLineJoin());
+        properties.putFloat(VFullPath_Delegate.STROKE_MITER_LIMIT_INDEX * 4,
+                path.getStrokeMiterlimit());
+
+        return true;
+    }
+
+    @LayoutlibDelegate
+    static void nUpdateFullPathProperties(long pathPtr, float strokeWidth,
+            int strokeColor, float strokeAlpha, int fillColor, float fillAlpha, float trimPathStart,
+            float trimPathEnd, float trimPathOffset, float strokeMiterLimit, int strokeLineCap,
+            int strokeLineJoin) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+
+        path.setStrokeWidth(strokeWidth);
+        path.setStrokeColor(strokeColor);
+        path.setStrokeAlpha(strokeAlpha);
+        path.setFillColor(fillColor);
+        path.setFillAlpha(fillAlpha);
+        path.setTrimPathStart(trimPathStart);
+        path.setTrimPathEnd(trimPathEnd);
+        path.setTrimPathOffset(trimPathOffset);
+        path.setStrokeMiterlimit(strokeMiterLimit);
+        path.setStrokeLineCap(strokeLineCap);
+        path.setStrokeLineJoin(strokeLineJoin);
+    }
+
+    @LayoutlibDelegate
+    static void nUpdateFullPathFillGradient(long pathPtr, long fillGradientPtr) {
+
+    }
+
+    @LayoutlibDelegate
+    static void nUpdateFullPathStrokeGradient(long pathPtr, long strokeGradientPtr) {
+
+    }
+
+    @LayoutlibDelegate
+    static long nCreateClipPath() {
+        return sPathManager.addNewDelegate(new VClipPath_Delegate());
+    }
+
+    @LayoutlibDelegate
+    static long nCreateClipPath(long clipPathPtr) {
+        VClipPath_Delegate original = getDelegate(clipPathPtr);
+        return sPathManager.addNewDelegate(new VClipPath_Delegate(original));
+    }
+
+    @LayoutlibDelegate
+    static long nCreateGroup() {
+        return sPathManager.addNewDelegate(new VGroup_Delegate());
+    }
+
+    @LayoutlibDelegate
+    static long nCreateGroup(long groupPtr) {
+        VGroup_Delegate original = getDelegate(groupPtr);
+        return sPathManager.addNewDelegate(
+                new VGroup_Delegate(original, new ArrayMap<String, Object>()));
+    }
+
+    @LayoutlibDelegate
+    static void nSetName(long nodePtr, String name) {
+        VNativeObject group = getDelegate(nodePtr);
+        group.setName(name);
+    }
+
+    @LayoutlibDelegate
+    static boolean nGetGroupProperties(long groupPtr, float[] propertiesData,
+            int length) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+
+        FloatBuffer properties = FloatBuffer.wrap(propertiesData);
+
+        properties.put(VGroup_Delegate.ROTATE_INDEX, group.getRotation());
+        properties.put(VGroup_Delegate.PIVOT_X_INDEX, group.getPivotX());
+        properties.put(VGroup_Delegate.PIVOT_Y_INDEX, group.getPivotY());
+        properties.put(VGroup_Delegate.SCALE_X_INDEX, group.getScaleX());
+        properties.put(VGroup_Delegate.SCALE_Y_INDEX, group.getScaleY());
+        properties.put(VGroup_Delegate.TRANSLATE_X_INDEX, group.getTranslateX());
+        properties.put(VGroup_Delegate.TRANSLATE_Y_INDEX, group.getTranslateY());
+
+        return true;
+    }
+    @LayoutlibDelegate
+    static void nUpdateGroupProperties(long groupPtr, float rotate, float pivotX,
+            float pivotY, float scaleX, float scaleY, float translateX, float translateY) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+
+        group.setRotation(rotate);
+        group.setPivotX(pivotX);
+        group.setPivotY(pivotY);
+        group.setScaleX(scaleX);
+        group.setScaleY(scaleY);
+        group.setTranslateX(translateX);
+        group.setTranslateY(translateY);
+    }
+
+    @LayoutlibDelegate
+    static void nAddChild(long groupPtr, long nodePtr) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        group.mChildren.add(getDelegate(nodePtr));
+    }
+
+    @LayoutlibDelegate
+    static void nSetPathString(long pathPtr, String pathString, int length) {
+        VPath_Delegate path = getDelegate(pathPtr);
+        path.setPathData(PathParser_Delegate.createNodesFromPathData(pathString));
+    }
+
+    /**
+     * The setters and getters below for paths and groups are here temporarily, and will be removed
+     * once the animation in AVD is replaced with RenderNodeAnimator, in which case the animation
+     * will modify these properties in native. By then no JNI hopping would be necessary for VD
+     * during animation, and these setters and getters will be obsolete.
+     */
+    // Setters and getters during animation.
+    @LayoutlibDelegate
+    static float nGetRotation(long groupPtr) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        return group.getRotation();
+    }
+
+    @LayoutlibDelegate
+    static void nSetRotation(long groupPtr, float rotation) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        group.setRotation(rotation);
+    }
+
+    @LayoutlibDelegate
+    static float nGetPivotX(long groupPtr) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        return group.getPivotX();
+    }
+
+    @LayoutlibDelegate
+    static void nSetPivotX(long groupPtr, float pivotX) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        group.setPivotX(pivotX);
+    }
+
+    @LayoutlibDelegate
+    static float nGetPivotY(long groupPtr) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        return group.getPivotY();
+    }
+
+    @LayoutlibDelegate
+    static void nSetPivotY(long groupPtr, float pivotY) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        group.setPivotY(pivotY);
+    }
+
+    @LayoutlibDelegate
+    static float nGetScaleX(long groupPtr) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        return group.getScaleX();
+    }
+
+    @LayoutlibDelegate
+    static void nSetScaleX(long groupPtr, float scaleX) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        group.setScaleX(scaleX);
+    }
+
+    @LayoutlibDelegate
+    static float nGetScaleY(long groupPtr) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        return group.getScaleY();
+    }
+
+    @LayoutlibDelegate
+    static void nSetScaleY(long groupPtr, float scaleY) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        group.setScaleY(scaleY);
+    }
+
+    @LayoutlibDelegate
+    static float nGetTranslateX(long groupPtr) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        return group.getTranslateX();
+    }
+
+    @LayoutlibDelegate
+    static void nSetTranslateX(long groupPtr, float translateX) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        group.setTranslateX(translateX);
+    }
+
+    @LayoutlibDelegate
+    static float nGetTranslateY(long groupPtr) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        return group.getTranslateY();
+    }
+
+    @LayoutlibDelegate
+    static void nSetTranslateY(long groupPtr, float translateY) {
+        VGroup_Delegate group = getDelegate(groupPtr);
+        group.setTranslateY(translateY);
+    }
+
+    @LayoutlibDelegate
+    static void nSetPathData(long pathPtr, long pathDataPtr) {
+        VPath_Delegate path = getDelegate(pathPtr);
+        path.setPathData(PathParser_Delegate.getDelegate(pathDataPtr).getPathDataNodes());
+    }
+
+    @LayoutlibDelegate
+    static float nGetStrokeWidth(long pathPtr) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        return path.getStrokeWidth();
+    }
+
+    @LayoutlibDelegate
+    static void nSetStrokeWidth(long pathPtr, float width) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        path.setStrokeWidth(width);
+    }
+
+    @LayoutlibDelegate
+    static int nGetStrokeColor(long pathPtr) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        return path.getStrokeColor();
+    }
+
+    @LayoutlibDelegate
+    static void nSetStrokeColor(long pathPtr, int strokeColor) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        path.setStrokeColor(strokeColor);
+    }
+
+    @LayoutlibDelegate
+    static float nGetStrokeAlpha(long pathPtr) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        return path.getStrokeAlpha();
+    }
+
+    @LayoutlibDelegate
+    static void nSetStrokeAlpha(long pathPtr, float alpha) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        path.setStrokeAlpha(alpha);
+    }
+
+    @LayoutlibDelegate
+    static int nGetFillColor(long pathPtr) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        return path.getFillColor();
+    }
+
+    @LayoutlibDelegate
+    static void nSetFillColor(long pathPtr, int fillColor) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        path.setFillColor(fillColor);
+    }
+
+    @LayoutlibDelegate
+    static float nGetFillAlpha(long pathPtr) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        return path.getFillAlpha();
+    }
+
+    @LayoutlibDelegate
+    static void nSetFillAlpha(long pathPtr, float fillAlpha) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        path.setFillAlpha(fillAlpha);
+    }
+
+    @LayoutlibDelegate
+    static float nGetTrimPathStart(long pathPtr) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        return path.getTrimPathStart();
+    }
+
+    @LayoutlibDelegate
+    static void nSetTrimPathStart(long pathPtr, float trimPathStart) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        path.setTrimPathStart(trimPathStart);
+    }
+
+    @LayoutlibDelegate
+    static float nGetTrimPathEnd(long pathPtr) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        return path.getTrimPathEnd();
+    }
+
+    @LayoutlibDelegate
+    static void nSetTrimPathEnd(long pathPtr, float trimPathEnd) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        path.setTrimPathEnd(trimPathEnd);
+    }
+
+    @LayoutlibDelegate
+    static float nGetTrimPathOffset(long pathPtr) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        return path.getTrimPathOffset();
+    }
+
+    @LayoutlibDelegate
+    static void nSetTrimPathOffset(long pathPtr, float trimPathOffset) {
+        VFullPath_Delegate path = getDelegate(pathPtr);
+        path.setTrimPathOffset(trimPathOffset);
+    }
+
+    /**
+     * Base class for all the internal Delegates that does two functions:
+     * <ol>
+     *     <li>Serves as base class to store all the delegates in one {@link DelegateManager}
+     *     <li>Provides setName for all the classes. {@link VPathRenderer_Delegate} does actually
+     *     not need it
+     * </ol>
+     */
+    private interface VNativeObject {
+        void setName(String name);
+    }
+
+    private static class VClipPath_Delegate extends VPath_Delegate {
+        private VClipPath_Delegate() {
+            // Empty constructor.
+        }
+
+        private VClipPath_Delegate(VClipPath_Delegate copy) {
+            super(copy);
+        }
+
+        @Override
+        public boolean isClipPath() {
+            return true;
+        }
+    }
+
+    private static class VFullPath_Delegate extends VPath_Delegate {
+        // These constants need to be kept in sync with their values in VectorDrawable.VFullPath
+        private static final int STROKE_WIDTH_INDEX = 0;
+        private static final int STROKE_COLOR_INDEX = 1;
+        private static final int STROKE_ALPHA_INDEX = 2;
+        private static final int FILL_COLOR_INDEX = 3;
+        private static final int FILL_ALPHA_INDEX = 4;
+        private static final int TRIM_PATH_START_INDEX = 5;
+        private static final int TRIM_PATH_END_INDEX = 6;
+        private static final int TRIM_PATH_OFFSET_INDEX = 7;
+        private static final int STROKE_LINE_CAP_INDEX = 8;
+        private static final int STROKE_LINE_JOIN_INDEX = 9;
+        private static final int STROKE_MITER_LIMIT_INDEX = 10;
+
+        private static final int LINECAP_BUTT = 0;
+        private static final int LINECAP_ROUND = 1;
+        private static final int LINECAP_SQUARE = 2;
+
+        private static final int LINEJOIN_MITER = 0;
+        private static final int LINEJOIN_ROUND = 1;
+        private static final int LINEJOIN_BEVEL = 2;
+
+        /////////////////////////////////////////////////////
+        // Variables below need to be copied (deep copy if applicable) for mutation.
+
+        int mStrokeColor = Color.TRANSPARENT;
+        float mStrokeWidth = 0;
+
+        int mFillColor = Color.TRANSPARENT;
+        float mStrokeAlpha = 1.0f;
+        float mFillAlpha = 1.0f;
+        float mTrimPathStart = 0;
+        float mTrimPathEnd = 1;
+        float mTrimPathOffset = 0;
+
+        Cap mStrokeLineCap = BUTT;
+        Join mStrokeLineJoin = MITER;
+        float mStrokeMiterlimit = 4;
+
+        private VFullPath_Delegate() {
+            // Empty constructor.
+        }
+
+        private VFullPath_Delegate(VFullPath_Delegate copy) {
+            super(copy);
+
+            mStrokeColor = copy.mStrokeColor;
+            mStrokeWidth = copy.mStrokeWidth;
+            mStrokeAlpha = copy.mStrokeAlpha;
+            mFillColor = copy.mFillColor;
+            mFillAlpha = copy.mFillAlpha;
+            mTrimPathStart = copy.mTrimPathStart;
+            mTrimPathEnd = copy.mTrimPathEnd;
+            mTrimPathOffset = copy.mTrimPathOffset;
+
+            mStrokeLineCap = copy.mStrokeLineCap;
+            mStrokeLineJoin = copy.mStrokeLineJoin;
+            mStrokeMiterlimit = copy.mStrokeMiterlimit;
+        }
+
+        private int getStrokeLineCap() {
+            switch (mStrokeLineCap) {
+                case BUTT:
+                    return LINECAP_BUTT;
+                case ROUND:
+                    return LINECAP_ROUND;
+                case SQUARE:
+                    return LINECAP_SQUARE;
+                default:
+                    assert false;
+            }
+
+            return -1;
+        }
+
+        private void setStrokeLineCap(int cap) {
+            switch (cap) {
+                case LINECAP_BUTT:
+                    mStrokeLineCap = BUTT;
+                    break;
+                case LINECAP_ROUND:
+                    mStrokeLineCap = ROUND;
+                    break;
+                case LINECAP_SQUARE:
+                    mStrokeLineCap = SQUARE;
+                    break;
+                default:
+                    assert false;
+            }
+        }
+
+        private int getStrokeLineJoin() {
+            switch (mStrokeLineJoin) {
+                case MITER:
+                    return LINEJOIN_MITER;
+                case ROUND:
+                    return LINEJOIN_ROUND;
+                case BEVEL:
+                    return LINEJOIN_BEVEL;
+                default:
+                    assert false;
+            }
+
+            return -1;
+        }
+
+        private void setStrokeLineJoin(int join) {
+            switch (join) {
+                case LINEJOIN_BEVEL:
+                    mStrokeLineJoin = BEVEL;
+                    break;
+                case LINEJOIN_MITER:
+                    mStrokeLineJoin = MITER;
+                    break;
+                case LINEJOIN_ROUND:
+                    mStrokeLineJoin = Join.ROUND;
+                    break;
+                default:
+                    assert false;
+            }
+        }
+
+        private int getStrokeColor() {
+            return mStrokeColor;
+        }
+
+                private void setStrokeColor(int strokeColor) {
+            mStrokeColor = strokeColor;
+        }
+
+        private float getStrokeWidth() {
+            return mStrokeWidth;
+        }
+
+        private void setStrokeWidth(float strokeWidth) {
+            mStrokeWidth = strokeWidth;
+        }
+
+        private float getStrokeAlpha() {
+            return mStrokeAlpha;
+        }
+
+        private void setStrokeAlpha(float strokeAlpha) {
+            mStrokeAlpha = strokeAlpha;
+        }
+
+        private int getFillColor() {
+            return mFillColor;
+        }
+
+        private void setFillColor(int fillColor) {
+            mFillColor = fillColor;
+        }
+
+        private float getFillAlpha() {
+            return mFillAlpha;
+        }
+
+        private void setFillAlpha(float fillAlpha) {
+            mFillAlpha = fillAlpha;
+        }
+
+        private float getTrimPathStart() {
+            return mTrimPathStart;
+        }
+
+        private void setTrimPathStart(float trimPathStart) {
+            mTrimPathStart = trimPathStart;
+        }
+
+        private float getTrimPathEnd() {
+            return mTrimPathEnd;
+        }
+
+        private void setTrimPathEnd(float trimPathEnd) {
+            mTrimPathEnd = trimPathEnd;
+        }
+
+        private float getTrimPathOffset() {
+            return mTrimPathOffset;
+        }
+
+        private void setTrimPathOffset(float trimPathOffset) {
+            mTrimPathOffset = trimPathOffset;
+        }
+
+        private void setStrokeMiterlimit(float limit) {
+            mStrokeMiterlimit = limit;
+        }
+
+        private float getStrokeMiterlimit() {
+            return mStrokeMiterlimit;
+        }
+    }
+
+    private static class VGroup_Delegate implements VNativeObject {
+        // This constants need to be kept in sync with their definitions in VectorDrawable.Group
+        private static final int ROTATE_INDEX = 0;
+        private static final int PIVOT_X_INDEX = 1;
+        private static final int PIVOT_Y_INDEX = 2;
+        private static final int SCALE_X_INDEX = 3;
+        private static final int SCALE_Y_INDEX = 4;
+        private static final int TRANSLATE_X_INDEX = 5;
+        private static final int TRANSLATE_Y_INDEX = 6;
+
+        /////////////////////////////////////////////////////
+        // Variables below need to be copied (deep copy if applicable) for mutation.
+        final ArrayList<Object> mChildren = new ArrayList<>();
+        // mStackedMatrix is only used temporarily when drawing, it combines all
+        // the parents' local matrices with the current one.
+        private final Matrix mStackedMatrix = new Matrix();
+        // mLocalMatrix is updated based on the update of transformation information,
+        // either parsed from the XML or by animation.
+        private final Matrix mLocalMatrix = new Matrix();
+        private float mRotate = 0;
+        private float mPivotX = 0;
+        private float mPivotY = 0;
+        private float mScaleX = 1;
+        private float mScaleY = 1;
+        private float mTranslateX = 0;
+        private float mTranslateY = 0;
+        private int mChangingConfigurations;
+        private String mGroupName = null;
+
+        private VGroup_Delegate(VGroup_Delegate copy, ArrayMap<String, Object> targetsMap) {
+            mRotate = copy.mRotate;
+            mPivotX = copy.mPivotX;
+            mPivotY = copy.mPivotY;
+            mScaleX = copy.mScaleX;
+            mScaleY = copy.mScaleY;
+            mTranslateX = copy.mTranslateX;
+            mTranslateY = copy.mTranslateY;
+            mGroupName = copy.mGroupName;
+            mChangingConfigurations = copy.mChangingConfigurations;
+            if (mGroupName != null) {
+                targetsMap.put(mGroupName, this);
+            }
+
+            mLocalMatrix.set(copy.mLocalMatrix);
+
+            final ArrayList<Object> children = copy.mChildren;
+            //noinspection ForLoopReplaceableByForEach
+            for (int i = 0; i < children.size(); i++) {
+                Object copyChild = children.get(i);
+                if (copyChild instanceof VGroup_Delegate) {
+                    VGroup_Delegate copyGroup = (VGroup_Delegate) copyChild;
+                    mChildren.add(new VGroup_Delegate(copyGroup, targetsMap));
+                } else {
+                    VPath_Delegate newPath;
+                    if (copyChild instanceof VFullPath_Delegate) {
+                        newPath = new VFullPath_Delegate((VFullPath_Delegate) copyChild);
+                    } else if (copyChild instanceof VClipPath_Delegate) {
+                        newPath = new VClipPath_Delegate((VClipPath_Delegate) copyChild);
+                    } else {
+                        throw new IllegalStateException("Unknown object in the tree!");
+                    }
+                    mChildren.add(newPath);
+                    if (newPath.mPathName != null) {
+                        targetsMap.put(newPath.mPathName, newPath);
+                    }
+                }
+            }
+        }
+
+        private VGroup_Delegate() {
+        }
+
+        private void updateLocalMatrix() {
+            // The order we apply is the same as the
+            // RenderNode.cpp::applyViewPropertyTransforms().
+            mLocalMatrix.reset();
+            mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
+            mLocalMatrix.postScale(mScaleX, mScaleY);
+            mLocalMatrix.postRotate(mRotate, 0, 0);
+            mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
+        }
+
+        /* Setters and Getters, used by animator from AnimatedVectorDrawable. */
+        private float getRotation() {
+            return mRotate;
+        }
+
+        private void setRotation(float rotation) {
+            if (rotation != mRotate) {
+                mRotate = rotation;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getPivotX() {
+            return mPivotX;
+        }
+
+        private void setPivotX(float pivotX) {
+            if (pivotX != mPivotX) {
+                mPivotX = pivotX;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getPivotY() {
+            return mPivotY;
+        }
+
+        private void setPivotY(float pivotY) {
+            if (pivotY != mPivotY) {
+                mPivotY = pivotY;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getScaleX() {
+            return mScaleX;
+        }
+
+        private void setScaleX(float scaleX) {
+            if (scaleX != mScaleX) {
+                mScaleX = scaleX;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getScaleY() {
+            return mScaleY;
+        }
+
+        private void setScaleY(float scaleY) {
+            if (scaleY != mScaleY) {
+                mScaleY = scaleY;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getTranslateX() {
+            return mTranslateX;
+        }
+
+        private void setTranslateX(float translateX) {
+            if (translateX != mTranslateX) {
+                mTranslateX = translateX;
+                updateLocalMatrix();
+            }
+        }
+
+        private float getTranslateY() {
+            return mTranslateY;
+        }
+
+        private void setTranslateY(float translateY) {
+            if (translateY != mTranslateY) {
+                mTranslateY = translateY;
+                updateLocalMatrix();
+            }
+        }
+
+        @Override
+        public void setName(String name) {
+            mGroupName = name;
+        }
+    }
+
+    public static class VPath_Delegate implements VNativeObject {
+        protected PathParser_Delegate.PathDataNode[] mNodes = null;
+        String mPathName;
+        int mChangingConfigurations;
+
+        public VPath_Delegate() {
+            // Empty constructor.
+        }
+
+        public VPath_Delegate(VPath_Delegate copy) {
+            mPathName = copy.mPathName;
+            mChangingConfigurations = copy.mChangingConfigurations;
+            mNodes = PathParser_Delegate.deepCopyNodes(copy.mNodes);
+        }
+
+        public void toPath(Path path) {
+            path.reset();
+            if (mNodes != null) {
+                PathParser_Delegate.PathDataNode.nodesToPath(mNodes,
+                        Path_Delegate.getDelegate(path.mNativePath));
+            }
+        }
+
+        @Override
+        public void setName(String name) {
+            mPathName = name;
+        }
+
+        public boolean isClipPath() {
+            return false;
+        }
+
+        private void setPathData(PathParser_Delegate.PathDataNode[] nodes) {
+            if (!PathParser_Delegate.canMorph(mNodes, nodes)) {
+                // This should not happen in the middle of animation.
+                mNodes = PathParser_Delegate.deepCopyNodes(nodes);
+            } else {
+                PathParser_Delegate.updateNodes(mNodes, nodes);
+            }
+        }
+    }
+
+    private static class VPathRenderer_Delegate implements VNativeObject {
+        /* Right now the internal data structure is organized as a tree.
+         * Each node can be a group node, or a path.
+         * A group node can have groups or paths as children, but a path node has
+         * no children.
+         * One example can be:
+         *                 Root Group
+         *                /    |     \
+         *           Group    Path    Group
+         *          /     \             |
+         *         Path   Path         Path
+         *
+         */
+        // Variables that only used temporarily inside the draw() call, so there
+        // is no need for deep copying.
+        private final Path mPath;
+        private final Path mRenderPath;
+        private final Matrix mFinalPathMatrix = new Matrix();
+        private final VGroup_Delegate mRootGroup;
+        private float mViewportWidth = 0;
+        private float mViewportHeight = 0;
+        private float mRootAlpha = 1.0f;
+        private Paint mStrokePaint;
+        private Paint mFillPaint;
+        private PathMeasure mPathMeasure;
+
+        private VPathRenderer_Delegate(VGroup_Delegate rootGroup) {
+            mRootGroup = rootGroup;
+            mPath = new Path();
+            mRenderPath = new Path();
+        }
+
+        private float getRootAlpha() {
+            return mRootAlpha;
+        }
+
+        private void setRootAlpha(float alpha) {
+            mRootAlpha = alpha;
+        }
+
+        private void drawGroupTree(VGroup_Delegate currentGroup, Matrix currentMatrix,
+                long canvasPtr, int w, int h, long filterPtr) {
+            // Calculate current group's matrix by preConcat the parent's and
+            // and the current one on the top of the stack.
+            // Basically the Mfinal = Mviewport * M0 * M1 * M2;
+            // Mi the local matrix at level i of the group tree.
+            currentGroup.mStackedMatrix.set(currentMatrix);
+            currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
+
+            // Save the current clip information, which is local to this group.
+            Canvas_Delegate.native_save(canvasPtr, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+            // Draw the group tree in the same order as the XML file.
+            for (int i = 0; i < currentGroup.mChildren.size(); i++) {
+                Object child = currentGroup.mChildren.get(i);
+                if (child instanceof VGroup_Delegate) {
+                    VGroup_Delegate childGroup = (VGroup_Delegate) child;
+                    drawGroupTree(childGroup, currentGroup.mStackedMatrix,
+                            canvasPtr, w, h, filterPtr);
+                } else if (child instanceof VPath_Delegate) {
+                    VPath_Delegate childPath = (VPath_Delegate) child;
+                    drawPath(currentGroup, childPath, canvasPtr, w, h, filterPtr);
+                }
+            }
+            Canvas_Delegate.native_restore(canvasPtr, true);
+        }
+
+        public void draw(long canvasPtr, long filterPtr, int w, int h) {
+            // Traverse the tree in pre-order to draw.
+            drawGroupTree(mRootGroup, Matrix.IDENTITY_MATRIX, canvasPtr, w, h, filterPtr);
+        }
+
+        private void drawPath(VGroup_Delegate VGroup, VPath_Delegate VPath, long canvasPtr,
+                int w,
+                int h,
+                long filterPtr) {
+            final float scaleX = w / mViewportWidth;
+            final float scaleY = h / mViewportHeight;
+            final float minScale = Math.min(scaleX, scaleY);
+            final Matrix groupStackedMatrix = VGroup.mStackedMatrix;
+
+            mFinalPathMatrix.set(groupStackedMatrix);
+            mFinalPathMatrix.postScale(scaleX, scaleY);
+
+            final float matrixScale = getMatrixScale(groupStackedMatrix);
+            if (matrixScale == 0) {
+                // When either x or y is scaled to 0, we don't need to draw anything.
+                return;
+            }
+            VPath.toPath(mPath);
+            final Path path = mPath;
+
+            mRenderPath.reset();
+
+            if (VPath.isClipPath()) {
+                mRenderPath.addPath(path, mFinalPathMatrix);
+                Canvas_Delegate.native_clipPath(canvasPtr, mRenderPath.mNativePath, Op
+                        .INTERSECT.nativeInt);
+            } else {
+                VFullPath_Delegate fullPath = (VFullPath_Delegate) VPath;
+                if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) {
+                    float start = (fullPath.mTrimPathStart + fullPath.mTrimPathOffset) % 1.0f;
+                    float end = (fullPath.mTrimPathEnd + fullPath.mTrimPathOffset) % 1.0f;
+
+                    if (mPathMeasure == null) {
+                        mPathMeasure = new PathMeasure();
+                    }
+                    mPathMeasure.setPath(mPath, false);
+
+                    float len = mPathMeasure.getLength();
+                    start = start * len;
+                    end = end * len;
+                    path.reset();
+                    if (start > end) {
+                        mPathMeasure.getSegment(start, len, path, true);
+                        mPathMeasure.getSegment(0f, end, path, true);
+                    } else {
+                        mPathMeasure.getSegment(start, end, path, true);
+                    }
+                    path.rLineTo(0, 0); // fix bug in measure
+                }
+                mRenderPath.addPath(path, mFinalPathMatrix);
+
+                if (fullPath.mFillColor != Color.TRANSPARENT) {
+                    if (mFillPaint == null) {
+                        mFillPaint = new Paint();
+                        mFillPaint.setStyle(Style.FILL);
+                        mFillPaint.setAntiAlias(true);
+                    }
+
+                    final Paint fillPaint = mFillPaint;
+                    fillPaint.setColor(applyAlpha(fullPath.mFillColor, fullPath.mFillAlpha));
+                    Paint_Delegate fillPaintDelegate = Paint_Delegate.getDelegate(fillPaint
+                            .getNativeInstance
+                            ());
+                    // mFillPaint can not be null at this point so we will have a delegate
+                    assert fillPaintDelegate != null;
+                    fillPaintDelegate.setColorFilter(filterPtr);
+                    Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, fillPaint
+                            .getNativeInstance());
+                }
+
+                if (fullPath.mStrokeColor != Color.TRANSPARENT) {
+                    if (mStrokePaint == null) {
+                        mStrokePaint = new Paint();
+                        mStrokePaint.setStyle(Style.STROKE);
+                        mStrokePaint.setAntiAlias(true);
+                    }
+
+                    final Paint strokePaint = mStrokePaint;
+                    if (fullPath.mStrokeLineJoin != null) {
+                        strokePaint.setStrokeJoin(fullPath.mStrokeLineJoin);
+                    }
+
+                    if (fullPath.mStrokeLineCap != null) {
+                        strokePaint.setStrokeCap(fullPath.mStrokeLineCap);
+                    }
+
+                    strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit);
+                    strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha));
+                    Paint_Delegate strokePaintDelegate = Paint_Delegate.getDelegate(strokePaint
+                            .getNativeInstance());
+                    // mStrokePaint can not be null at this point so we will have a delegate
+                    assert strokePaintDelegate != null;
+                    strokePaintDelegate.setColorFilter(filterPtr);
+                    final float finalStrokeScale = minScale * matrixScale;
+                    strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale);
+                    Canvas_Delegate.native_drawPath(canvasPtr, mRenderPath.mNativePath, strokePaint
+                            .getNativeInstance());
+                }
+            }
+        }
+
+        private float getMatrixScale(Matrix groupStackedMatrix) {
+            // Given unit vectors A = (0, 1) and B = (1, 0).
+            // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'.
+            // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)),
+            // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|);
+            // If  max (|A'|, |B'|) = 0, that means either x or y has a scale of 0.
+            //
+            // For non-skew case, which is most of the cases, matrix scale is computing exactly the
+            // scale on x and y axis, and take the minimal of these two.
+            // For skew case, an unit square will mapped to a parallelogram. And this function will
+            // return the minimal height of the 2 bases.
+            float[] unitVectors = new float[]{0, 1, 1, 0};
+            groupStackedMatrix.mapVectors(unitVectors);
+            float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]);
+            float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]);
+            float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1],
+                    unitVectors[2], unitVectors[3]);
+            float maxScale = MathUtils.max(scaleX, scaleY);
+
+            float matrixScale = 0;
+            if (maxScale > 0) {
+                matrixScale = MathUtils.abs(crossProduct) / maxScale;
+            }
+            if (DBG_VECTOR_DRAWABLE) {
+                Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale);
+            }
+            return matrixScale;
+        }
+
+        @Override
+        public void setName(String name) {
+        }
+    }
+}
index d3af837..6c34c70 100644 (file)
@@ -24,7 +24,6 @@ import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
 import android.annotation.NonNull;
 import android.graphics.Path_Delegate;
 
-import java.awt.geom.Path2D;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.logging.Level;
@@ -52,10 +51,18 @@ public class PathParser_Delegate {
     @NonNull
     private PathDataNode[] mPathDataNodes;
 
+    public static PathParser_Delegate getDelegate(long nativePtr) {
+        return sManager.getDelegate(nativePtr);
+    }
+
     private PathParser_Delegate(@NonNull PathDataNode[] nodes) {
         mPathDataNodes = nodes;
     }
 
+    public PathDataNode[] getPathDataNodes() {
+        return mPathDataNodes;
+    }
+
     @LayoutlibDelegate
     /*package*/ static boolean nParseStringForPath(long pathPtr, @NonNull String pathString, int
             stringLength) {
@@ -64,7 +71,7 @@ public class PathParser_Delegate {
             return false;
         }
         assert pathString.length() == stringLength;
-        PathDataNode.nodesToPath(createNodesFromPathData(pathString), path_delegate.getJavaShape());
+        PathDataNode.nodesToPath(createNodesFromPathData(pathString), path_delegate);
         return true;
     }
 
@@ -75,7 +82,7 @@ public class PathParser_Delegate {
         if (source == null || path_delegate == null) {
             return;
         }
-        PathDataNode.nodesToPath(source.mPathDataNodes, path_delegate.getJavaShape());
+        PathDataNode.nodesToPath(source.mPathDataNodes, path_delegate);
     }
 
     @LayoutlibDelegate
@@ -124,8 +131,11 @@ public class PathParser_Delegate {
             out.mPathDataNodes = new PathDataNode[length];
         }
         for (int i = 0; i < length; i++) {
+            if (out.mPathDataNodes[i] == null) {
+                out.mPathDataNodes[i] = new PathDataNode(from.mPathDataNodes[i]);
+            }
             out.mPathDataNodes[i].interpolatePathDataNode(from.mPathDataNodes[i],
-                    to.mPathDataNodes[i], fraction);
+                        to.mPathDataNodes[i], fraction);
         }
         return true;
     }
@@ -137,9 +147,13 @@ public class PathParser_Delegate {
 
     @LayoutlibDelegate
     /*package*/ static boolean nCanMorph(long fromDataPtr, long toDataPtr) {
-        Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED, "morphing path data isn't " +
-                "supported", null, null);
-        return false;
+        PathParser_Delegate fromPath = PathParser_Delegate.getDelegate(fromDataPtr);
+        PathParser_Delegate toPath = PathParser_Delegate.getDelegate(toDataPtr);
+        if (fromPath == null || toPath == null || fromPath.getPathDataNodes() == null || toPath
+                .getPathDataNodes() == null) {
+            return true;
+        }
+        return PathParser_Delegate.canMorph(fromPath.getPathDataNodes(), toPath.getPathDataNodes());
     }
 
     @LayoutlibDelegate
@@ -158,7 +172,7 @@ public class PathParser_Delegate {
      * @return an array of the PathDataNode.
      */
     @NonNull
-    private static PathDataNode[] createNodesFromPathData(@NonNull String pathData) {
+    public static PathDataNode[] createNodesFromPathData(@NonNull String pathData) {
         int start = 0;
         int end = 1;
 
@@ -186,7 +200,7 @@ public class PathParser_Delegate {
      * @return a deep copy of the <code>source</code>.
      */
     @NonNull
-    private static PathDataNode[] deepCopyNodes(@NonNull PathDataNode[] source) {
+    public static PathDataNode[] deepCopyNodes(@NonNull PathDataNode[] source) {
         PathDataNode[] copy = new PathDataNode[source.length];
         for (int i = 0; i < source.length; i++) {
             copy[i] = new PathDataNode(source[i]);
@@ -194,6 +208,45 @@ public class PathParser_Delegate {
         return copy;
     }
 
+    /**
+     * @param nodesFrom The source path represented in an array of PathDataNode
+     * @param nodesTo The target path represented in an array of PathDataNode
+     * @return whether the <code>nodesFrom</code> can morph into <code>nodesTo</code>
+     */
+    public static boolean canMorph(PathDataNode[] nodesFrom, PathDataNode[] nodesTo) {
+        if (nodesFrom == null || nodesTo == null) {
+            return false;
+        }
+
+        if (nodesFrom.length != nodesTo.length) {
+            return false;
+        }
+
+        for (int i = 0; i < nodesFrom.length; i ++) {
+            if (nodesFrom[i].mType != nodesTo[i].mType
+                    || nodesFrom[i].mParams.length != nodesTo[i].mParams.length) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Update the target's data to match the source.
+     * Before calling this, make sure canMorph(target, source) is true.
+     *
+     * @param target The target path represented in an array of PathDataNode
+     * @param source The source path represented in an array of PathDataNode
+     */
+    public static void updateNodes(PathDataNode[] target, PathDataNode[] source) {
+        for (int i = 0; i < source.length; i ++) {
+            target[i].mType = source[i].mType;
+            for (int j = 0; j < source[i].mParams.length; j ++) {
+                target[i].mParams[j] = source[i].mParams[j];
+            }
+        }
+    }
+
     private static int nextStart(@NonNull String s, int end) {
         char c;
 
@@ -330,7 +383,7 @@ public class PathParser_Delegate {
      * Each PathDataNode represents one command in the "d" attribute of the svg file. An array of
      * PathDataNode can represent the whole "d" attribute.
      */
-    private static class PathDataNode {
+    public static class PathDataNode {
         private char mType;
         @NonNull
         private float[] mParams;
@@ -355,12 +408,13 @@ public class PathParser_Delegate {
         }
 
         /**
-         * Convert an array of PathDataNode to Path.
+         * Convert an array of PathDataNode to Path. Reset the passed path as needed before
+         * calling this method.
          *
          * @param node The source array of PathDataNode.
          * @param path The target Path object.
          */
-        private static void nodesToPath(@NonNull PathDataNode[] node, @NonNull Path2D path) {
+        public static void nodesToPath(@NonNull PathDataNode[] node, @NonNull Path_Delegate path) {
             float[] current = new float[6];
             char previousCommand = 'm';
             //noinspection ForLoopReplaceableByForEach
@@ -387,24 +441,32 @@ public class PathParser_Delegate {
         }
 
         @SuppressWarnings("PointlessArithmeticExpression")
-        private static void addCommand(@NonNull Path2D path, float[] current, char cmd,
-                char lastCmd, @NonNull float[] val) {
+        private static void addCommand(@NonNull Path_Delegate path, float[] current,
+                char previousCmd, char cmd, @NonNull float[] val) {
 
             int incr = 2;
-
-            float cx = current[0];
-            float cy = current[1];
-            float cpx = current[2];
-            float cpy = current[3];
-            float loopX = current[4];
-            float loopY = current[5];
+            float currentX = current[0];
+            float currentY = current[1];
+            float ctrlPointX = current[2];
+            float ctrlPointY = current[3];
+            float currentSegmentStartX = current[4];
+            float currentSegmentStartY = current[5];
+            float reflectiveCtrlPointX;
+            float reflectiveCtrlPointY;
 
             switch (cmd) {
                 case 'z':
                 case 'Z':
-                    path.closePath();
-                    cx = loopX;
-                    cy = loopY;
+                    path.close();
+                    // Path is closed here, but we need to move the pen to the
+                    // closed position. So we cache the segment's starting position,
+                    // and restore it here.
+                    currentX = currentSegmentStartX;
+                    currentY = currentSegmentStartY;
+                    ctrlPointX = currentSegmentStartX;
+                    ctrlPointY = currentSegmentStartY;
+                    path.moveTo(currentX, currentY);
+                    break;
                 case 'm':
                 case 'M':
                 case 'l':
@@ -432,185 +494,206 @@ public class PathParser_Delegate {
                 case 'a':
                 case 'A':
                     incr = 7;
+                    break;
             }
 
             for (int k = 0; k < val.length; k += incr) {
-                boolean reflectCtrl;
-                float tempReflectedX, tempReflectedY;
-
                 switch (cmd) {
-                    case 'm':
-                        cx += val[k + 0];
-                        cy += val[k + 1];
+                    case 'm': // moveto - Start a new sub-path (relative)
+                        currentX += val[k + 0];
+                        currentY += val[k + 1];
+
                         if (k > 0) {
                             // According to the spec, if a moveto is followed by multiple
                             // pairs of coordinates, the subsequent pairs are treated as
                             // implicit lineto commands.
-                            path.lineTo(cx, cy);
+                            path.rLineTo(val[k + 0], val[k + 1]);
                         } else {
-                            path.moveTo(cx, cy);
-                            loopX = cx;
-                            loopY = cy;
+                            path.rMoveTo(val[k + 0], val[k + 1]);
+                            currentSegmentStartX = currentX;
+                            currentSegmentStartY = currentY;
                         }
                         break;
-                    case 'M':
-                        cx = val[k + 0];
-                        cy = val[k + 1];
+                    case 'M': // moveto - Start a new sub-path
+                        currentX = val[k + 0];
+                        currentY = val[k + 1];
+
                         if (k > 0) {
                             // According to the spec, if a moveto is followed by multiple
                             // pairs of coordinates, the subsequent pairs are treated as
                             // implicit lineto commands.
-                            path.lineTo(cx, cy);
+                            path.lineTo(val[k + 0], val[k + 1]);
                         } else {
-                            path.moveTo(cx, cy);
-                            loopX = cx;
-                            loopY = cy;
+                            path.moveTo(val[k + 0], val[k + 1]);
+                            currentSegmentStartX = currentX;
+                            currentSegmentStartY = currentY;
                         }
                         break;
-                    case 'l':
-                        cx += val[k + 0];
-                        cy += val[k + 1];
-                        path.lineTo(cx, cy);
-                        break;
-                    case 'L':
-                        cx = val[k + 0];
-                        cy = val[k + 1];
-                        path.lineTo(cx, cy);
+                    case 'l': // lineto - Draw a line from the current point (relative)
+                        path.rLineTo(val[k + 0], val[k + 1]);
+                        currentX += val[k + 0];
+                        currentY += val[k + 1];
                         break;
-                    case 'z':
-                    case 'Z':
-                        path.closePath();
-                        cx = loopX;
-                        cy = loopY;
+                    case 'L': // lineto - Draw a line from the current point
+                        path.lineTo(val[k + 0], val[k + 1]);
+                        currentX = val[k + 0];
+                        currentY = val[k + 1];
                         break;
-                    case 'h':
-                        cx += val[k + 0];
-                        path.lineTo(cx, cy);
+                    case 'h': // horizontal lineto - Draws a horizontal line (relative)
+                        path.rLineTo(val[k + 0], 0);
+                        currentX += val[k + 0];
                         break;
-                    case 'H':
-                        path.lineTo(val[k + 0], cy);
-                        cx = val[k + 0];
+                    case 'H': // horizontal lineto - Draws a horizontal line
+                        path.lineTo(val[k + 0], currentY);
+                        currentX = val[k + 0];
                         break;
-                    case 'v':
-                        cy += val[k + 0];
-                        path.lineTo(cx, cy);
+                    case 'v': // vertical lineto - Draws a vertical line from the current point (r)
+                        path.rLineTo(0, val[k + 0]);
+                        currentY += val[k + 0];
                         break;
-                    case 'V':
-                        path.lineTo(cx, val[k + 0]);
-                        cy = val[k + 0];
+                    case 'V': // vertical lineto - Draws a vertical line from the current point
+                        path.lineTo(currentX, val[k + 0]);
+                        currentY = val[k + 0];
                         break;
-                    case 'c':
-                        path.curveTo(cx + val[k + 0], cy + val[k + 1], cx + val[k + 2],
-                                cy + val[k + 3], cx + val[k + 4], cy + val[k + 5]);
-                        cpx = cx + val[k + 2];
-                        cpy = cy + val[k + 3];
-                        cx += val[k + 4];
-                        cy += val[k + 5];
+                    case 'c': // curveto - Draws a cubic Bézier curve (relative)
+                        path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+                                val[k + 4], val[k + 5]);
+
+                        ctrlPointX = currentX + val[k + 2];
+                        ctrlPointY = currentY + val[k + 3];
+                        currentX += val[k + 4];
+                        currentY += val[k + 5];
+
                         break;
-                    case 'C':
-                        path.curveTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
+                    case 'C': // curveto - Draws a cubic Bézier curve
+                        path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
                                 val[k + 4], val[k + 5]);
-                        cx = val[k + 4];
-                        cy = val[k + 5];
-                        cpx = val[k + 2];
-                        cpy = val[k + 3];
+                        currentX = val[k + 4];
+                        currentY = val[k + 5];
+                        ctrlPointX = val[k + 2];
+                        ctrlPointY = val[k + 3];
                         break;
-                    case 's':
-                        reflectCtrl = (lastCmd == 'c' || lastCmd == 's' || lastCmd == 'C' ||
-                                lastCmd == 'S');
-                        path.curveTo(reflectCtrl ? 2 * cx - cpx : cx, reflectCtrl ? 2
-                                * cy - cpy : cy, cx + val[k + 0], cy + val[k + 1], cx
-                                + val[k + 2], cy + val[k + 3]);
-
-                        cpx = cx + val[k + 0];
-                        cpy = cy + val[k + 1];
-                        cx += val[k + 2];
-                        cy += val[k + 3];
+                    case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
+                        reflectiveCtrlPointX = 0;
+                        reflectiveCtrlPointY = 0;
+                        if (previousCmd == 'c' || previousCmd == 's'
+                                || previousCmd == 'C' || previousCmd == 'S') {
+                            reflectiveCtrlPointX = currentX - ctrlPointX;
+                            reflectiveCtrlPointY = currentY - ctrlPointY;
+                        }
+                        path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+                                val[k + 0], val[k + 1],
+                                val[k + 2], val[k + 3]);
+
+                        ctrlPointX = currentX + val[k + 0];
+                        ctrlPointY = currentY + val[k + 1];
+                        currentX += val[k + 2];
+                        currentY += val[k + 3];
                         break;
-                    case 'S':
-                        reflectCtrl = (lastCmd == 'c' || lastCmd == 's' || lastCmd == 'C' ||
-                                lastCmd == 'S');
-                        path.curveTo(reflectCtrl ? 2 * cx - cpx : cx, reflectCtrl ? 2
-                                        * cy - cpy : cy, val[k + 0], val[k + 1], val[k + 2],
-                                val[k + 3]);
-                        cpx = (val[k + 0]);
-                        cpy = (val[k + 1]);
-                        cx = val[k + 2];
-                        cy = val[k + 3];
+                    case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
+                        reflectiveCtrlPointX = currentX;
+                        reflectiveCtrlPointY = currentY;
+                        if (previousCmd == 'c' || previousCmd == 's'
+                                || previousCmd == 'C' || previousCmd == 'S') {
+                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+                        }
+                        path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+                                val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+                        ctrlPointX = val[k + 0];
+                        ctrlPointY = val[k + 1];
+                        currentX = val[k + 2];
+                        currentY = val[k + 3];
                         break;
-                    case 'q':
-                        path.quadTo(cx + val[k + 0], cy + val[k + 1], cx + val[k + 2],
-                                cy + val[k + 3]);
-                        cpx = cx + val[k + 0];
-                        cpy = cy + val[k + 1];
-                        // Note that we have to update cpx first, since cx will be updated here.
-                        cx += val[k + 2];
-                        cy += val[k + 3];
+                    case 'q': // Draws a quadratic Bézier (relative)
+                        path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
+                        ctrlPointX = currentX + val[k + 0];
+                        ctrlPointY = currentY + val[k + 1];
+                        currentX += val[k + 2];
+                        currentY += val[k + 3];
                         break;
-                    case 'Q':
+                    case 'Q': // Draws a quadratic Bézier
                         path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
-                        cx = val[k + 2];
-                        cy = val[k + 3];
-                        cpx = val[k + 0];
-                        cpy = val[k + 1];
+                        ctrlPointX = val[k + 0];
+                        ctrlPointY = val[k + 1];
+                        currentX = val[k + 2];
+                        currentY = val[k + 3];
                         break;
-                    case 't':
-                        reflectCtrl = (lastCmd == 'q' || lastCmd == 't' || lastCmd == 'Q' ||
-                                lastCmd == 'T');
-                        tempReflectedX = reflectCtrl ? 2 * cx - cpx : cx;
-                        tempReflectedY = reflectCtrl ? 2 * cy - cpy : cy;
-                        path.quadTo(tempReflectedX, tempReflectedY, cx + val[k + 0],
-                                cy + val[k + 1]);
-                        cpx = tempReflectedX;
-                        cpy = tempReflectedY;
-                        cx += val[k + 0];
-                        cy += val[k + 1];
+                    case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
+                        reflectiveCtrlPointX = 0;
+                        reflectiveCtrlPointY = 0;
+                        if (previousCmd == 'q' || previousCmd == 't'
+                                || previousCmd == 'Q' || previousCmd == 'T') {
+                            reflectiveCtrlPointX = currentX - ctrlPointX;
+                            reflectiveCtrlPointY = currentY - ctrlPointY;
+                        }
+                        path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+                                val[k + 0], val[k + 1]);
+                        ctrlPointX = currentX + reflectiveCtrlPointX;
+                        ctrlPointY = currentY + reflectiveCtrlPointY;
+                        currentX += val[k + 0];
+                        currentY += val[k + 1];
                         break;
-                    case 'T':
-                        reflectCtrl = (lastCmd == 'q' || lastCmd == 't' || lastCmd == 'Q' ||
-                                lastCmd == 'T');
-                        tempReflectedX = reflectCtrl ? 2 * cx - cpx : cx;
-                        tempReflectedY = reflectCtrl ? 2 * cy - cpy : cy;
-                        path.quadTo(tempReflectedX, tempReflectedY, val[k + 0], val[k + 1]);
-                        cx = val[k + 0];
-                        cy = val[k + 1];
-                        cpx = tempReflectedX;
-                        cpy = tempReflectedY;
+                    case 'T': // Draws a quadratic Bézier curve (reflective control point)
+                        reflectiveCtrlPointX = currentX;
+                        reflectiveCtrlPointY = currentY;
+                        if (previousCmd == 'q' || previousCmd == 't'
+                                || previousCmd == 'Q' || previousCmd == 'T') {
+                            reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
+                            reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
+                        }
+                        path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
+                                val[k + 0], val[k + 1]);
+                        ctrlPointX = reflectiveCtrlPointX;
+                        ctrlPointY = reflectiveCtrlPointY;
+                        currentX = val[k + 0];
+                        currentY = val[k + 1];
                         break;
-                    case 'a':
+                    case 'a': // Draws an elliptical arc
                         // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
-                        drawArc(path, cx, cy, val[k + 5] + cx, val[k + 6] + cy,
-                                val[k + 0], val[k + 1], val[k + 2], val[k + 3] != 0,
+                        drawArc(path,
+                                currentX,
+                                currentY,
+                                val[k + 5] + currentX,
+                                val[k + 6] + currentY,
+                                val[k + 0],
+                                val[k + 1],
+                                val[k + 2],
+                                val[k + 3] != 0,
                                 val[k + 4] != 0);
-                        cx += val[k + 5];
-                        cy += val[k + 6];
-                        cpx = cx;
-                        cpy = cy;
-
+                        currentX += val[k + 5];
+                        currentY += val[k + 6];
+                        ctrlPointX = currentX;
+                        ctrlPointY = currentY;
                         break;
-                    case 'A':
-                        drawArc(path, cx, cy, val[k + 5], val[k + 6], val[k + 0],
-                                val[k + 1], val[k + 2], val[k + 3] != 0,
+                    case 'A': // Draws an elliptical arc
+                        drawArc(path,
+                                currentX,
+                                currentY,
+                                val[k + 5],
+                                val[k + 6],
+                                val[k + 0],
+                                val[k + 1],
+                                val[k + 2],
+                                val[k + 3] != 0,
                                 val[k + 4] != 0);
-                        cx = val[k + 5];
-                        cy = val[k + 6];
-                        cpx = cx;
-                        cpy = cy;
+                        currentX = val[k + 5];
+                        currentY = val[k + 6];
+                        ctrlPointX = currentX;
+                        ctrlPointY = currentY;
                         break;
-
                 }
-                lastCmd = cmd;
+                previousCmd = cmd;
             }
-            current[0] = cx;
-            current[1] = cy;
-            current[2] = cpx;
-            current[3] = cpy;
-            current[4] = loopX;
-            current[5] = loopY;
-
+            current[0] = currentX;
+            current[1] = currentY;
+            current[2] = ctrlPointX;
+            current[3] = ctrlPointY;
+            current[4] = currentSegmentStartX;
+            current[5] = currentSegmentStartY;
         }
 
-        private static void drawArc(@NonNull Path2D p, float x0, float y0, float x1,
+        private static void drawArc(@NonNull Path_Delegate p, float x0, float y0, float x1,
                 float y1, float a, float b, float theta, boolean isMoreThanHalf,
                 boolean isPositiveArc) {
 
@@ -707,7 +790,7 @@ public class PathParser_Delegate {
          * @param start The start angle of the arc on the ellipse
          * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
          */
-        private static void arcToBezier(@NonNull Path2D p, double cx, double cy, double a,
+        private static void arcToBezier(@NonNull Path_Delegate p, double cx, double cy, double a,
                 double b, double e1x, double e1y, double theta, double start,
                 double sweep) {
             // Taken from equations at:
@@ -744,8 +827,12 @@ public class PathParser_Delegate {
                 double q2x = e2x - alpha * ep2x;
                 double q2y = e2y - alpha * ep2y;
 
-                p.curveTo((float) q1x, (float) q1y, (float) q2x, (float) q2y,
-                        (float) e2x, (float) e2y);
+                p.cubicTo((float) q1x,
+                        (float) q1y,
+                        (float) q2x,
+                        (float) q2y,
+                        (float) e2x,
+                        (float) e2y);
                 eta1 = eta2;
                 e1x = e2x;
                 e1y = e2y;
index d2103c8..97195e4 100644 (file)
@@ -349,7 +349,7 @@ public class IWindowManagerImpl implements IWindowManager {
     }
 
     @Override
-    public void notifyAppStopped(IBinder token) throws RemoteException {
+    public void notifyAppStopped(IBinder token, boolean stopped) throws RemoteException {
         // TODO Auto-generated method stub
     }
 
index fcfbad2..4039cdf 100644 (file)
@@ -24,7 +24,6 @@ import android.content.IntentFilter;
 import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.ContainerEncryptionParams;
 import android.content.pm.EphemeralApplicationInfo;
 import android.content.pm.FeatureInfo;
 import android.content.pm.IPackageDataObserver;
@@ -43,7 +42,6 @@ import android.content.pm.PermissionInfo;
 import android.content.pm.ProviderInfo;
 import android.content.pm.ResolveInfo;
 import android.content.pm.ServiceInfo;
-import android.content.pm.VerificationParams;
 import android.content.pm.VerifierDeviceIdentity;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
@@ -486,6 +484,12 @@ public class BridgePackageManager extends PackageManager {
     }
 
     @Override
+    public Drawable getManagedUserBadgedDrawable(Drawable drawable, Rect badgeLocation,
+        int badgeDensity) {
+        return null;
+    }
+
+    @Override
     public Drawable getUserBadgedIcon(Drawable icon, UserHandle user) {
         return null;
     }
@@ -555,40 +559,11 @@ public class BridgePackageManager extends PackageManager {
     }
 
     @Override
-    public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
-            int flags, String installerPackageName, Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-    }
-
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            IPackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-    }
-
-    @Override
     public void installPackage(Uri packageURI, PackageInstallObserver observer, int flags,
             String installerPackageName) {
     }
 
     @Override
-    public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,int flags,
-            String installerPackageName, int userId) {
-    }
-
-    @Override
-    public void installPackageWithVerification(Uri packageURI, PackageInstallObserver observer,
-            int flags, String installerPackageName, Uri verificationURI,
-            ContainerEncryptionParams encryptionParams) {
-    }
-
-    @Override
-    public void installPackageWithVerificationAndEncryption(Uri packageURI,
-            PackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
-    }
-
-    @Override
     public int installExistingPackage(String packageName) throws NameNotFoundException {
         return 0;
     }
index 99af226..53f1912 100644 (file)
@@ -60,6 +60,7 @@ import android.app.Fragment_Delegate;
 import android.graphics.Bitmap;
 import android.graphics.Bitmap_Delegate;
 import android.graphics.Canvas;
+import android.os.Looper;
 import android.preference.Preference_Delegate;
 import android.view.AttachInfo_Accessor;
 import android.view.BridgeInflater;
@@ -1398,6 +1399,14 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
     }
 
     public void dispose() {
+        boolean createdLooper = false;
+        if (Looper.myLooper() == null) {
+            // Detaching the root view from the window will try to stop any running animations.
+            // The stop method checks that it can run in the looper so, if there is no current
+            // looper, we create a temporary one to complete the shutdown.
+            Bridge.prepareThread();
+            createdLooper = true;
+        }
         AttachInfo_Accessor.detachFromWindow(mViewRoot);
         if (mCanvas != null) {
             mCanvas.release();
@@ -1412,5 +1421,9 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
         mImage = null;
         mViewRoot = null;
         mContentRoot = null;
+
+        if (createdLooper) {
+            Bridge.cleanupThread();
+        }
     }
 }
index 6b23da7..2726042 100644 (file)
@@ -335,7 +335,7 @@ public class Main {
                 .setNavigation(Navigation.NONAV);
 
         SessionParams params = getSessionParams(parser, customConfigGenerator,
-                layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+                layoutLibCallback, "Theme.Material.Light.NoActionBar.Fullscreen", false,
                 RenderingMode.V_SCROLL, 22);
 
         renderAndVerify(params, "expand_vert_layout.png");
@@ -348,7 +348,7 @@ public class Main {
         parser = new LayoutPullParser(APP_TEST_RES + "/layout/" +
                 "expand_horz_layout.xml");
         params = getSessionParams(parser, customConfigGenerator,
-                layoutLibCallback, "Theme.Material.NoActionBar.Fullscreen", false,
+                layoutLibCallback, "Theme.Material.Light.NoActionBar.Fullscreen", false,
                 RenderingMode.H_SCROLL, 22);
 
         renderAndVerify(params, "expand_horz_layout.png");
index b2b14b4..368b46b 100644 (file)
@@ -22,6 +22,6 @@
         </SOURCES>
       </library>
     </orderEntry>
-    <orderEntry type="library" scope="TEST" name="JUnit4" level="application" />
+    <orderEntry type="library" scope="TEST" name="junit" level="project" />
   </component>
 </module>
\ No newline at end of file
index 8a23e4b..8c3bd2f 100644 (file)
@@ -269,6 +269,7 @@ public final class CreateInfo implements ICreateInfo {
         "android.graphics.SweepGradient",
         "android.graphics.Typeface",
         "android.graphics.Xfermode",
+        "android.graphics.drawable.VectorDrawable",
         "android.os.SystemClock",
         "android.os.SystemProperties",
         "android.text.AndroidBidi",
@@ -321,7 +322,12 @@ public final class CreateInfo implements ICreateInfo {
             "org.kxml2.io.KXmlParser"
         };
 
+    /**
+     * List of fields for which we will update the visibility to be public. This is sometimes
+     * needed when access from the delegate classes is needed.
+     */
     private final static String[] PROMOTED_FIELDS = new String[] {
+        "android.graphics.drawable.VectorDrawable#mVectorState",
         "android.view.Choreographer#mLastFrameTimeNanos"
     };
 
index 0912fb1..afaa399 100644 (file)
@@ -53,12 +53,10 @@ public class DelegateClassAdapterTest {
 
     private MockLog mLog;
 
-    private static final String NATIVE_CLASS_NAME = ClassWithNative.class.getCanonicalName();
-    private static final String OUTER_CLASS_NAME = OuterClass.class.getCanonicalName();
-    private static final String INNER_CLASS_NAME = OuterClass.class.getCanonicalName() + "$" +
-                                                   InnerClass.class.getSimpleName();
-    private static final String STATIC_INNER_CLASS_NAME =
-            OuterClass.class.getCanonicalName() + "$" + StaticInnerClass.class.getSimpleName();
+    private static final String NATIVE_CLASS_NAME = ClassWithNative.class.getName();
+    private static final String OUTER_CLASS_NAME = OuterClass.class.getName();
+    private static final String INNER_CLASS_NAME = InnerClass.class.getName();
+    private static final String STATIC_INNER_CLASS_NAME = StaticInnerClass.class.getName();
 
     @Before
     public void setUp() throws Exception {
@@ -69,12 +67,12 @@ public class DelegateClassAdapterTest {
     /**
      * Tests that a class not being modified still works.
      */
-    @SuppressWarnings("unchecked")
     @Test
     public void testNoOp() throws Throwable {
         // create an instance of the class that will be modified
         // (load the class in a distinct class loader so that we can trash its definition later)
         ClassLoader cl1 = new ClassLoader(this.getClass().getClassLoader()) { };
+        @SuppressWarnings("unchecked")
         Class<ClassWithNative> clazz1 = (Class<ClassWithNative>) cl1.loadClass(NATIVE_CLASS_NAME);
         ClassWithNative instance1 = clazz1.newInstance();
         assertEquals(42, instance1.add(20, 22));
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/StubMethodAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/StubMethodAdapterTest.java
new file mode 100644 (file)
index 0000000..3db3e23
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create;
+
+import com.android.tools.layoutlib.create.dataclass.StubClass;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+import java.lang.reflect.Method;
+import java.util.function.BiPredicate;
+import java.util.function.Consumer;
+
+import static org.junit.Assert.*;
+
+public class StubMethodAdapterTest {
+
+    private static final String STUB_CLASS_NAME = StubClass.class.getName();
+
+    /**
+     * Load a dummy class, stub one of its method and ensure that the modified class works as
+     * intended.
+     */
+    @Test
+    public void testBoolean() throws Exception {
+        final String methodName = "returnTrue";
+        // First don't change the method and assert that it returns true
+        testBoolean((name, type) -> false, Assert::assertTrue, methodName);
+        // Change the method now and assert that it returns false.
+        testBoolean((name, type) -> methodName.equals(name) &&
+                Type.BOOLEAN_TYPE.equals(type.getReturnType()), Assert::assertFalse, methodName);
+    }
+
+    /**
+     * @param methodPredicate tests if the method should be replaced
+     */
+    private void testBoolean(BiPredicate<String, Type> methodPredicate, Consumer<Boolean> assertion,
+            String methodName) throws Exception {
+        ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+        // Always rename the class to avoid conflict with the original class.
+        String newClassName = STUB_CLASS_NAME + '_';
+        new ClassReader(STUB_CLASS_NAME).accept(
+                new ClassAdapter(newClassName, writer, methodPredicate), 0);
+        MyClassLoader myClassLoader = new MyClassLoader(newClassName, writer.toByteArray());
+        Class<?> aClass = myClassLoader.loadClass(newClassName);
+        assertTrue("StubClass not loaded by the classloader. Likely a bug in the test.",
+                myClassLoader.findClassCalled);
+        Method method = aClass.getMethod(methodName);
+        Object o = aClass.newInstance();
+        assertion.accept((Boolean) method.invoke(o));
+    }
+
+    private static class ClassAdapter extends ClassVisitor {
+
+        private final String mClassName;
+        private final BiPredicate<String, Type> mMethodPredicate;
+
+        private ClassAdapter(String className, ClassVisitor cv,
+                BiPredicate<String, Type> methodPredicate) {
+            super(Main.ASM_VERSION, cv);
+            mClassName = className.replace('.', '/');
+            mMethodPredicate = methodPredicate;
+        }
+
+        @Override
+        public void visit(int version, int access, String name, String signature, String superName,
+                String[] interfaces) {
+            super.visit(version, access, mClassName, signature, superName,
+                    interfaces);
+        }
+
+        @Override
+        public MethodVisitor visitMethod(int access, String name, String desc, String signature,
+                String[] exceptions) {
+            // Copied partly from
+            // com.android.tools.layoutlib.create.DelegateClassAdapter.visitMethod()
+            // but not generating the _Original method.
+            boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
+            boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
+            MethodVisitor originalMethod =
+                    super.visitMethod(access, name, desc, signature, exceptions);
+            Type descriptor = Type.getMethodType(desc);
+            if (mMethodPredicate.test(name, descriptor)) {
+                String methodSignature = mClassName + "#" + name;
+                String invokeSignature = methodSignature + desc;
+                return new StubMethodAdapter(originalMethod, name, descriptor.getReturnType(),
+                        invokeSignature, isStatic, isNative);
+            }
+            return originalMethod;
+        }
+    }
+
+    private static class MyClassLoader extends ClassLoader {
+        private final String mName;
+        private final byte[] mBytes;
+        private boolean findClassCalled;
+
+        private MyClassLoader(String name, byte[] bytes) {
+            mName = name;
+            mBytes = bytes;
+        }
+
+        @Override
+        protected Class<?> findClass(String name) throws ClassNotFoundException {
+            if (name.equals(mName)) {
+                findClassCalled = true;
+                return defineClass(name, mBytes, 0, mBytes.length);
+            }
+            return super.findClass(name);
+        }
+    }
+}
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 The Android Open Source Project
+ * Copyright (C) 2016 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.
  * limitations under the License.
  */
 
-package android.hardware;
+package com.android.tools.layoutlib.create.dataclass;
 
-/** @hide */
-interface ICameraServiceListener
-{
-    /**
-     * Keep up-to-date with frameworks/av/include/camera/ICameraServiceListener.h
-     */
-    void onStatusChanged(int status, int cameraId);
+import com.android.tools.layoutlib.create.StubMethodAdapterTest;
 
-    void onTorchStatusChanged(int status, String cameraId);
+/**
+ * Used by {@link StubMethodAdapterTest}
+ */
+@SuppressWarnings("unused")
+public class StubClass {
+
+    public boolean returnTrue() {
+        return true;
+    }
 }
index 59416b8..13abaff 100644 (file)
@@ -300,7 +300,7 @@ public class RttManager {
                 try {
                     mRttCapabilities = mService.getRttCapabilities();
                 } catch (RemoteException e) {
-                    Log.e(TAG, "Can not get RTT Capabilities");
+                    throw e.rethrowFromSystemServer();
                 }
             }
             return mRttCapabilities;
@@ -1132,7 +1132,7 @@ public class RttManager {
                     Log.d(TAG, "Get the messenger from " + mService);
                     messenger = mService.getMessenger();
                 } catch (RemoteException e) {
-                    /* do nothing */
+                    throw e.rethrowFromSystemServer();
                 } catch (SecurityException e) {
                     /* do nothing */
                 }
index ddd8f43..7dc8049 100644 (file)
@@ -1357,6 +1357,7 @@ public class WifiConfiguration implements Parcelable {
                 append(" PROVIDER-NAME: ").append(this.providerFriendlyName).
                 append(" BSSID: ").append(this.BSSID).append(" FQDN: ").append(this.FQDN)
                 .append(" PRIO: ").append(this.priority)
+                .append(" HIDDEN: ").append(this.hiddenSSID)
                 .append('\n');
 
 
index 4921073..a5bfd3c 100644 (file)
@@ -39,9 +39,9 @@ import android.os.WorkSource;
 import android.util.Log;
 import android.util.SparseArray;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.AsyncChannel;
 import com.android.internal.util.Protocol;
+import com.android.server.net.NetworkPinner;
 
 import java.net.InetAddress;
 import java.util.ArrayList;
@@ -678,11 +678,6 @@ public class WifiManager {
     private static int sThreadRefCount;
     private static HandlerThread sHandlerThread;
 
-    @GuardedBy("sCM")
-    // TODO: Introduce refcounting and make this a per-process static callback, instead of a
-    // per-WifiManager callback.
-    private PinningNetworkCallback mNetworkCallback;
-
     /**
      * Create a new WifiManager instance.
      * Applications will almost always want to use
@@ -723,8 +718,7 @@ public class WifiManager {
         try {
             return mService.getConfiguredNetworks();
         } catch (RemoteException e) {
-            Log.w(TAG, "Caught RemoteException trying to get configured networks: " + e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -734,7 +728,7 @@ public class WifiManager {
         try {
             return mService.getPrivilegedConfiguredNetworks();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -744,7 +738,7 @@ public class WifiManager {
         try {
             return mService.getConnectionStatistics();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -758,7 +752,7 @@ public class WifiManager {
         try {
             return mService.getMatchingWifiConfig(scanResult);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -818,7 +812,7 @@ public class WifiManager {
         try {
             return mService.addOrUpdateNetwork(config);
         } catch (RemoteException e) {
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -832,7 +826,7 @@ public class WifiManager {
         try {
             return mService.addPasspointManagementObject(mo);
         } catch (RemoteException e) {
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -848,7 +842,7 @@ public class WifiManager {
         try {
             return mService.modifyPasspointManagementObject(fqdn, mos);
         } catch (RemoteException e) {
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -862,6 +856,7 @@ public class WifiManager {
         try {
             mService.queryPasspointIcon(bssid, fileName);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -875,7 +870,7 @@ public class WifiManager {
         try {
             return mService.matchProviderWithCurrentNetwork(fqdn);
         } catch (RemoteException e) {
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -889,28 +884,11 @@ public class WifiManager {
         try {
             mService.deauthenticateNetwork(holdoff, ess);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
     /**
-     * Sets whether or not the given network is metered from a network policy
-     * point of view. A network should be classified as metered when the user is
-     * sensitive to heavy data usage on that connection due to monetary costs,
-     * data limitations or battery/performance issues. A typical example would
-     * be a wifi connection where the user was being charged for usage.
-     * @param netId the integer that identifies the network configuration
-     * to the supplicant.
-     * @param isMetered True to mark the network as metered.
-     * @return {@code true} if the operation succeeded.
-     * @hide
-     */
-    @SystemApi
-    public boolean setMetered(int netId, boolean isMetered) {
-        // TODO(jjoslin): Implement
-        return false;
-    }
-
-    /**
      * Remove the specified network from the list of configured networks.
      * This may result in the asynchronous delivery of state change
      * events.
@@ -922,7 +900,7 @@ public class WifiManager {
         try {
             return mService.removeNetwork(netId);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -955,18 +933,22 @@ public class WifiManager {
     public boolean enableNetwork(int netId, boolean disableOthers) {
         final boolean pin = disableOthers && mTargetSdkVersion < Build.VERSION_CODES.LOLLIPOP;
         if (pin) {
-            registerPinningNetworkCallback();
+            NetworkRequest request = new NetworkRequest.Builder()
+                    .clearCapabilities()
+                    .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
+                    .build();
+            NetworkPinner.pin(mContext, request);
         }
 
         boolean success;
         try {
             success = mService.enableNetwork(netId, disableOthers);
         } catch (RemoteException e) {
-            success = false;
+            throw e.rethrowFromSystemServer();
         }
 
         if (pin && !success) {
-            unregisterPinningNetworkCallback();
+            NetworkPinner.unpin();
         }
 
         return success;
@@ -983,7 +965,7 @@ public class WifiManager {
         try {
             return mService.disableNetwork(netId);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -997,7 +979,7 @@ public class WifiManager {
             mService.disconnect();
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1012,7 +994,7 @@ public class WifiManager {
             mService.reconnect();
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1027,7 +1009,7 @@ public class WifiManager {
             mService.reassociate();
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1042,7 +1024,7 @@ public class WifiManager {
         try {
             return mService.pingSupplicant();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1090,7 +1072,7 @@ public class WifiManager {
         try {
             return mService.getSupportedFeatures();
         } catch (RemoteException e) {
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1216,9 +1198,8 @@ public class WifiManager {
                 return mService.reportActivityInfo();
             }
         } catch (RemoteException e) {
-            Log.e(TAG, "getControllerActivityEnergyInfo: " + e);
+            throw e.rethrowFromSystemServer();
         }
-        return null;
     }
 
     /**
@@ -1232,7 +1213,7 @@ public class WifiManager {
             mService.startScan(null, null);
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1243,7 +1224,7 @@ public class WifiManager {
             mService.startScan(null, workSource);
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1299,7 +1280,7 @@ public class WifiManager {
         try {
             return mService.getWpsNfcConfigurationToken(netId);
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1311,7 +1292,7 @@ public class WifiManager {
         try {
             return mService.getConnectionInfo();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1328,7 +1309,7 @@ public class WifiManager {
         try {
             return mService.getScanResults(mContext.getOpPackageName());
         } catch (RemoteException e) {
-            return new ArrayList<ScanResult>();
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1344,7 +1325,7 @@ public class WifiManager {
         try {
             return mService.isScanAlwaysAvailable();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1361,7 +1342,7 @@ public class WifiManager {
         try {
             return mService.saveConfiguration();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1375,7 +1356,9 @@ public class WifiManager {
     public void setCountryCode(String country, boolean persist) {
         try {
             mService.setCountryCode(country, persist);
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -1387,9 +1370,9 @@ public class WifiManager {
     public String getCountryCode() {
        try {
            String country = mService.getCountryCode();
-           return(country);
+           return country;
        } catch (RemoteException e) {
-           return null;
+           throw e.rethrowFromSystemServer();
        }
     }
 
@@ -1405,7 +1388,9 @@ public class WifiManager {
     public void setFrequencyBand(int band, boolean persist) {
         try {
             mService.setFrequencyBand(band, persist);
-        } catch (RemoteException e) { }
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
     }
 
     /**
@@ -1421,7 +1406,7 @@ public class WifiManager {
         try {
             return mService.getFrequencyBand();
         } catch (RemoteException e) {
-            return -1;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1434,7 +1419,7 @@ public class WifiManager {
         try {
             return mService.isDualBandSupported();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1447,7 +1432,7 @@ public class WifiManager {
         try {
             return mService.getDhcpInfo();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1461,7 +1446,7 @@ public class WifiManager {
         try {
             return mService.setWifiEnabled(enabled);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1476,7 +1461,7 @@ public class WifiManager {
         try {
             return mService.getWifiEnabledState();
         } catch (RemoteException e) {
-            return WIFI_STATE_UNKNOWN;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1553,7 +1538,7 @@ public class WifiManager {
             mService.setWifiApEnabled(wifiConfig, enabled);
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1571,7 +1556,7 @@ public class WifiManager {
         try {
             return mService.getWifiApEnabledState();
         } catch (RemoteException e) {
-            return WIFI_AP_STATE_FAILED;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1598,7 +1583,7 @@ public class WifiManager {
         try {
             return mService.getWifiApConfiguration();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1612,8 +1597,7 @@ public class WifiManager {
         try {
             return mService.buildWifiConfig(uriString, mimeType, data);
         } catch (RemoteException e) {
-            Log.w(TAG, "Caught RemoteException trying to build wifi config: " + e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1629,7 +1613,7 @@ public class WifiManager {
             mService.setWifiApConfiguration(wifiConfig);
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1646,7 +1630,7 @@ public class WifiManager {
             mService.addToBlacklist(bssid);
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1663,7 +1647,7 @@ public class WifiManager {
             mService.clearBlacklist();
             return true;
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1692,7 +1676,7 @@ public class WifiManager {
         try {
             mService.enableTdls(remoteIPAddress.getHostAddress(), enable);
         } catch (RemoteException e) {
-            // Just ignore the exception
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1706,7 +1690,7 @@ public class WifiManager {
         try {
             mService.enableTdlsWithMacAddress(remoteMacAddress, enable);
         } catch (RemoteException e) {
-            // Just ignore the exception
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2012,100 +1996,6 @@ public class WifiManager {
                 "No permission to access and change wifi or a bad initialization");
     }
 
-    private void initConnectivityManager() {
-        // TODO: what happens if an app calls a WifiManager API before ConnectivityManager is
-        // registered? Can we fix this by starting ConnectivityService before WifiService?
-        if (sCM == null) {
-            sCM = (ConnectivityManager) mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
-            if (sCM == null) {
-                throw new IllegalStateException("Bad luck, ConnectivityService not started.");
-            }
-        }
-    }
-
-    /**
-     * A NetworkCallback that pins the process to the first wifi network to connect.
-     *
-     * We use this to maintain compatibility with pre-M apps that call WifiManager.enableNetwork()
-     * to connect to a Wi-Fi network that has no Internet access, and then assume that they will be
-     * able to use that network because it's the system default.
-     *
-     * In order to maintain compatibility with apps that call setProcessDefaultNetwork themselves,
-     * we try not to set the default network unless they have already done so, and we try not to
-     * clear the default network unless we set it ourselves.
-     *
-     * This should maintain behaviour that's compatible with L, which would pin the whole system to
-     * any wifi network that was created via enableNetwork(..., true) until that network
-     * disconnected.
-     *
-     * Note that while this hack allows network traffic to flow, it is quite limited. For example:
-     *
-     * 1. setProcessDefaultNetwork only affects this process, so:
-     *    - Any subprocesses spawned by this process will not be pinned to Wi-Fi.
-     *    - If this app relies on any other apps on the device also being on Wi-Fi, that won't work
-     *      either, because other apps on the device will not be pinned.
-     * 2. The behaviour of other APIs is not modified. For example:
-     *    - getActiveNetworkInfo will return the system default network, not Wi-Fi.
-     *    - There will be no CONNECTIVITY_ACTION broadcasts about TYPE_WIFI.
-     *    - getProcessDefaultNetwork will not return null, so if any apps are relying on that, they
-     *      will be surprised as well.
-     */
-    private class PinningNetworkCallback extends NetworkCallback {
-        private Network mPinnedNetwork;
-
-        @Override
-        public void onPreCheck(Network network) {
-            if (sCM.getProcessDefaultNetwork() == null && mPinnedNetwork == null) {
-                sCM.setProcessDefaultNetwork(network);
-                mPinnedNetwork = network;
-                Log.d(TAG, "Wifi alternate reality enabled on network " + network);
-            }
-        }
-
-        @Override
-        public void onLost(Network network) {
-            if (network.equals(mPinnedNetwork) && network.equals(sCM.getProcessDefaultNetwork())) {
-                sCM.setProcessDefaultNetwork(null);
-                Log.d(TAG, "Wifi alternate reality disabled on network " + network);
-                mPinnedNetwork = null;
-                unregisterPinningNetworkCallback();
-            }
-        }
-    }
-
-    private void registerPinningNetworkCallback() {
-        initConnectivityManager();
-        synchronized (sCM) {
-            if (mNetworkCallback == null) {
-                // TODO: clear all capabilities.
-                NetworkRequest request = new NetworkRequest.Builder()
-                        .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)
-                        .removeCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
-                        .build();
-                mNetworkCallback = new PinningNetworkCallback();
-                try {
-                    sCM.registerNetworkCallback(request, mNetworkCallback);
-                } catch (SecurityException e) {
-                    Log.d(TAG, "Failed to register network callback", e);
-                }
-            }
-        }
-    }
-
-    private void unregisterPinningNetworkCallback() {
-        initConnectivityManager();
-        synchronized (sCM) {
-            if (mNetworkCallback != null) {
-                try {
-                    sCM.unregisterNetworkCallback(mNetworkCallback);
-                } catch (SecurityException e) {
-                    Log.d(TAG, "Failed to unregister network callback", e);
-                }
-                mNetworkCallback = null;
-            }
-        }
-    }
-
     /**
      * Connect to a network with the given configuration. The network also
      * gets added to the supplicant configuration.
@@ -2219,6 +2109,7 @@ public class WifiManager {
         try {
             mService.disableEphemeralNetwork(SSID);
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2259,7 +2150,7 @@ public class WifiManager {
         try {
             return mService.getWifiServiceMessenger();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         } catch (SecurityException e) {
             return null;
         }
@@ -2274,7 +2165,7 @@ public class WifiManager {
         try {
             return mService.getConfigFile();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2340,7 +2231,8 @@ public class WifiManager {
                             }
                             mActiveLockCount++;
                         }
-                    } catch (RemoteException ignore) {
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                     mHeld = true;
                 }
@@ -2367,7 +2259,8 @@ public class WifiManager {
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
-                    } catch (RemoteException ignore) {
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                     mHeld = false;
                 }
@@ -2427,6 +2320,7 @@ public class WifiManager {
                     try {
                         mService.updateWifiLockWorkSource(mBinder, mWorkSource);
                     } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             }
@@ -2456,7 +2350,8 @@ public class WifiManager {
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
-                    } catch (RemoteException ignore) {
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                 }
             }
@@ -2572,7 +2467,8 @@ public class WifiManager {
                             }
                             mActiveLockCount++;
                         }
-                    } catch (RemoteException ignore) {
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                     mHeld = true;
                 }
@@ -2611,7 +2507,8 @@ public class WifiManager {
                         synchronized (WifiManager.this) {
                             mActiveLockCount--;
                         }
-                    } catch (RemoteException ignore) {
+                    } catch (RemoteException e) {
+                        throw e.rethrowFromSystemServer();
                     }
                     mHeld = false;
                 }
@@ -2685,7 +2582,7 @@ public class WifiManager {
         try {
             return mService.isMulticastEnabled();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2698,7 +2595,7 @@ public class WifiManager {
             mService.initializeMulticastFiltering();
             return true;
         } catch (RemoteException e) {
-             return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2736,7 +2633,7 @@ public class WifiManager {
         try {
             return mService.getVerboseLoggingLevel();
         } catch (RemoteException e) {
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2748,7 +2645,7 @@ public class WifiManager {
         try {
             mService.enableAggressiveHandover(enabled);
         } catch (RemoteException e) {
-
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2761,7 +2658,7 @@ public class WifiManager {
         try {
             return mService.getAggressiveHandover();
         } catch (RemoteException e) {
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2773,7 +2670,7 @@ public class WifiManager {
         try {
             mService.setAllowScansWithTraffic(enabled);
         } catch (RemoteException e) {
-
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2785,7 +2682,7 @@ public class WifiManager {
         try {
             return mService.getAllowScansWithTraffic();
         } catch (RemoteException e) {
-            return 0;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2798,6 +2695,7 @@ public class WifiManager {
         try {
             mService.factoryReset();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2810,7 +2708,7 @@ public class WifiManager {
         try {
             return mService.getCurrentNetwork();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2824,7 +2722,7 @@ public class WifiManager {
         try {
             return mService.enableAutoJoinWhenAssociated(enabled);
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2836,7 +2734,7 @@ public class WifiManager {
         try {
             return mService.getEnableAutoJoinWhenAssociated();
         } catch (RemoteException e) {
-            return false;
+            throw e.rethrowFromSystemServer();
         }
     }
     /**
@@ -2847,7 +2745,7 @@ public class WifiManager {
         try {
             mService.setHalBasedAutojoinOffload(enabled);
         } catch (RemoteException e) {
-
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -2859,7 +2757,7 @@ public class WifiManager {
         try {
             return mService.getHalBasedAutojoinOffload();
         } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
-        return 0;
     }
 }
index 69e179d..97dd985 100644 (file)
@@ -192,6 +192,11 @@ public class WifiScanner {
          * for a given period
          */
         public int stepCount;
+        /**
+         * Flag to indicate if the scan settings are targeted for PNO scan.
+         * {@hide}
+         */
+        public boolean isPnoScan;
 
         /** Implement the Parcelable interface {@hide} */
         public int describeContents() {
@@ -207,6 +212,7 @@ public class WifiScanner {
             dest.writeInt(maxScansToCache);
             dest.writeInt(maxPeriodInMs);
             dest.writeInt(stepCount);
+            dest.writeInt(isPnoScan ? 1 : 0);
 
             if (channels != null) {
                 dest.writeInt(channels.length);
@@ -234,6 +240,7 @@ public class WifiScanner {
                         settings.maxScansToCache = in.readInt();
                         settings.maxPeriodInMs = in.readInt();
                         settings.stepCount = in.readInt();
+                        settings.isPnoScan = in.readInt() == 1;
                         int num_channels = in.readInt();
                         settings.channels = new ChannelSpec[num_channels];
                         for (int i = 0; i < num_channels; i++) {
@@ -436,6 +443,158 @@ public class WifiScanner {
                 };
     }
 
+    /** {@hide} */
+    public static final String PNO_PARAMS_PNO_SETTINGS_KEY = "PnoSettings";
+    /** {@hide} */
+    public static final String PNO_PARAMS_SCAN_SETTINGS_KEY = "ScanSettings";
+    /**
+     * PNO scan configuration parameters to be sent to {@link #startPnoScan}.
+     * Note: This structure needs to be in sync with |wifi_epno_params| struct in gscan HAL API.
+     * {@hide}
+     */
+    public static class PnoSettings implements Parcelable {
+        /**
+         * Pno network to be added to the PNO scan filtering.
+         * {@hide}
+         */
+        public static class PnoNetwork {
+            /*
+             * Pno flags bitmask to be set in {@link #PnoNetwork.flags}
+             */
+            /** Whether directed scan needs to be performed (for hidden SSIDs) */
+            public static final byte FLAG_DIRECTED_SCAN = (1 << 0);
+            /** Whether PNO event shall be triggered if the network is found on A band */
+            public static final byte FLAG_A_BAND = (1 << 1);
+            /** Whether PNO event shall be triggered if the network is found on G band */
+            public static final byte FLAG_G_BAND = (1 << 2);
+            /**
+             * Whether strict matching is required
+             * If required then the firmware must store the network's SSID and not just a hash
+             */
+            public static final byte FLAG_STRICT_MATCH = (1 << 3);
+            /**
+             * If this SSID should be considered the same network as the currently connected
+             * one for scoring.
+             */
+            public static final byte FLAG_SAME_NETWORK = (1 << 4);
+
+            /*
+             * Code for matching the beacon AUTH IE - additional codes. Bitmask to be set in
+             * {@link #PnoNetwork.authBitField}
+             */
+            /** Open Network */
+            public static final byte AUTH_CODE_OPEN = (1 << 0);
+            /** WPA_PSK or WPA2PSK */
+            public static final byte AUTH_CODE_PSK = (1 << 1);
+            /** any EAPOL */
+            public static final byte AUTH_CODE_EAPOL = (1 << 2);
+
+            /** SSID of the network */
+            public String ssid;
+            /** Network ID in wpa_supplicant */
+            public int networkId;
+            /** Assigned priority for the network */
+            public int priority;
+            /** Bitmask of the FLAG_XXX */
+            public byte flags;
+            /** Bitmask of the ATUH_XXX */
+            public byte authBitField;
+
+            /**
+             * default constructor for PnoNetwork
+             */
+            public PnoNetwork(String ssid) {
+                this.ssid = ssid;
+                flags = 0;
+                authBitField = 0;
+            }
+        }
+
+        /** Connected vs Disconnected PNO flag {@hide} */
+        public boolean isConnected;
+        /** Minimum 5GHz RSSI for a BSSID to be considered */
+        public int min5GHzRssi;
+        /** Minimum 2.4GHz RSSI for a BSSID to be considered */
+        public int min24GHzRssi;
+        /** Maximum score that a network can have before bonuses */
+        public int initialScoreMax;
+        /**
+         *  Only report when there is a network's score this much higher
+         *  than the current connection.
+         */
+        public int currentConnectionBonus;
+        /** score bonus for all networks with the same network flag */
+        public int sameNetworkBonus;
+        /** score bonus for networks that are not open */
+        public int secureBonus;
+        /** 5GHz RSSI score bonus (applied to all 5GHz networks) */
+        public int band5GHzBonus;
+        /** Pno Network filter list */
+        public PnoNetwork[] networkList;
+
+        /** Implement the Parcelable interface {@hide} */
+        public int describeContents() {
+            return 0;
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public void writeToParcel(Parcel dest, int flags) {
+            dest.writeInt(isConnected ? 1 : 0);
+            dest.writeInt(min5GHzRssi);
+            dest.writeInt(min24GHzRssi);
+            dest.writeInt(initialScoreMax);
+            dest.writeInt(currentConnectionBonus);
+            dest.writeInt(sameNetworkBonus);
+            dest.writeInt(secureBonus);
+            dest.writeInt(band5GHzBonus);
+            if (networkList != null) {
+                dest.writeInt(networkList.length);
+                for (int i = 0; i < networkList.length; i++) {
+                    dest.writeString(networkList[i].ssid);
+                    dest.writeInt(networkList[i].networkId);
+                    dest.writeInt(networkList[i].priority);
+                    dest.writeByte(networkList[i].flags);
+                    dest.writeByte(networkList[i].authBitField);
+                }
+            } else {
+                dest.writeInt(0);
+            }
+        }
+
+        /** Implement the Parcelable interface {@hide} */
+        public static final Creator<PnoSettings> CREATOR =
+                new Creator<PnoSettings>() {
+                    public PnoSettings createFromParcel(Parcel in) {
+                        PnoSettings settings = new PnoSettings();
+                        settings.isConnected = in.readInt() == 1;
+                        settings.min5GHzRssi = in.readInt();
+                        settings.min24GHzRssi = in.readInt();
+                        settings.initialScoreMax = in.readInt();
+                        settings.currentConnectionBonus = in.readInt();
+                        settings.sameNetworkBonus = in.readInt();
+                        settings.secureBonus = in.readInt();
+                        settings.band5GHzBonus = in.readInt();
+                        int numNetworks = in.readInt();
+                        settings.networkList = new PnoNetwork[numNetworks];
+                        for (int i = 0; i < numNetworks; i++) {
+                            String ssid = in.readString();
+                            PnoNetwork network = new PnoNetwork(ssid);
+                            network.networkId = in.readInt();
+                            network.priority = in.readInt();
+                            network.flags = in.readByte();
+                            network.authBitField = in.readByte();
+                            settings.networkList[i] = network;
+                        }
+                        return settings;
+                    }
+
+                    public PnoSettings[] newArray(int size) {
+                        return new PnoSettings[size];
+                    }
+                };
+
+    }
+
     /**
      * interface to get scan events on; specify this on {@link #startBackgroundScan} or
      * {@link #startScan}
@@ -456,6 +615,18 @@ public class WifiScanner {
         public void onFullResult(ScanResult fullScanResult);
     }
 
+    /**
+     * interface to get PNO scan events on; specify this on {@link #startDisconnectedPnoScan} and
+     * {@link #startConnectedPnoScan}.
+     * {@hide}
+     */
+    public interface PnoScanListener extends ScanListener {
+        /**
+         * Invoked when one of the PNO networks are found in scan results.
+         */
+        void onPnoNetworkFound(ScanResult[] results);
+    }
+
     /** start wifi scan in background
      * @param settings specifies various parameters for the scan; for more information look at
      * {@link ScanSettings}
@@ -521,6 +692,75 @@ public class WifiScanner {
         sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
     }
 
+    private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
+        // Bundle up both the settings and send it across.
+        Bundle pnoParams = new Bundle();
+        if (pnoParams == null) return;
+        // Set the PNO scan flag.
+        scanSettings.isPnoScan = true;
+        pnoParams.putParcelable(PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
+        pnoParams.putParcelable(PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings);
+        sAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
+    }
+    /**
+     * Start wifi connected PNO scan
+     * @param scanSettings specifies various parameters for the scan; for more information look at
+     * {@link ScanSettings}
+     * @param pnoSettings specifies various parameters for PNO; for more information look at
+     * {@link PnoSettings}
+     * @param listener specifies the object to report events to. This object is also treated as a
+     *                 key for this scan, and must also be specified to cancel the scan. Multiple
+     *                 scans should also not share this object.
+     * {@hide}
+     */
+    public void startConnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
+            PnoScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
+        validateChannel();
+        pnoSettings.isConnected = true;
+        startPnoScan(scanSettings, pnoSettings, key);
+    }
+    /**
+     * Start wifi disconnected PNO scan
+     * @param scanSettings specifies various parameters for the scan; for more information look at
+     * {@link ScanSettings}
+     * @param pnoSettings specifies various parameters for PNO; for more information look at
+     * {@link PnoSettings}
+     * @param listener specifies the object to report events to. This object is also treated as a
+     *                 key for this scan, and must also be specified to cancel the scan. Multiple
+     *                 scans should also not share this object.
+     * {@hide}
+     */
+    public void startDisconnectedPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings,
+            PnoScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        Preconditions.checkNotNull(pnoSettings, "pnoSettings cannot be null");
+        int key = addListener(listener);
+        if (key == INVALID_KEY) return;
+        validateChannel();
+        pnoSettings.isConnected = false;
+        startPnoScan(scanSettings, pnoSettings, key);
+    }
+    /**
+     * Stop an ongoing wifi PNO scan
+     * @param pnoSettings specifies various parameters for PNO; for more information look at
+     * {@link PnoSettings}
+     * @param listener specifies which scan to cancel; must be same object as passed in {@link
+     *  #startPnoScan}
+     * TODO(rpius): Check if we can remove pnoSettings param in stop.
+     * {@hide}
+     */
+    public void stopPnoScan(PnoSettings pnoSettings, ScanListener listener) {
+        Preconditions.checkNotNull(listener, "listener cannot be null");
+        int key = removeListener(listener);
+        if (key == INVALID_KEY) return;
+        validateChannel();
+        sAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key, pnoSettings);
+    }
+
     /** specifies information about an access point of interest */
     public static class BssidInfo {
         /** bssid of the access point; in XX:XX:XX:XX:XX:XX format */
@@ -824,6 +1064,12 @@ public class WifiScanner {
     public static final int CMD_STOP_SINGLE_SCAN            = BASE + 22;
     /** @hide */
     public static final int CMD_SINGLE_SCAN_COMPLETED       = BASE + 23;
+    /** @hide */
+    public static final int CMD_START_PNO_SCAN              = BASE + 24;
+    /** @hide */
+    public static final int CMD_STOP_PNO_SCAN               = BASE + 25;
+    /** @hide */
+    public static final int CMD_PNO_NETWORK_FOUND           = BASE + 26;
 
     private Context mContext;
     private IWifiScanner mService;
@@ -1110,6 +1356,10 @@ public class WifiScanner {
                     if (DBG) Log.d(TAG, "removing listener for single scan");
                     removeListener(msg.arg2);
                     break;
+                case CMD_PNO_NETWORK_FOUND:
+                    ((PnoScanListener) listener).onPnoNetworkFound(
+                            ((ParcelableScanResults) msg.obj).getResults());
+                    return;
                 default:
                     if (DBG) Log.d(TAG, "Ignoring message " + msg.what);
                     return;
index 667c4b1..1b78beb 100644 (file)
@@ -75,7 +75,7 @@ public class WifiNanManager {
             }
             mService.connect(mBinder, listener.callback, events);
         } catch (RemoteException e) {
-            Log.w(TAG, "connect RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -94,7 +94,7 @@ public class WifiNanManager {
             mService.disconnect(mBinder);
             mBinder = null;
         } catch (RemoteException e) {
-            Log.w(TAG, "disconnect RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -116,7 +116,7 @@ public class WifiNanManager {
         try {
             mService.requestConfig(configRequest);
         } catch (RemoteException e) {
-            Log.w(TAG, "requestConfig RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -173,8 +173,7 @@ public class WifiNanManager {
             if (DBG) Log.d(TAG, "publish: session created - sessionId=" + sessionId);
             mService.publish(sessionId, publishData, publishSettings);
         } catch (RemoteException e) {
-            Log.w(TAG, "createSession/publish RemoteException: " + e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
 
         return new WifiNanPublishSession(this, sessionId);
@@ -200,7 +199,7 @@ public class WifiNanManager {
         try {
             mService.publish(sessionId, publishData, publishSettings);
         } catch (RemoteException e) {
-            Log.w(TAG, "publish RemoteException: " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
     /**
@@ -256,8 +255,7 @@ public class WifiNanManager {
             if (DBG) Log.d(TAG, "subscribe: session created - sessionId=" + sessionId);
             mService.subscribe(sessionId, subscribeData, subscribeSettings);
         } catch (RemoteException e) {
-            Log.w(TAG, "createSession/subscribe RemoteException: " + e);
-            return null;
+            throw e.rethrowFromSystemServer();
         }
 
         return new WifiNanSubscribeSession(this, sessionId);
@@ -286,7 +284,7 @@ public class WifiNanManager {
         try {
             mService.subscribe(sessionId, subscribeData, subscribeSettings);
         } catch (RemoteException e) {
-            Log.w(TAG, "subscribe RemoteException: " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -299,7 +297,7 @@ public class WifiNanManager {
         try {
             mService.stopSession(sessionId);
         } catch (RemoteException e) {
-            Log.w(TAG, "stopSession RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -312,7 +310,7 @@ public class WifiNanManager {
         try {
             mService.destroySession(sessionId);
         } catch (RemoteException e) {
-            Log.w(TAG, "destroySession RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -328,7 +326,7 @@ public class WifiNanManager {
             }
             mService.sendMessage(sessionId, peerId, message, messageLength, messageId);
         } catch (RemoteException e) {
-            Log.w(TAG, "subscribe RemoteException (FYI - ignoring): " + e);
+            throw e.rethrowFromSystemServer();
         }
     }
 }
index 6409450..8d5cf63 100644 (file)
@@ -1362,8 +1362,8 @@ public class WifiP2pManager {
     public void setMiracastMode(int mode) {
         try {
             mService.setMiracastMode(mode);
-        } catch(RemoteException e) {
-           // ignore
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1378,7 +1378,7 @@ public class WifiP2pManager {
         try {
             return mService.getMessenger();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }
 
@@ -1393,7 +1393,7 @@ public class WifiP2pManager {
         try {
             return mService.getP2pStateMachineMessenger();
         } catch (RemoteException e) {
-            return null;
+            throw e.rethrowFromSystemServer();
         }
     }