summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--NOTICE10
-rw-r--r--api/current.xml649
-rw-r--r--cmds/stagefright/stagefright.cpp12
-rw-r--r--core/java/android/app/Activity.java13
-rw-r--r--core/java/android/app/ActivityThread.java26
-rw-r--r--core/java/android/app/ContextImpl.java14
-rw-r--r--core/java/android/app/Instrumentation.java1
-rw-r--r--core/java/android/app/OnActivityPausedListener.java31
-rw-r--r--core/java/android/bluetooth/BluetoothAdapter.java56
-rw-r--r--core/java/android/bluetooth/BluetoothDevice.java53
-rw-r--r--core/java/android/bluetooth/BluetoothDeviceProfileState.java4
-rw-r--r--core/java/android/content/pm/IPackageManager.aidl3
-rw-r--r--core/java/android/content/pm/PackageManager.java25
-rw-r--r--core/java/android/content/pm/PackageParser.java8
-rw-r--r--core/java/android/nfc/INfcAdapter.aidl6
-rw-r--r--core/java/android/nfc/NfcAdapter.java83
-rwxr-xr-xcore/java/android/view/WindowOrientationListener.java11
-rw-r--r--core/java/com/android/internal/widget/DigitalClock.java103
-rw-r--r--core/jni/Android.mk1
-rw-r--r--core/jni/AndroidRuntime.cpp2
-rw-r--r--core/jni/android/graphics/BitmapFactory.cpp7
-rw-r--r--core/jni/android/graphics/BitmapFactory.h1
-rw-r--r--core/jni/android/graphics/BitmapRegionDecoder.cpp326
-rw-r--r--core/jni/android/graphics/Graphics.cpp26
-rw-r--r--core/jni/android/graphics/GraphicsJNI.h3
-rw-r--r--core/res/res/values-ar/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-bg/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-ca/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-fa/donottranslate-cldr.xml135
-rw-r--r--core/res/res/values-fi/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-hr/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-hu/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-in-rID/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-in/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-iw-rIL/arrays.xml32
-rw-r--r--core/res/res/values-iw/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-lt/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-lv/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-rm-rCH/arrays.xml32
-rw-r--r--core/res/res/values-rm/donottranslate-cldr.xml145
-rw-r--r--core/res/res/values-ro/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-sk/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-sl/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-sr/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-th/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-tl/donottranslate-cldr.xml123
-rw-r--r--core/res/res/values-uk/donottranslate-cldr.xml149
-rw-r--r--core/res/res/values-vi/donottranslate-cldr.xml149
-rwxr-xr-xcore/tests/coretests/src/android/content/pm/PackageManagerTests.java159
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java10
-rw-r--r--graphics/java/android/graphics/BitmapRegionDecoder.java263
-rw-r--r--include/media/IMediaMetadataRetriever.h4
-rw-r--r--include/media/MediaMetadataRetrieverInterface.h31
-rw-r--r--include/media/mediametadataretriever.h37
-rw-r--r--libs/utils/Threads.cpp3
-rw-r--r--media/java/android/media/MediaMetadataRetriever.java253
-rw-r--r--media/java/android/media/ThumbnailUtils.java3
-rw-r--r--media/jni/android_media_MediaMetadataRetriever.cpp53
-rw-r--r--media/libmedia/IMediaMetadataRetriever.cpp50
-rw-r--r--media/libmedia/mediametadataretriever.cpp28
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.cpp50
-rw-r--r--media/libmediaplayerservice/MetadataRetrieverClient.h5
-rw-r--r--media/libstagefright/StagefrightMediaScanner.cpp8
-rw-r--r--media/libstagefright/StagefrightMetadataRetriever.cpp48
-rw-r--r--media/libstagefright/include/StagefrightMetadataRetriever.h2
-rw-r--r--media/libstagefright/matroska/MatroskaExtractor.cpp387
-rw-r--r--media/libstagefright/matroska/mkvparser.cpp3
-rw-r--r--media/libstagefright/matroska/mkvparser.hpp2
-rw-r--r--media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp384
-rw-r--r--media/libstagefright/rtsp/AMPEG4AudioAssembler.h13
-rw-r--r--media/libstagefright/rtsp/ARTPSource.cpp2
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.cpp265
-rw-r--r--media/libstagefright/rtsp/ARTSPConnection.h20
-rw-r--r--media/libstagefright/rtsp/ASessionDescription.cpp31
-rw-r--r--media/libstagefright/rtsp/Android.mk1
-rw-r--r--media/libstagefright/rtsp/MyHandler.h25
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java2
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java1
-rw-r--r--media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java50
-rw-r--r--packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.pngbin1081 -> 463 bytes
-rw-r--r--packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.pngbin827 -> 753 bytes
-rw-r--r--policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java9
-rw-r--r--policy/src/com/android/internal/policy/impl/GlobalActions.java4
-rw-r--r--policy/src/com/android/internal/policy/impl/KeyguardViewManager.java2
-rw-r--r--policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java2
-rw-r--r--policy/src/com/android/internal/policy/impl/LockScreen.java15
-rw-r--r--policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java9
-rw-r--r--services/java/com/android/server/IntentResolver.java8
-rw-r--r--services/java/com/android/server/PackageManagerService.java186
-rw-r--r--test-runner/src/android/test/mock/MockPackageManager.java11
-rw-r--r--voip/java/android/net/sip/SipProfile.java26
-rw-r--r--voip/java/com/android/server/sip/SipSessionGroup.java4
92 files changed, 6519 insertions, 573 deletions
diff --git a/NOTICE b/NOTICE
index 2006201..5560999 100644
--- a/NOTICE
+++ b/NOTICE
@@ -53,6 +53,16 @@ Media Codecs
These files are Copyright 1998 - 2009 PacketVideo, but released under
the Apache2 License.
+ =========================================================================
+ == NOTICE file corresponding to the section 4 d of ==
+ == the Apache License, Version 2.0, ==
+ == in this case for Additional Codecs code. ==
+ =========================================================================
+
+Additional Codecs
+These files are Copyright 2003-2010 VisualOn, but released under
+the Apache2 License.
+
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
diff --git a/api/current.xml b/api/current.xml
index 05658e7..4006e67 100644
--- a/api/current.xml
+++ b/api/current.xml
@@ -29401,6 +29401,23 @@
visibility="public"
>
</method>
+<method name="listenUsingInsecureRfcommWithServiceRecord"
+ return="android.bluetooth.BluetoothServerSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="name" type="java.lang.String">
+</parameter>
+<parameter name="uuid" type="java.util.UUID">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
<method name="listenUsingRfcommWithServiceRecord"
return="android.bluetooth.BluetoothServerSocket"
abstract="false"
@@ -30587,6 +30604,21 @@
>
<implements name="android.os.Parcelable">
</implements>
+<method name="createInsecureRfcommSocketToServiceRecord"
+ return="android.bluetooth.BluetoothSocket"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="uuid" type="java.util.UUID">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
<method name="createRfcommSocketToServiceRecord"
return="android.bluetooth.BluetoothSocket"
abstract="false"
@@ -45952,6 +45984,19 @@
<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
</exception>
</method>
+<method name="getPackageObbPaths"
+ return="java.lang.String[]"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<method name="getPackagesForUid"
return="java.lang.String[]"
abstract="true"
@@ -46423,6 +46468,21 @@
<parameter name="flags" type="int">
</parameter>
</method>
+<method name="setPackageObbPaths"
+ return="void"
+ abstract="true"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="paths" type="java.lang.String[]">
+</parameter>
+</method>
<field name="COMPONENT_ENABLED_STATE_DEFAULT"
type="int"
transient="false"
@@ -59862,6 +59922,16 @@
visibility="public"
>
</field>
+<field name="inPreferQualityOverSpeed"
+ type="boolean"
+ transient="false"
+ volatile="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
<field name="inPreferredConfig"
type="android.graphics.Bitmap.Config"
transient="false"
@@ -59974,6 +60044,146 @@
>
</field>
</class>
+<class name="BitmapRegionDecoder"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<method name="decodeRegion"
+ return="android.graphics.Bitmap"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="rect" type="android.graphics.Rect">
+</parameter>
+<parameter name="options" type="android.graphics.BitmapFactory.Options">
+</parameter>
+</method>
+<method name="getHeight"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getWidth"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="isRecycled"
+ return="boolean"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="newInstance"
+ return="android.graphics.BitmapRegionDecoder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="data" type="byte[]">
+</parameter>
+<parameter name="offset" type="int">
+</parameter>
+<parameter name="length" type="int">
+</parameter>
+<parameter name="isShareable" type="boolean">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="newInstance"
+ return="android.graphics.BitmapRegionDecoder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<parameter name="isShareable" type="boolean">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="newInstance"
+ return="android.graphics.BitmapRegionDecoder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="is" type="java.io.InputStream">
+</parameter>
+<parameter name="isShareable" type="boolean">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="newInstance"
+ return="android.graphics.BitmapRegionDecoder"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="pathName" type="java.lang.String">
+</parameter>
+<parameter name="isShareable" type="boolean">
+</parameter>
+<exception name="IOException" type="java.io.IOException">
+</exception>
+</method>
+<method name="recycle"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+</class>
<class name="BitmapShader"
extends="android.graphics.Shader"
abstract="false"
@@ -85937,6 +86147,385 @@
</parameter>
</method>
</interface>
+<class name="MediaMetadataRetriever"
+ extends="java.lang.Object"
+ abstract="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<constructor name="MediaMetadataRetriever"
+ type="android.media.MediaMetadataRetriever"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</constructor>
+<method name="extractMetadata"
+ return="java.lang.String"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="keyCode" type="int">
+</parameter>
+</method>
+<method name="getEmbeddedPicture"
+ return="byte[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="getFrameAtTime"
+ return="android.graphics.Bitmap"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeUs" type="long">
+</parameter>
+<parameter name="option" type="int">
+</parameter>
+</method>
+<method name="getFrameAtTime"
+ return="android.graphics.Bitmap"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="timeUs" type="long">
+</parameter>
+</method>
+<method name="getFrameAtTime"
+ return="android.graphics.Bitmap"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="release"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</method>
+<method name="setDataSource"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="path" type="java.lang.String">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</method>
+<method name="setDataSource"
+ return="void"
+ abstract="false"
+ native="true"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<parameter name="offset" type="long">
+</parameter>
+<parameter name="length" type="long">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</method>
+<method name="setDataSource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="fd" type="java.io.FileDescriptor">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+</method>
+<method name="setDataSource"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="context" type="android.content.Context">
+</parameter>
+<parameter name="uri" type="android.net.Uri">
+</parameter>
+<exception name="IllegalArgumentException" type="java.lang.IllegalArgumentException">
+</exception>
+<exception name="SecurityException" type="java.lang.SecurityException">
+</exception>
+</method>
+<field name="METADATA_KEY_ALBUM"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_ALBUMARTIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="13"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_ARTIST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_AUTHOR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_CD_TRACK_NUMBER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_COMPILATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="15"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_COMPOSER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="4"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_DATE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="5"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_DISC_NUMBER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="14"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_DURATION"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="9"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_GENRE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="6"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_MIMETYPE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="12"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_NUM_TRACKS"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="10"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_TITLE"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="7"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_WRITER"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="11"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="METADATA_KEY_YEAR"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="8"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OPTION_CLOSEST"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="3"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OPTION_CLOSEST_SYNC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="2"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OPTION_NEXT_SYNC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="1"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+<field name="OPTION_PREVIOUS_SYNC"
+ type="int"
+ transient="false"
+ volatile="false"
+ value="0"
+ static="true"
+ final="true"
+ deprecated="not deprecated"
+ visibility="public"
+>
+</field>
+</class>
<class name="MediaPlayer"
extends="java.lang.Object"
abstract="false"
@@ -100228,6 +100817,36 @@
deprecated="not deprecated"
visibility="public"
>
+<method name="disableForegroundDispatch"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+</method>
+<method name="enableForegroundDispatch"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="activity" type="android.app.Activity">
+</parameter>
+<parameter name="intent" type="android.app.PendingIntent">
+</parameter>
+<parameter name="filters" type="android.content.IntentFilter...">
+</parameter>
+</method>
<method name="getDefaultAdapter"
return="android.nfc.NfcAdapter"
abstract="false"
@@ -159105,6 +159724,19 @@
<exception name="PackageManager.NameNotFoundException" type="android.content.pm.PackageManager.NameNotFoundException">
</exception>
</method>
+<method name="getPackageObbPaths"
+ return="java.lang.String[]"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+</method>
<method name="getPackagesForUid"
return="java.lang.String[]"
abstract="false"
@@ -159589,6 +160221,21 @@
<parameter name="path" type="java.lang.String">
</parameter>
</method>
+<method name="setPackageObbPaths"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ deprecated="not deprecated"
+ visibility="public"
+>
+<parameter name="packageName" type="java.lang.String">
+</parameter>
+<parameter name="paths" type="java.lang.String[]">
+</parameter>
+</method>
</class>
<class name="MockResources"
extends="android.content.res.Resources"
@@ -226180,7 +226827,7 @@
deprecated="not deprecated"
visibility="public"
>
-<parameter name="arg0" type="T">
+<parameter name="t" type="T">
</parameter>
</method>
</interface>
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index f55b746..ff92431 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -596,21 +596,19 @@ int main(int argc, char **argv) {
const char *filename = argv[k];
CHECK_EQ(retriever->setDataSource(filename), (status_t)OK);
- CHECK_EQ(retriever->setMode(
- METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL),
- (status_t)OK);
-
- sp<IMemory> mem = retriever->captureFrame();
+ sp<IMemory> mem =
+ retriever->getFrameAtTime(-1,
+ MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC);
if (mem != NULL) {
- printf("captureFrame(%s) => OK\n", filename);
+ printf("getFrameAtTime(%s) => OK\n", filename);
} else {
mem = retriever->extractAlbumArt();
if (mem != NULL) {
printf("extractAlbumArt(%s) => OK\n", filename);
} else {
- printf("both captureFrame and extractAlbumArt "
+ printf("both getFrameAtTime and extractAlbumArt "
"failed on file '%s'.\n", filename);
}
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index f25c4c3..a54b305 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -632,7 +632,7 @@ public class Activity extends ContextThemeWrapper
/*package*/ HashMap<String,Object> mLastNonConfigurationChildInstances;
Activity mParent;
boolean mCalled;
- private boolean mResumed;
+ /*package*/ boolean mResumed;
private boolean mStopped;
boolean mFinished;
boolean mStartedActivity;
@@ -3827,9 +3827,8 @@ public class Activity extends ContextThemeWrapper
mLastNonConfigurationInstance = null;
- // First call onResume() -before- setting mResumed, so we don't
- // send out any status bar / menu notifications the client makes.
mCalled = false;
+ // mResumed is set by the instrumentation
mInstrumentation.callActivityOnResume(this);
if (!mCalled) {
throw new SuperNotCalledException(
@@ -3838,7 +3837,6 @@ public class Activity extends ContextThemeWrapper
}
// Now really resume, and install the current status bar and menu.
- mResumed = true;
mCalled = false;
onPostResume();
if (!mCalled) {
@@ -3857,6 +3855,7 @@ public class Activity extends ContextThemeWrapper
"Activity " + mComponent.toShortString() +
" did not call through to super.onPause()");
}
+ mResumed = false;
}
final void performUserLeaving() {
@@ -3891,10 +3890,12 @@ public class Activity extends ContextThemeWrapper
mStopped = true;
}
- mResumed = false;
}
- final boolean isResumed() {
+ /**
+ * @hide
+ */
+ public final boolean isResumed() {
return mResumed;
}
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 78df780..e3fa32c 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -185,6 +185,9 @@ public final class ActivityThread {
final HashMap<IBinder, ProviderClientRecord> mLocalProviders
= new HashMap<IBinder, ProviderClientRecord>();
+ final HashMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
+ = new HashMap<Activity, ArrayList<OnActivityPausedListener>>();
+
final GcIdler mGcIdler = new GcIdler();
boolean mGcIdlerScheduled = false;
@@ -1424,6 +1427,18 @@ public final class ActivityThread {
}
}
+ public void registerOnActivityPausedListener(Activity activity,
+ OnActivityPausedListener listener) {
+ synchronized (mOnPauseListeners) {
+ ArrayList<OnActivityPausedListener> list = mOnPauseListeners.get(activity);
+ if (list == null) {
+ list = new ArrayList<OnActivityPausedListener>();
+ mOnPauseListeners.put(activity, list);
+ }
+ list.add(listener);
+ }
+ }
+
public final ActivityInfo resolveActivityInfo(Intent intent) {
ActivityInfo aInfo = intent.resolveActivityInfo(
mInitialApplication.getPackageManager(), PackageManager.GET_SHARED_LIBRARY_FILES);
@@ -2333,6 +2348,17 @@ public final class ActivityThread {
}
}
r.paused = true;
+
+ // Notify any outstanding on paused listeners
+ ArrayList<OnActivityPausedListener> listeners;
+ synchronized (mOnPauseListeners) {
+ listeners = mOnPauseListeners.remove(r.activity);
+ }
+ int size = (listeners != null ? listeners.size() : 0);
+ for (int i = 0; i < size; i++) {
+ listeners.get(i).onPaused(r.activity);
+ }
+
return state;
}
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7e7cd7a..18ab478 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2700,14 +2700,24 @@ class ContextImpl extends Context {
}
@Override
- public void setPackageObbPath(String packageName, String path) {
+ public void setPackageObbPaths(String packageName, String[] paths) {
try {
- mPM.setPackageObbPath(packageName, path);
+ mPM.setPackageObbPaths(packageName, paths);
} catch (RemoteException e) {
// Should never happen!
}
}
+ @Override
+ public String[] getPackageObbPaths(String packageName) {
+ try {
+ return mPM.getPackageObbPaths(packageName);
+ } catch (RemoteException e) {
+ // Should never happen!
+ }
+ return null;
+ }
+
private final ContextImpl mContext;
private final IPackageManager mPM;
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index b8c3aa3..5c333a2 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1146,6 +1146,7 @@ public class Instrumentation {
* @param activity The activity being resumed.
*/
public void callActivityOnResume(Activity activity) {
+ activity.mResumed = true;
activity.onResume();
if (mActivityMonitors != null) {
diff --git a/core/java/android/app/OnActivityPausedListener.java b/core/java/android/app/OnActivityPausedListener.java
new file mode 100644
index 0000000..379f133
--- /dev/null
+++ b/core/java/android/app/OnActivityPausedListener.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app;
+
+/**
+ * A listener that is called when an Activity is paused. Since this is tracked client side
+ * it should not be trusted to represent the exact current state, but can be used as a hint
+ * for cleanup.
+ *
+ * @hide
+ */
+public interface OnActivityPausedListener {
+ /**
+ * Called when the given activity is paused.
+ */
+ public void onPaused(Activity activity);
+}
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index 3040319..a7175e3 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -729,6 +729,15 @@ public final class BluetoothAdapter {
* Create a listening, secure RFCOMM Bluetooth socket.
* <p>A remote device connecting to this socket will be authenticated and
* communication on this socket will be encrypted.
+ * <p> Use this socket only if an authenticated socket link is possible.
+ * Authentication refers to the authentication of the link key to
+ * prevent man-in-the-middle type of attacks.
+ * For example, for Bluetooth 2.1 devices, if any of the devices does not
+ * have an input and output capability or just has the ability to
+ * display a numeric key, a secure socket connection is not possible.
+ * In such a case, use {#link listenUsingInsecureRfcommOn}.
+ * For more details, refer to the Security Model section 5.2 (vol 3) of
+ * Bluetooth Core Specification version 2.1 + EDR.
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
* connections from a listening {@link BluetoothServerSocket}.
* <p>Valid RFCOMM channels are in range 1 to 30.
@@ -756,6 +765,15 @@ public final class BluetoothAdapter {
* Create a listening, secure RFCOMM Bluetooth socket with Service Record.
* <p>A remote device connecting to this socket will be authenticated and
* communication on this socket will be encrypted.
+ * <p> Use this socket only if an authenticated socket link is possible.
+ * Authentication refers to the authentication of the link key to
+ * prevent man-in-the-middle type of attacks.
+ * For example, for Bluetooth 2.1 devices, if any of the devices does not
+ * have an input and output capability or just has the ability to
+ * display a numeric key, a secure socket connection is not possible.
+ * In such a case, use {#link listenUsingInsecureRfcommWithServiceRecord}.
+ * For more details, refer to the Security Model section 5.2 (vol 3) of
+ * Bluetooth Core Specification version 2.1 + EDR.
* <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
* connections from a listening {@link BluetoothServerSocket}.
* <p>The system will assign an unused RFCOMM channel to listen on.
@@ -776,6 +794,42 @@ public final class BluetoothAdapter {
*/
public BluetoothServerSocket listenUsingRfcommWithServiceRecord(String name, UUID uuid)
throws IOException {
+ return createNewRfcommSocketAndRecord(name, uuid, true, true);
+ }
+
+ /**
+ * Create a listening, insecure RFCOMM Bluetooth socket with Service Record.
+ * <p>The link key will be unauthenticated i.e the communication is
+ * vulnerable to Man In the Middle attacks. For Bluetooth 2.1 devices,
+ * the link key will be encrypted, as encryption is mandartory.
+ * For legacy devices (pre Bluetooth 2.1 devices) the link key will not
+ * be encrypted. Use {@link #listenUsingRfcommWithServiceRecord}, if an
+ * encrypted and authenticated communication channel is desired.
+ * <p>Use {@link BluetoothServerSocket#accept} to retrieve incoming
+ * connections from a listening {@link BluetoothServerSocket}.
+ * <p>The system will assign an unused RFCOMM channel to listen on.
+ * <p>The system will also register a Service Discovery
+ * Protocol (SDP) record with the local SDP server containing the specified
+ * UUID, service name, and auto-assigned channel. Remote Bluetooth devices
+ * can use the same UUID to query our SDP server and discover which channel
+ * to connect to. This SDP record will be removed when this socket is
+ * closed, or if this application closes unexpectedly.
+ * <p>Use {@link BluetoothDevice#createRfcommSocketToServiceRecord} to
+ * connect to this socket from another device using the same {@link UUID}.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ * @param name service name for SDP record
+ * @param uuid uuid for SDP record
+ * @return a listening RFCOMM BluetoothServerSocket
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions, or channel in use.
+ */
+ public BluetoothServerSocket listenUsingInsecureRfcommWithServiceRecord(String name, UUID uuid)
+ throws IOException {
+ return createNewRfcommSocketAndRecord(name, uuid, false, false);
+ }
+
+ private BluetoothServerSocket createNewRfcommSocketAndRecord(String name, UUID uuid,
+ boolean auth, boolean encrypt) throws IOException {
RfcommChannelPicker picker = new RfcommChannelPicker(uuid);
BluetoothServerSocket socket;
@@ -789,7 +843,7 @@ public final class BluetoothAdapter {
}
socket = new BluetoothServerSocket(
- BluetoothSocket.TYPE_RFCOMM, true, true, channel);
+ BluetoothSocket.TYPE_RFCOMM, auth, encrypt, channel);
errno = socket.mSocket.bindListen();
if (errno == 0) {
if (DBG) Log.d(TAG, "listening on RFCOMM channel " + channel);
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index ada3c24..aee6ad8 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -693,6 +693,15 @@ public final class BluetoothDevice implements Parcelable {
* outgoing connection to this remote device on given channel.
* <p>The remote device will be authenticated and communication on this
* socket will be encrypted.
+ * <p> Use this socket only if an authenticated socket link is possible.
+ * Authentication refers to the authentication of the link key to
+ * prevent man-in-the-middle type of attacks.
+ * For example, for Bluetooth 2.1 devices, if any of the devices does not
+ * have an input and output capability or just has the ability to
+ * display a numeric key, a secure socket connection is not possible.
+ * In such a case, use {#link createInsecureRfcommSocket}.
+ * For more details, refer to the Security Model section 5.2 (vol 3) of
+ * Bluetooth Core Specification version 2.1 + EDR.
* <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
* connection.
* <p>Valid RFCOMM channels are in range 1 to 30.
@@ -720,11 +729,20 @@ public final class BluetoothDevice implements Parcelable {
* determine which channel to connect to.
* <p>The remote device will be authenticated and communication on this
* socket will be encrypted.
+ * <p> Use this socket only if an authenticated socket link is possible.
+ * Authentication refers to the authentication of the link key to
+ * prevent man-in-the-middle type of attacks.
+ * For example, for Bluetooth 2.1 devices, if any of the devices does not
+ * have an input and output capability or just has the ability to
+ * display a numeric key, a secure socket connection is not possible.
+ * In such a case, use {#link createInsecureRfcommSocketToServiceRecord}.
+ * For more details, refer to the Security Model section 5.2 (vol 3) of
+ * Bluetooth Core Specification version 2.1 + EDR.
* <p>Hint: If you are connecting to a Bluetooth serial board then try
* using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
* However if you are connecting to an Android peer then please generate
* your own unique UUID.
- * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
*
* @param uuid service record uuid to lookup RFCOMM channel
* @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
@@ -737,6 +755,39 @@ public final class BluetoothDevice implements Parcelable {
}
/**
+ * Create an RFCOMM {@link BluetoothSocket} socket ready to start an insecure
+ * outgoing connection to this remote device using SDP lookup of uuid.
+ * <p> The communication channel will not have an authenticated link key
+ * i.e it will be subject to man-in-the-middle attacks. For Bluetooth 2.1
+ * devices, the link key will be encrypted, as encryption is mandatory.
+ * For legacy devices (pre Bluetooth 2.1 devices) the link key will
+ * be not be encrypted. Use {@link #createRfcommSocketToServiceRecord} if an
+ * encrypted and authenticated communication channel is desired.
+ * <p>This is designed to be used with {@link
+ * BluetoothAdapter#listenUsingInsecureRfcommWithServiceRecord} for peer-peer
+ * Bluetooth applications.
+ * <p>Use {@link BluetoothSocket#connect} to initiate the outgoing
+ * connection. This will also perform an SDP lookup of the given uuid to
+ * determine which channel to connect to.
+ * <p>The remote device will be authenticated and communication on this
+ * socket will be encrypted.
+ * <p>Hint: If you are connecting to a Bluetooth serial board then try
+ * using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
+ * However if you are connecting to an Android peer then please generate
+ * your own unique UUID.
+ * <p>Requires {@link android.Manifest.permission#BLUETOOTH}
+ *
+ * @param uuid service record uuid to lookup RFCOMM channel
+ * @return a RFCOMM BluetoothServerSocket ready for an outgoing connection
+ * @throws IOException on error, for example Bluetooth not available, or
+ * insufficient permissions
+ */
+ public BluetoothSocket createInsecureRfcommSocketToServiceRecord(UUID uuid) throws IOException {
+ return new BluetoothSocket(BluetoothSocket.TYPE_RFCOMM, -1, false, false, this, -1,
+ new ParcelUuid(uuid));
+ }
+
+ /**
* Construct an insecure RFCOMM socket ready to start an outgoing
* connection.
* Call #connect on the returned #BluetoothSocket to begin the connection.
diff --git a/core/java/android/bluetooth/BluetoothDeviceProfileState.java b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
index 9be4c8f..954fde5 100644
--- a/core/java/android/bluetooth/BluetoothDeviceProfileState.java
+++ b/core/java/android/bluetooth/BluetoothDeviceProfileState.java
@@ -129,10 +129,6 @@ public final class BluetoothDeviceProfileState extends HierarchicalStateMachine
newState == BluetoothA2dp.STATE_DISCONNECTED) {
sendMessage(TRANSITION_TO_STABLE);
}
- } else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)) {
- Message msg = new Message();
- msg.what = AUTO_CONNECT_PROFILES;
- sendMessageDelayed(msg, AUTO_CONNECT_DELAY);
} else if (action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
// This is technically not needed, but we can get stuck sometimes.
// For example, if incoming A2DP fails, we are not informed by Bluez
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 4cff3bb..44b0c96 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -322,5 +322,6 @@ interface IPackageManager {
boolean setInstallLocation(int loc);
int getInstallLocation();
- void setPackageObbPath(String packageName, String path);
+ void setPackageObbPaths(in String packageName, in String[] paths);
+ String[] getPackageObbPaths(in String packageName);
}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index b5d1653..a1c29f7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2273,15 +2273,30 @@ public abstract class PackageManager {
String packageName, IPackageMoveObserver observer, int flags);
/**
- * Sets the Opaque Binary Blob (OBB) file location.
+ * Sets the Opaque Binary Blob (OBB) file path associated with a package
+ * name. The caller must have the
+ * {@link android.Manifest.permission#INSTALL_PACKAGES} permission.
* <p>
* NOTE: The existence or format of this file is not currently checked, but
* it may be in the future.
*
* @param packageName Name of the package with which to associate the .obb
- * file
- * @param path Path on the filesystem to the .obb file
- * @hide
+ * file.
+ * @param paths Arrays of paths on the filesystem to the .obb files
+ * associated with the package.
+ * @see #getPackageObbPaths(String)
+ */
+ public abstract void setPackageObbPaths(String packageName, String[] paths);
+
+ /**
+ * Gets the Opaque Binary Blob (OBB) file path associated with the package.
+ * The caller must be the owner of the package queried or have the
+ * {@link android.Manifest.permission#INSTALL_PACKAGES} permission.
+ *
+ * @param packageName Name of the package with which to associate the .obb
+ * file.
+ * @return array of paths to .obb files associated with the package
+ * @see #setPackageObbPaths(String, String[])
*/
- public abstract void setPackageObbPath(String packageName, String path);
+ public abstract String[] getPackageObbPaths(String packageName);
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 80b8d92..16805b2 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2601,14 +2601,8 @@ public class PackageParser {
int priority = sa.getInt(
com.android.internal.R.styleable.AndroidManifestIntentFilter_priority, 0);
- if (priority > 0 && isActivity && (flags&PARSE_IS_SYSTEM) == 0) {
- Log.w(TAG, "Activity with priority > 0, forcing to 0 at "
- + mArchiveSourcePath + " "
- + parser.getPositionDescription());
- priority = 0;
- }
outInfo.setPriority(priority);
-
+
TypedValue v = sa.peekValue(
com.android.internal.R.styleable.AndroidManifestIntentFilter_label);
if (v != null && (outInfo.labelRes=v.resourceId) == 0) {
diff --git a/core/java/android/nfc/INfcAdapter.aidl b/core/java/android/nfc/INfcAdapter.aidl
index a663fb8..cb9fc9d 100644
--- a/core/java/android/nfc/INfcAdapter.aidl
+++ b/core/java/android/nfc/INfcAdapter.aidl
@@ -16,6 +16,9 @@
package android.nfc;
+import android.app.PendingIntent;
+import android.content.ComponentName;
+import android.content.IntentFilter;
import android.nfc.NdefMessage;
import android.nfc.Tag;
import android.nfc.ILlcpSocket;
@@ -44,6 +47,9 @@ interface INfcAdapter
NdefMessage localGet();
void localSet(in NdefMessage message);
void openTagConnection(in Tag tag);
+ void enableForegroundDispatch(in ComponentName activity, in PendingIntent intent,
+ in IntentFilter[] filters);
+ void disableForegroundDispatch(in ComponentName activity);
// Non-public methods
// TODO: check and complete
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index cfbe581..c0c0462 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -18,8 +18,12 @@ package android.nfc;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.app.Activity;
import android.app.ActivityThread;
+import android.app.OnActivityPausedListener;
+import android.app.PendingIntent;
import android.content.Context;
+import android.content.IntentFilter;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.nfc.technology.TagTechnology;
@@ -100,6 +104,20 @@ public final class NfcAdapter {
"android.nfc.action.TRANSACTION_DETECTED";
/**
+ * Broadcast Action: an RF field ON has been detected.
+ * @hide
+ */
+ public static final String ACTION_RF_FIELD_ON_DETECTED =
+ "android.nfc.action.RF_FIELD_ON_DETECTED";
+
+ /**
+ * Broadcast Action: an RF Field OFF has been detected.
+ * @hide
+ */
+ public static final String ACTION_RF_FIELD_OFF_DETECTED =
+ "android.nfc.action.RF_FIELD_OFF_DETECTED";
+
+ /**
* Broadcast Action: an adapter's state changed between enabled and disabled.
*
* The new value is stored in the extra EXTRA_NEW_BOOLEAN_STATE and just contains
@@ -197,8 +215,6 @@ public final class NfcAdapter {
private static INfcAdapter sService;
private static INfcTag sTagService;
- private final Context mContext;
-
/**
* Helper to check if this device has FEATURE_NFC, but without using
* a context.
@@ -294,7 +310,6 @@ public final class NfcAdapter {
if (setupService() == null) {
throw new UnsupportedOperationException();
}
- mContext = context;
}
/**
@@ -302,6 +317,7 @@ public final class NfcAdapter {
* @hide
*/
public INfcAdapter getService() {
+ isEnabled(); // NOP call to recover sService if it is stale
return sService;
}
@@ -310,6 +326,7 @@ public final class NfcAdapter {
* @hide
*/
public INfcTag getTagService() {
+ isEnabled(); // NOP call to recover sTagService if it is stale
return sTagService;
}
@@ -396,6 +413,66 @@ public final class NfcAdapter {
}
}
+ class ForegroundDispatchPausedListener implements OnActivityPausedListener {
+ @Override
+ public void onPaused(Activity activity) {
+ disableForegroundDispatchInternal(activity, true);
+ }
+ }
+
+ /**
+ * Enables foreground dispatching to the given Activity. This will force all NFC Intents that
+ * match the given filters to be delivered to the activity bypassing the standard dispatch
+ * mechanism.
+ *
+ * This method must be called from the main thread.
+ *
+ * @param activity the Activity to dispatch to
+ * @param intent the PendingIntent to start for the dispatch
+ * @param filters the IntentFilters to override dispatching for
+ * @throws IllegalStateException
+ */
+ public void enableForegroundDispatch(Activity activity, PendingIntent intent,
+ IntentFilter... filters) {
+ if (activity == null || intent == null || filters == null) {
+ throw new NullPointerException();
+ }
+ if (!activity.isResumed()) {
+ throw new IllegalStateException("Foregorund dispatching can onlly be enabled " +
+ "when your activity is resumed");
+ }
+ try {
+ ActivityThread.currentActivityThread().registerOnActivityPausedListener(activity,
+ new ForegroundDispatchPausedListener());
+ sService.enableForegroundDispatch(activity.getComponentName(), intent, filters);
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ }
+ }
+
+ /**
+ * Disables foreground activity dispatching setup with
+ * {@link #enableForegroundDispatch}. This must be called before the Activity returns from
+ * it's <code>onPause()</code> or this method will throw an IllegalStateException.
+ *
+ * This method must be called from the main thread.
+ */
+ public void disableForegroundDispatch(Activity activity) {
+ disableForegroundDispatchInternal(activity, false);
+ }
+
+ void disableForegroundDispatchInternal(Activity activity, boolean force) {
+ try {
+ sService.disableForegroundDispatch(activity.getComponentName());
+ if (!force && !activity.isResumed()) {
+ throw new IllegalStateException("You must disable forgeground dispatching " +
+ "while your activity is still resumed");
+ }
+ } catch (RemoteException e) {
+ attemptDeadServiceRecovery(e);
+ }
+ }
+
/**
* Retrieve a TagTechnology object used to interact with a Tag that is
* in field.
diff --git a/core/java/android/view/WindowOrientationListener.java b/core/java/android/view/WindowOrientationListener.java
index 2a76e33..6095a64 100755
--- a/core/java/android/view/WindowOrientationListener.java
+++ b/core/java/android/view/WindowOrientationListener.java
@@ -234,6 +234,14 @@ public abstract class WindowOrientationListener {
// high time constant.
private static final float MAX_DEVIATION_FROM_GRAVITY = 1.5f;
+ // Minimum acceleration considered, in m/s^2. Below this threshold sensor noise will have
+ // significant impact on the calculations and in case of the vector (0, 0, 0) there is no
+ // defined rotation or tilt at all. Low or zero readings can happen when space travelling
+ // or free falling, but more commonly when shaking or getting bad readings from the sensor.
+ // The accelerometer is turned off when not used and polling it too soon after it is
+ // turned on may result in (0, 0, 0).
+ private static final float MIN_ABS_ACCELERATION = 1.5f;
+
// Actual sampling period corresponding to SensorManager.SENSOR_DELAY_NORMAL. There's no
// way to get this information from SensorManager.
// Note the actual period is generally 3-30ms larger than this depending on the device, but
@@ -347,6 +355,9 @@ public abstract class WindowOrientationListener {
float deviation = Math.abs(magnitude - SensorManager.STANDARD_GRAVITY);
handleAccelerationDistrust(deviation);
+ if (magnitude < MIN_ABS_ACCELERATION) {
+ return; // Ignore tilt and orientation when (0, 0, 0) or low reading
+ }
// only filter tilt when we're accelerating
float alpha = 1;
diff --git a/core/java/com/android/internal/widget/DigitalClock.java b/core/java/com/android/internal/widget/DigitalClock.java
index fa47ff6..303a1bf 100644
--- a/core/java/com/android/internal/widget/DigitalClock.java
+++ b/core/java/com/android/internal/widget/DigitalClock.java
@@ -22,7 +22,6 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Typeface;
import android.os.Handler;
@@ -33,6 +32,7 @@ import android.view.View;
import android.widget.LinearLayout;
import android.widget.TextView;
+import java.lang.ref.WeakReference;
import java.text.DateFormatSymbols;
import java.util.Calendar;
@@ -49,26 +49,41 @@ public class DigitalClock extends LinearLayout {
private TextView mTimeDisplay;
private AmPm mAmPm;
private ContentObserver mFormatChangeObserver;
- private boolean mLive = true;
- private boolean mAttached;
+ private int mAttached = 0; // for debugging - tells us whether attach/detach is unbalanced
/* called by system on minute ticks */
private final Handler mHandler = new Handler();
- private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
- @Override
- public void onReceive(Context context, Intent intent) {
- if (mLive && intent.getAction().equals(
- Intent.ACTION_TIMEZONE_CHANGED)) {
- mCalendar = Calendar.getInstance();
- }
- // Post a runnable to avoid blocking the broadcast.
- mHandler.post(new Runnable() {
- public void run() {
- updateTime();
+ private BroadcastReceiver mIntentReceiver;
+
+ private static class TimeChangedReceiver extends BroadcastReceiver {
+ private WeakReference<DigitalClock> mClock;
+ private Context mContext;
+
+ public TimeChangedReceiver(DigitalClock clock) {
+ mClock = new WeakReference<DigitalClock>(clock);
+ mContext = clock.getContext();
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ // Post a runnable to avoid blocking the broadcast.
+ final boolean timezoneChanged =
+ intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED);
+ final DigitalClock clock = mClock.get();
+ if (clock != null) {
+ clock.mHandler.post(new Runnable() {
+ public void run() {
+ if (timezoneChanged) {
+ clock.mCalendar = Calendar.getInstance();
}
+ clock.updateTime();
+ }
});
+ } else {
+ mContext.unregisterReceiver(this);
}
- };
+ }
+ };
static class AmPm {
private TextView mAmPm;
@@ -94,14 +109,23 @@ public class DigitalClock extends LinearLayout {
}
}
- private class FormatChangeObserver extends ContentObserver {
- public FormatChangeObserver() {
+ private static class FormatChangeObserver extends ContentObserver {
+ private WeakReference<DigitalClock> mClock;
+ private Context mContext;
+ public FormatChangeObserver(DigitalClock clock) {
super(new Handler());
+ mClock = new WeakReference<DigitalClock>(clock);
+ mContext = clock.getContext();
}
@Override
public void onChange(boolean selfChange) {
- setDateFormat();
- updateTime();
+ DigitalClock digitalClock = mClock.get();
+ if (digitalClock != null) {
+ digitalClock.setDateFormat();
+ digitalClock.updateTime();
+ } else {
+ mContext.getContentResolver().unregisterContentObserver(this);
+ }
}
}
@@ -129,11 +153,11 @@ public class DigitalClock extends LinearLayout {
protected void onAttachedToWindow() {
super.onAttachedToWindow();
- if (mAttached) return;
- mAttached = true;
+ mAttached++;
- if (mLive) {
- /* monitor time ticks, time changed, timezone */
+ /* monitor time ticks, time changed, timezone */
+ if (mIntentReceiver == null) {
+ mIntentReceiver = new TimeChangedReceiver(this);
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_TIME_TICK);
filter.addAction(Intent.ACTION_TIME_CHANGED);
@@ -142,9 +166,11 @@ public class DigitalClock extends LinearLayout {
}
/* monitor 12/24-hour display preference */
- mFormatChangeObserver = new FormatChangeObserver();
- mContext.getContentResolver().registerContentObserver(
- Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+ if (mFormatChangeObserver == null) {
+ mFormatChangeObserver = new FormatChangeObserver(this);
+ mContext.getContentResolver().registerContentObserver(
+ Settings.System.CONTENT_URI, true, mFormatChangeObserver);
+ }
updateTime();
}
@@ -153,16 +179,19 @@ public class DigitalClock extends LinearLayout {
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
- if (!mAttached) return;
- mAttached = false;
+ mAttached--;
- if (mLive) {
+ if (mIntentReceiver != null) {
mContext.unregisterReceiver(mIntentReceiver);
}
- mContext.getContentResolver().unregisterContentObserver(
- mFormatChangeObserver);
- }
+ if (mFormatChangeObserver != null) {
+ mContext.getContentResolver().unregisterContentObserver(
+ mFormatChangeObserver);
+ }
+ mFormatChangeObserver = null;
+ mIntentReceiver = null;
+ }
void updateTime(Calendar c) {
mCalendar = c;
@@ -170,9 +199,7 @@ public class DigitalClock extends LinearLayout {
}
private void updateTime() {
- if (mLive) {
- mCalendar.setTimeInMillis(System.currentTimeMillis());
- }
+ mCalendar.setTimeInMillis(System.currentTimeMillis());
CharSequence newTime = DateFormat.format(mFormat, mCalendar);
mTimeDisplay.setText(newTime);
@@ -180,12 +207,8 @@ public class DigitalClock extends LinearLayout {
}
private void setDateFormat() {
- mFormat = android.text.format.DateFormat.is24HourFormat(getContext())
+ mFormat = android.text.format.DateFormat.is24HourFormat(getContext())
? M24 : M12;
mAmPm.setShowAmPm(mFormat.equals(M12));
}
-
- void setLive(boolean live) {
- mLive = live;
- }
}
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index c3f393d..12b9ca5 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -103,6 +103,7 @@ LOCAL_SRC_FILES:= \
android_graphics_PixelFormat.cpp \
android/graphics/Picture.cpp \
android/graphics/PorterDuff.cpp \
+ android/graphics/BitmapRegionDecoder.cpp \
android/graphics/Rasterizer.cpp \
android/graphics/Region.cpp \
android/graphics/Shader.cpp \
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 648d93f..d9759bf 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -53,6 +53,7 @@ extern int register_android_os_Binder(JNIEnv* env);
extern int register_android_os_Process(JNIEnv* env);
extern int register_android_graphics_Bitmap(JNIEnv*);
extern int register_android_graphics_BitmapFactory(JNIEnv*);
+extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
extern int register_android_graphics_Camera(JNIEnv* env);
extern int register_android_graphics_Graphics(JNIEnv* env);
extern int register_android_graphics_Interpolator(JNIEnv* env);
@@ -1209,6 +1210,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_graphics_Bitmap),
REG_JNI(register_android_graphics_BitmapFactory),
+ REG_JNI(register_android_graphics_BitmapRegionDecoder),
REG_JNI(register_android_graphics_Camera),
REG_JNI(register_android_graphics_Canvas),
REG_JNI(register_android_graphics_ColorFilter),
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 90a0243..987dd4f 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -27,6 +27,7 @@ jfieldID gOptions_ditherFieldID;
jfieldID gOptions_purgeableFieldID;
jfieldID gOptions_shareableFieldID;
jfieldID gOptions_nativeAllocFieldID;
+jfieldID gOptions_preferQualityOverSpeedFieldID;
jfieldID gOptions_widthFieldID;
jfieldID gOptions_heightFieldID;
jfieldID gOptions_mimeFieldID;
@@ -180,6 +181,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
bool isPurgeable = forcePurgeable ||
(allowPurgeable && optionsPurgeable(env, options));
bool reportSizeToVM = optionsReportSizeToVM(env, options);
+ bool preferQualityOverSpeed = false;
if (NULL != options) {
sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
@@ -194,6 +196,8 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
+ preferQualityOverSpeed = env->GetBooleanField(options,
+ gOptions_preferQualityOverSpeedFieldID);
}
SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
@@ -203,6 +207,7 @@ static jobject doDecode(JNIEnv* env, SkStream* stream, jobject padding,
decoder->setSampleSize(sampleSize);
decoder->setDitherImage(doDither);
+ decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
NinePatchPeeker peeker(decoder);
JavaPixelAllocator javaAllocator(env, reportSizeToVM);
@@ -551,6 +556,8 @@ int register_android_graphics_BitmapFactory(JNIEnv* env) {
gOptions_purgeableFieldID = getFieldIDCheck(env, gOptions_class, "inPurgeable", "Z");
gOptions_shareableFieldID = getFieldIDCheck(env, gOptions_class, "inInputShareable", "Z");
gOptions_nativeAllocFieldID = getFieldIDCheck(env, gOptions_class, "inNativeAlloc", "Z");
+ gOptions_preferQualityOverSpeedFieldID = getFieldIDCheck(env, gOptions_class,
+ "inPreferQualityOverSpeed", "Z");
gOptions_widthFieldID = getFieldIDCheck(env, gOptions_class, "outWidth", "I");
gOptions_heightFieldID = getFieldIDCheck(env, gOptions_class, "outHeight", "I");
gOptions_mimeFieldID = getFieldIDCheck(env, gOptions_class, "outMimeType", "Ljava/lang/String;");
diff --git a/core/jni/android/graphics/BitmapFactory.h b/core/jni/android/graphics/BitmapFactory.h
index f868434..9ae61bc 100644
--- a/core/jni/android/graphics/BitmapFactory.h
+++ b/core/jni/android/graphics/BitmapFactory.h
@@ -11,6 +11,7 @@ extern jfieldID gOptions_ditherFieldID;
extern jfieldID gOptions_purgeableFieldID;
extern jfieldID gOptions_shareableFieldID;
extern jfieldID gOptions_nativeAllocFieldID;
+extern jfieldID gOptions_preferQualityOverSpeedFieldID;
extern jfieldID gOptions_widthFieldID;
extern jfieldID gOptions_heightFieldID;
extern jfieldID gOptions_mimeFieldID;
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
new file mode 100644
index 0000000..91a8202
--- /dev/null
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -0,0 +1,326 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "BitmapRegionDecoder"
+
+#include "SkBitmap.h"
+#include "SkImageEncoder.h"
+#include "GraphicsJNI.h"
+#include "SkUtils.h"
+#include "SkTemplates.h"
+#include "SkPixelRef.h"
+#include "SkStream.h"
+#include "BitmapFactory.h"
+#include "AutoDecodeCancel.h"
+#include "SkBitmapRegionDecoder.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+#include "Utils.h"
+
+#include <android_runtime/AndroidRuntime.h>
+#include "android_util_Binder.h"
+#include "android_nio_utils.h"
+#include "CreateJavaOutputStreamAdaptor.h"
+
+#include <binder/Parcel.h>
+#include <jni.h>
+#include <utils/Asset.h>
+#include <sys/stat.h>
+
+static jclass gFileDescriptor_class;
+static jfieldID gFileDescriptor_descriptor;
+
+#if 0
+ #define TRACE_BITMAP(code) code
+#else
+ #define TRACE_BITMAP(code)
+#endif
+
+using namespace android;
+
+static SkMemoryStream* buildSkMemoryStream(SkStream *stream) {
+ size_t bufferSize = 4096;
+ size_t streamLen = 0;
+ size_t len;
+ char* data = (char*)sk_malloc_throw(bufferSize);
+
+ while ((len = stream->read(data + streamLen,
+ bufferSize - streamLen)) != 0) {
+ streamLen += len;
+ if (streamLen == bufferSize) {
+ bufferSize *= 2;
+ data = (char*)sk_realloc_throw(data, bufferSize);
+ }
+ }
+ data = (char*)sk_realloc_throw(data, streamLen);
+
+ SkMemoryStream* streamMem = new SkMemoryStream();
+ streamMem->setMemoryOwned(data, streamLen);
+ return streamMem;
+}
+
+static jobject doBuildTileIndex(JNIEnv* env, SkStream* stream) {
+ SkImageDecoder* decoder = SkImageDecoder::Factory(stream);
+ int width, height;
+ if (NULL == decoder) {
+ doThrowIOE(env, "Image format not supported");
+ return nullObjectReturn("SkImageDecoder::Factory returned null");
+ }
+
+ JavaPixelAllocator *javaAllocator = new JavaPixelAllocator(env, true);
+ decoder->setAllocator(javaAllocator);
+ JavaMemoryUsageReporter *javaMemoryReporter = new JavaMemoryUsageReporter(env);
+ decoder->setReporter(javaMemoryReporter);
+ javaAllocator->unref();
+ javaMemoryReporter->unref();
+
+ if (!decoder->buildTileIndex(stream, &width, &height)) {
+ char msg[100];
+ snprintf(msg, sizeof(msg), "Image failed to decode using %s decoder",
+ decoder->getFormatName());
+ doThrowIOE(env, msg);
+ return nullObjectReturn("decoder->buildTileIndex returned false");
+ }
+
+ SkBitmapRegionDecoder *bm = new SkBitmapRegionDecoder(decoder, width, height);
+
+ return GraphicsJNI::createBitmapRegionDecoder(env, bm);
+}
+
+static jobject nativeNewInstanceFromByteArray(JNIEnv* env, jobject, jbyteArray byteArray,
+ int offset, int length, jboolean isShareable) {
+ /* If isShareable we could decide to just wrap the java array and
+ share it, but that means adding a globalref to the java array object
+ For now we just always copy the array's data if isShareable.
+ */
+ AutoJavaByteArray ar(env, byteArray);
+ SkStream* stream = new SkMemoryStream(ar.ptr() + offset, length, true);
+ return doBuildTileIndex(env, stream);
+}
+
+static jobject nativeNewInstanceFromFileDescriptor(JNIEnv* env, jobject clazz,
+ jobject fileDescriptor, jboolean isShareable) {
+ NPE_CHECK_RETURN_ZERO(env, fileDescriptor);
+
+ jint descriptor = env->GetIntField(fileDescriptor,
+ gFileDescriptor_descriptor);
+ SkStream *stream = NULL;
+ struct stat fdStat;
+ int newFD;
+ if (fstat(descriptor, &fdStat) == -1) {
+ doThrowIOE(env, "broken file descriptor");
+ return nullObjectReturn("fstat return -1");
+ }
+
+ if (isShareable &&
+ S_ISREG(fdStat.st_mode) &&
+ (newFD = ::dup(descriptor)) != -1) {
+ SkFDStream* fdStream = new SkFDStream(newFD, true);
+ if (!fdStream->isValid()) {
+ fdStream->unref();
+ return NULL;
+ }
+ stream = fdStream;
+ } else {
+ /* Restore our offset when we leave, so we can be called more than once
+ with the same descriptor. This is only required if we didn't dup the
+ file descriptor, but it is OK to do it all the time.
+ */
+ AutoFDSeek as(descriptor);
+
+ SkFDStream* fdStream = new SkFDStream(descriptor, false);
+ if (!fdStream->isValid()) {
+ fdStream->unref();
+ return NULL;
+ }
+ stream = buildSkMemoryStream(fdStream);
+ fdStream->unref();
+ }
+
+ return doBuildTileIndex(env, stream);
+}
+
+static jobject nativeNewInstanceFromStream(JNIEnv* env, jobject clazz,
+ jobject is, // InputStream
+ jbyteArray storage, // byte[]
+ jboolean isShareable) {
+ jobject largeBitmap = NULL;
+ SkStream* stream = CreateJavaInputStreamAdaptor(env, is, storage, 1024);
+
+ if (stream) {
+ // for now we don't allow shareable with java inputstreams
+ SkMemoryStream *mStream = buildSkMemoryStream(stream);
+ largeBitmap = doBuildTileIndex(env, mStream);
+ stream->unref();
+ }
+ return largeBitmap;
+}
+
+static jobject nativeNewInstanceFromAsset(JNIEnv* env, jobject clazz,
+ jint native_asset, // Asset
+ jboolean isShareable) {
+ SkStream* stream, *assStream;
+ Asset* asset = reinterpret_cast<Asset*>(native_asset);
+ assStream = new AssetStreamAdaptor(asset);
+ stream = buildSkMemoryStream(assStream);
+ assStream->unref();
+ return doBuildTileIndex(env, stream);
+}
+
+/*
+ * nine patch not supported
+ *
+ * purgeable not supported
+ * reportSizeToVM not supported
+ */
+static jobject nativeDecodeRegion(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd,
+ int start_x, int start_y, int width, int height, jobject options) {
+ SkImageDecoder *decoder = brd->getDecoder();
+ int sampleSize = 1;
+ SkBitmap::Config prefConfig = SkBitmap::kNo_Config;
+ bool doDither = true;
+ bool preferQualityOverSpeed = false;
+
+ if (NULL != options) {
+ sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
+ // initialize these, in case we fail later on
+ env->SetIntField(options, gOptions_widthFieldID, -1);
+ env->SetIntField(options, gOptions_heightFieldID, -1);
+ env->SetObjectField(options, gOptions_mimeFieldID, 0);
+
+ jobject jconfig = env->GetObjectField(options, gOptions_configFieldID);
+ prefConfig = GraphicsJNI::getNativeBitmapConfig(env, jconfig);
+ doDither = env->GetBooleanField(options, gOptions_ditherFieldID);
+ preferQualityOverSpeed = env->GetBooleanField(options,
+ gOptions_preferQualityOverSpeedFieldID);
+ }
+
+ decoder->setDitherImage(doDither);
+ decoder->setPreferQualityOverSpeed(preferQualityOverSpeed);
+ SkBitmap* bitmap = new SkBitmap;
+ SkAutoTDelete<SkBitmap> adb(bitmap);
+ AutoDecoderCancel adc(options, decoder);
+
+ // To fix the race condition in case "requestCancelDecode"
+ // happens earlier than AutoDecoderCancel object is added
+ // to the gAutoDecoderCancelMutex linked list.
+ if (NULL != options && env->GetBooleanField(options, gOptions_mCancelID)) {
+ return nullObjectReturn("gOptions_mCancelID");;
+ }
+
+ SkIRect region;
+ region.fLeft = start_x;
+ region.fTop = start_y;
+ region.fRight = start_x + width;
+ region.fBottom = start_y + height;
+
+ if (!brd->decodeRegion(bitmap, region, prefConfig, sampleSize)) {
+ return nullObjectReturn("decoder->decodeRegion returned false");
+ }
+
+ // update options (if any)
+ if (NULL != options) {
+ env->SetIntField(options, gOptions_widthFieldID, bitmap->width());
+ env->SetIntField(options, gOptions_heightFieldID, bitmap->height());
+ // TODO: set the mimeType field with the data from the codec.
+ // but how to reuse a set of strings, rather than allocating new one
+ // each time?
+ env->SetObjectField(options, gOptions_mimeFieldID,
+ getMimeTypeString(env, decoder->getFormat()));
+ }
+
+ // detach bitmap from its autotdeleter, since we want to own it now
+ adb.detach();
+
+ SkPixelRef* pr;
+ pr = bitmap->pixelRef();
+ // promise we will never change our pixels (great for sharing and pictures)
+ pr->setImmutable();
+ // now create the java bitmap
+ return GraphicsJNI::createBitmap(env, bitmap, false, NULL);
+}
+
+static int nativeGetHeight(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
+ return brd->getHeight();
+}
+
+static int nativeGetWidth(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
+ return brd->getWidth();
+}
+
+static void nativeClean(JNIEnv* env, jobject, SkBitmapRegionDecoder *brd) {
+ delete brd;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+#include <android_runtime/AndroidRuntime.h>
+
+static JNINativeMethod gBitmapRegionDecoderMethods[] = {
+ { "nativeDecodeRegion",
+ "(IIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
+ (void*)nativeDecodeRegion},
+
+ { "nativeGetHeight", "(I)I", (void*)nativeGetHeight},
+
+ { "nativeGetWidth", "(I)I", (void*)nativeGetWidth},
+
+ { "nativeClean", "(I)V", (void*)nativeClean},
+
+ { "nativeNewInstance",
+ "([BIIZ)Landroid/graphics/BitmapRegionDecoder;",
+ (void*)nativeNewInstanceFromByteArray
+ },
+
+ { "nativeNewInstance",
+ "(Ljava/io/InputStream;[BZ)Landroid/graphics/BitmapRegionDecoder;",
+ (void*)nativeNewInstanceFromStream
+ },
+
+ { "nativeNewInstance",
+ "(Ljava/io/FileDescriptor;Z)Landroid/graphics/BitmapRegionDecoder;",
+ (void*)nativeNewInstanceFromFileDescriptor
+ },
+
+ { "nativeNewInstance",
+ "(IZ)Landroid/graphics/BitmapRegionDecoder;",
+ (void*)nativeNewInstanceFromAsset
+ },
+};
+
+#define kClassPathName "android/graphics/BitmapRegionDecoder"
+
+static jclass make_globalref(JNIEnv* env, const char classname[]) {
+ jclass c = env->FindClass(classname);
+ SkASSERT(c);
+ return (jclass)env->NewGlobalRef(c);
+}
+
+static jfieldID getFieldIDCheck(JNIEnv* env, jclass clazz,
+ const char fieldname[], const char type[]) {
+ jfieldID id = env->GetFieldID(clazz, fieldname, type);
+ SkASSERT(id);
+ return id;
+}
+
+int register_android_graphics_BitmapRegionDecoder(JNIEnv* env);
+int register_android_graphics_BitmapRegionDecoder(JNIEnv* env)
+{
+
+ gFileDescriptor_class = make_globalref(env, "java/io/FileDescriptor");
+ gFileDescriptor_descriptor = getFieldIDCheck(env, gFileDescriptor_class, "descriptor", "I");
+ return android::AndroidRuntime::registerNativeMethods(env, kClassPathName,
+ gBitmapRegionDecoderMethods, SK_ARRAY_COUNT(gBitmapRegionDecoderMethods));
+}
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 195f4d2..9467be8 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -46,7 +46,7 @@ void doThrowOOME(JNIEnv* env, const char* msg) {
}
void doThrowIOE(JNIEnv* env, const char* msg) {
- doThrow(env, "java/lang/IOException", msg);
+ doThrow(env, "java/io/IOException", msg);
}
bool GraphicsJNI::hasException(JNIEnv *env) {
@@ -168,6 +168,9 @@ static jmethodID gBitmap_allocBufferMethodID;
static jclass gBitmapConfig_class;
static jfieldID gBitmapConfig_nativeInstanceID;
+static jclass gBitmapRegionDecoder_class;
+static jmethodID gBitmapRegionDecoder_constructorMethodID;
+
static jclass gCanvas_class;
static jfieldID gCanvas_nativeInstanceID;
@@ -374,6 +377,24 @@ jobject GraphicsJNI::createBitmap(JNIEnv* env, SkBitmap* bitmap, bool isMutable,
return obj;
}
+jobject GraphicsJNI::createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap)
+{
+ SkASSERT(bitmap != NULL);
+
+ jobject obj = env->AllocObject(gBitmapRegionDecoder_class);
+ if (hasException(env)) {
+ obj = NULL;
+ return obj;
+ }
+ if (obj) {
+ env->CallVoidMethod(obj, gBitmapRegionDecoder_constructorMethodID, (jint)bitmap);
+ if (hasException(env)) {
+ obj = NULL;
+ }
+ }
+ return obj;
+}
+
jobject GraphicsJNI::createRegion(JNIEnv* env, SkRegion* region)
{
SkASSERT(region != NULL);
@@ -592,6 +613,9 @@ int register_android_graphics_Graphics(JNIEnv* env)
gBitmap_constructorMethodID = env->GetMethodID(gBitmap_class, "<init>",
"(IZ[BI)V");
+ gBitmapRegionDecoder_class = make_globalref(env, "android/graphics/BitmapRegionDecoder");
+ gBitmapRegionDecoder_constructorMethodID = env->GetMethodID(gBitmapRegionDecoder_class, "<init>", "(I)V");
+
gBitmapConfig_class = make_globalref(env, "android/graphics/Bitmap$Config");
gBitmapConfig_nativeInstanceID = getFieldIDCheck(env, gBitmapConfig_class,
"nativeInt", "I");
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index 1f94418..d0f9125 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -4,6 +4,7 @@
#include "SkPoint.h"
#include "SkRect.h"
#include "SkBitmap.h"
+#include "../images/SkBitmapRegionDecoder.h"
#include "../images/SkImageDecoder.h"
#include <jni.h>
@@ -55,6 +56,8 @@ public:
static jobject createRegion(JNIEnv* env, SkRegion* region);
+ static jobject createBitmapRegionDecoder(JNIEnv* env, SkBitmapRegionDecoder* bitmap);
+
/** Set a pixelref for the bitmap (needs setConfig to already be called)
Returns true on success. If it returns false, then it failed, and the
appropriate exception will have been raised.
diff --git a/core/res/res/values-ar/donottranslate-cldr.xml b/core/res/res/values-ar/donottranslate-cldr.xml
new file mode 100644
index 0000000..d662590
--- /dev/null
+++ b/core/res/res/values-ar/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">يناير</string>
+ <string name="month_long_standalone_february">فبراير</string>
+ <string name="month_long_standalone_march">مارس</string>
+ <string name="month_long_standalone_april">أبريل</string>
+ <string name="month_long_standalone_may">مايو</string>
+ <string name="month_long_standalone_june">يونيو</string>
+ <string name="month_long_standalone_july">يوليو</string>
+ <string name="month_long_standalone_august">أغسطس</string>
+ <string name="month_long_standalone_september">سبتمبر</string>
+ <string name="month_long_standalone_october">أكتوبر</string>
+ <string name="month_long_standalone_november">نوفمبر</string>
+ <string name="month_long_standalone_december">ديسمبر</string>
+
+ <string name="month_long_january">يناير</string>
+ <string name="month_long_february">فبراير</string>
+ <string name="month_long_march">مارس</string>
+ <string name="month_long_april">أبريل</string>
+ <string name="month_long_may">مايو</string>
+ <string name="month_long_june">يونيو</string>
+ <string name="month_long_july">يوليو</string>
+ <string name="month_long_august">أغسطس</string>
+ <string name="month_long_september">سبتمبر</string>
+ <string name="month_long_october">أكتوبر</string>
+ <string name="month_long_november">نوفمبر</string>
+ <string name="month_long_december">ديسمبر</string>
+
+ <string name="month_medium_january">يناير</string>
+ <string name="month_medium_february">فبراير</string>
+ <string name="month_medium_march">مارس</string>
+ <string name="month_medium_april">أبريل</string>
+ <string name="month_medium_may">مايو</string>
+ <string name="month_medium_june">يونيو</string>
+ <string name="month_medium_july">يوليو</string>
+ <string name="month_medium_august">أغسطس</string>
+ <string name="month_medium_september">سبتمبر</string>
+ <string name="month_medium_october">أكتوبر</string>
+ <string name="month_medium_november">نوفمبر</string>
+ <string name="month_medium_december">ديسمبر</string>
+
+ <string name="month_shortest_january">ي</string>
+ <string name="month_shortest_february">ف</string>
+ <string name="month_shortest_march">م</string>
+ <string name="month_shortest_april">أ</string>
+ <string name="month_shortest_may">و</string>
+ <string name="month_shortest_june">ن</string>
+ <string name="month_shortest_july">ل</string>
+ <string name="month_shortest_august">غ</string>
+ <string name="month_shortest_september">س</string>
+ <string name="month_shortest_october">ك</string>
+ <string name="month_shortest_november">ب</string>
+ <string name="month_shortest_december">د</string>
+
+ <string name="day_of_week_long_sunday">الأحد</string>
+ <string name="day_of_week_long_monday">الإثنين</string>
+ <string name="day_of_week_long_tuesday">الثلاثاء</string>
+ <string name="day_of_week_long_wednesday">الأربعاء</string>
+ <string name="day_of_week_long_thursday">الخميس</string>
+ <string name="day_of_week_long_friday">الجمعة</string>
+ <string name="day_of_week_long_saturday">السبت</string>
+
+ <string name="day_of_week_medium_sunday">أحد</string>
+ <string name="day_of_week_medium_monday">إثنين</string>
+ <string name="day_of_week_medium_tuesday">ثلاثاء</string>
+ <string name="day_of_week_medium_wednesday">أربعاء</string>
+ <string name="day_of_week_medium_thursday">خميس</string>
+ <string name="day_of_week_medium_friday">جمعة</string>
+ <string name="day_of_week_medium_saturday">سبت</string>
+
+ <string name="day_of_week_short_sunday">أحد</string>
+ <string name="day_of_week_short_monday">إثنين</string>
+ <string name="day_of_week_short_tuesday">ثلاثاء</string>
+ <string name="day_of_week_short_wednesday">أربعاء</string>
+ <string name="day_of_week_short_thursday">خميس</string>
+ <string name="day_of_week_short_friday">جمعة</string>
+ <string name="day_of_week_short_saturday">سبت</string>
+
+ <string name="day_of_week_shortest_sunday">ح</string>
+ <string name="day_of_week_shortest_monday">ن</string>
+ <string name="day_of_week_shortest_tuesday">ث</string>
+ <string name="day_of_week_shortest_wednesday">ر</string>
+ <string name="day_of_week_shortest_thursday">خ</string>
+ <string name="day_of_week_shortest_friday">ج</string>
+ <string name="day_of_week_shortest_saturday">س</string>
+
+ <string name="am">ص</string>
+ <string name="pm">م</string>
+ <string name="yesterday">أمس</string>
+ <string name="today">اليوم</string>
+ <string name="tomorrow">غدًا</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%-e‏/%-m‏/%Y</string>
+ <string name="numeric_date_format">d‏/M‏/yyyy</string>
+ <string name="numeric_date_template">"%s‏/%s‏/%s"</string>
+ <string name="month_day_year">%-e %B، %Y</string>
+ <string name="time_of_day">%-l:%M:%S %p</string>
+ <string name="date_and_time">%-l:%M:%S %p %d‏/%m‏/%Y</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%d‏/%m‏/%Y</string>
+ <string name="month_day">%-e %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%-e %b</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s – %2$s</string>
+ <string name="date1_date2">%2$s – %5$s</string>
+ <string name="numeric_md1_md2">%3$s‏/%2$s - %8$s‏/%7$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s، %3$s/‏%2$s - %6$s، %8$s/‏%7$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s‏/%2$s‏/%4$s - %8$s‏/%7$s‏/%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s، %3$s‏/%2$s‏/%4$s - %6$s، %8$s‏/%7$s‏/%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s، %3$s/‏%2$s/‏%4$s – %10$s %6$s، %8$s/‏%7$s/‏%9$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s/‏%2$s – %10$s %8$s/‏%7$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s، %3$s-%2$s – %10$s %6$s، %8$s-%7$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s‏/%2$s‏/%4$s – %10$s %8$s‏/%7$s‏/%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s %3$s</string>
+ <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s %2$s – %8$s %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s – %6$s %8$s %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s – %10$s %8$s %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s – %10$s %8$s %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s – %10$s %6$s %8$s %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s، %4$s – %10$s %8$s %7$s، %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s، %4$s – %10$s %8$s %7$s، %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s، %3$s %2$s %4$s – %10$s %6$s، %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s، %3$s %2$s %4$s – %10$s %6$s، %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s، %3$s %2$s %4$s – %6$s، %8$s %7$s %9$s</string>
+ <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s – %6$s %8$s %7$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s، %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s، %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s، %3$s %2$s - %6$s، %8$s %7$s، %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E d MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE، d MMMM y</string>
+</resources>
diff --git a/core/res/res/values-bg/donottranslate-cldr.xml b/core/res/res/values-bg/donottranslate-cldr.xml
new file mode 100644
index 0000000..c15e4a7
--- /dev/null
+++ b/core/res/res/values-bg/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">януари</string>
+ <string name="month_long_standalone_february">февруари</string>
+ <string name="month_long_standalone_march">март</string>
+ <string name="month_long_standalone_april">април</string>
+ <string name="month_long_standalone_may">май</string>
+ <string name="month_long_standalone_june">юни</string>
+ <string name="month_long_standalone_july">юли</string>
+ <string name="month_long_standalone_august">август</string>
+ <string name="month_long_standalone_september">септември</string>
+ <string name="month_long_standalone_october">октомври</string>
+ <string name="month_long_standalone_november">ноември</string>
+ <string name="month_long_standalone_december">декември</string>
+
+ <string name="month_long_january">януари</string>
+ <string name="month_long_february">февруари</string>
+ <string name="month_long_march">март</string>
+ <string name="month_long_april">април</string>
+ <string name="month_long_may">май</string>
+ <string name="month_long_june">юни</string>
+ <string name="month_long_july">юли</string>
+ <string name="month_long_august">август</string>
+ <string name="month_long_september">септември</string>
+ <string name="month_long_october">октомври</string>
+ <string name="month_long_november">ноември</string>
+ <string name="month_long_december">декември</string>
+
+ <string name="month_medium_january">ян.</string>
+ <string name="month_medium_february">февр.</string>
+ <string name="month_medium_march">март</string>
+ <string name="month_medium_april">апр.</string>
+ <string name="month_medium_may">май</string>
+ <string name="month_medium_june">юни</string>
+ <string name="month_medium_july">юли</string>
+ <string name="month_medium_august">авг.</string>
+ <string name="month_medium_september">септ.</string>
+ <string name="month_medium_october">окт.</string>
+ <string name="month_medium_november">ноем.</string>
+ <string name="month_medium_december">дек.</string>
+
+ <string name="month_shortest_january">я</string>
+ <string name="month_shortest_february">ф</string>
+ <string name="month_shortest_march">м</string>
+ <string name="month_shortest_april">а</string>
+ <string name="month_shortest_may">м</string>
+ <string name="month_shortest_june">ю</string>
+ <string name="month_shortest_july">ю</string>
+ <string name="month_shortest_august">а</string>
+ <string name="month_shortest_september">с</string>
+ <string name="month_shortest_october">о</string>
+ <string name="month_shortest_november">н</string>
+ <string name="month_shortest_december">д</string>
+
+ <string name="day_of_week_long_sunday">неделя</string>
+ <string name="day_of_week_long_monday">понеделник</string>
+ <string name="day_of_week_long_tuesday">вторник</string>
+ <string name="day_of_week_long_wednesday">сряда</string>
+ <string name="day_of_week_long_thursday">четвъртък</string>
+ <string name="day_of_week_long_friday">петък</string>
+ <string name="day_of_week_long_saturday">събота</string>
+
+ <string name="day_of_week_medium_sunday">нд</string>
+ <string name="day_of_week_medium_monday">пн</string>
+ <string name="day_of_week_medium_tuesday">вт</string>
+ <string name="day_of_week_medium_wednesday">ср</string>
+ <string name="day_of_week_medium_thursday">чт</string>
+ <string name="day_of_week_medium_friday">пт</string>
+ <string name="day_of_week_medium_saturday">сб</string>
+
+ <string name="day_of_week_short_sunday">нд</string>
+ <string name="day_of_week_short_monday">пн</string>
+ <string name="day_of_week_short_tuesday">вт</string>
+ <string name="day_of_week_short_wednesday">ср</string>
+ <string name="day_of_week_short_thursday">чт</string>
+ <string name="day_of_week_short_friday">пт</string>
+ <string name="day_of_week_short_saturday">сб</string>
+
+ <string name="day_of_week_shortest_sunday">н</string>
+ <string name="day_of_week_shortest_monday">п</string>
+ <string name="day_of_week_shortest_tuesday">в</string>
+ <string name="day_of_week_shortest_wednesday">с</string>
+ <string name="day_of_week_shortest_thursday">ч</string>
+ <string name="day_of_week_shortest_friday">п</string>
+ <string name="day_of_week_shortest_saturday">с</string>
+
+ <string name="am">пр. об.</string>
+ <string name="pm">сл. об.</string>
+ <string name="yesterday">Вчера</string>
+ <string name="today">Днес</string>
+ <string name="tomorrow">Утре</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%d.%m.%Y</string>
+ <string name="numeric_date_format">dd.MM.yyyy</string>
+ <string name="numeric_date_template">"%s.%s.%s"</string>
+ <string name="month_day_year">%d %B %Y</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %d.%m.%Y</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%d.%m.%Y</string>
+ <string name="month_day">%-e %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%-e %b</string>
+ <string name="abbrev_month">%b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%3$s.%2$s - %8$s.%7$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%3$s.%2$s, %1$s - %8$s.%7$s, %6$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%3$s.%2$s.%4$s, %1$s - %8$s.%7$s.%9$s, %6$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s.%2$s.%4$s, %1$s - %10$s %8$s.%7$s.%9$s, %6$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s - %10$s %8$s.%7$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %3$s.%2$s, %1$s - %10$s %8$s.%7$s, %6$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %2$s, %1$s - %6$s %5$s, %4$s</string>
+ <string name="wday1_date1_wday2_date2">%2$s, %1$s - %5$s, %4$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %3$s, %2$s</string>
+ <string name="wday_date">%3$s, %2$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s - %10$s %8$s %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s - %10$s %8$s %7$s %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s %2$s %4$s, %1$s - %10$s %8$s %7$s %9$s, %6$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %3$s %2$s %4$s, %1$s - %10$s %8$s %7$s %9$s, %6$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%3$s %2$s %4$s, %1$s - %8$s %7$s %9$s, %6$s</string>
+ <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%3$s %2$s %9$s, %1$s - %8$s %7$s y, %6$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E MMMM d</string>
+ <string name="abbrev_wday_month_day_year">d MMM y, E</string>
+</resources>
diff --git a/core/res/res/values-ca/donottranslate-cldr.xml b/core/res/res/values-ca/donottranslate-cldr.xml
new file mode 100644
index 0000000..a77aa38
--- /dev/null
+++ b/core/res/res/values-ca/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">gener</string>
+ <string name="month_long_standalone_february">febrer</string>
+ <string name="month_long_standalone_march">març</string>
+ <string name="month_long_standalone_april">abril</string>
+ <string name="month_long_standalone_may">maig</string>
+ <string name="month_long_standalone_june">juny</string>
+ <string name="month_long_standalone_july">juliol</string>
+ <string name="month_long_standalone_august">agost</string>
+ <string name="month_long_standalone_september">setembre</string>
+ <string name="month_long_standalone_october">octubre</string>
+ <string name="month_long_standalone_november">novembre</string>
+ <string name="month_long_standalone_december">desembre</string>
+
+ <string name="month_long_january">gener</string>
+ <string name="month_long_february">febrer</string>
+ <string name="month_long_march">març</string>
+ <string name="month_long_april">abril</string>
+ <string name="month_long_may">maig</string>
+ <string name="month_long_june">juny</string>
+ <string name="month_long_july">juliol</string>
+ <string name="month_long_august">agost</string>
+ <string name="month_long_september">setembre</string>
+ <string name="month_long_october">octubre</string>
+ <string name="month_long_november">novembre</string>
+ <string name="month_long_december">desembre</string>
+
+ <string name="month_medium_january">gen.</string>
+ <string name="month_medium_february">febr.</string>
+ <string name="month_medium_march">març</string>
+ <string name="month_medium_april">abr.</string>
+ <string name="month_medium_may">maig</string>
+ <string name="month_medium_june">juny</string>
+ <string name="month_medium_july">jul.</string>
+ <string name="month_medium_august">ag.</string>
+ <string name="month_medium_september">set.</string>
+ <string name="month_medium_october">oct.</string>
+ <string name="month_medium_november">nov.</string>
+ <string name="month_medium_december">des.</string>
+
+ <string name="month_shortest_january">g</string>
+ <string name="month_shortest_february">f</string>
+ <string name="month_shortest_march">m</string>
+ <string name="month_shortest_april">a</string>
+ <string name="month_shortest_may">m</string>
+ <string name="month_shortest_june">j</string>
+ <string name="month_shortest_july">j</string>
+ <string name="month_shortest_august">a</string>
+ <string name="month_shortest_september">s</string>
+ <string name="month_shortest_october">o</string>
+ <string name="month_shortest_november">n</string>
+ <string name="month_shortest_december">d</string>
+
+ <string name="day_of_week_long_sunday">diumenge</string>
+ <string name="day_of_week_long_monday">dilluns</string>
+ <string name="day_of_week_long_tuesday">dimarts</string>
+ <string name="day_of_week_long_wednesday">dimecres</string>
+ <string name="day_of_week_long_thursday">dijous</string>
+ <string name="day_of_week_long_friday">divendres</string>
+ <string name="day_of_week_long_saturday">dissabte</string>
+
+ <string name="day_of_week_medium_sunday">dg.</string>
+ <string name="day_of_week_medium_monday">dl.</string>
+ <string name="day_of_week_medium_tuesday">dt.</string>
+ <string name="day_of_week_medium_wednesday">dc.</string>
+ <string name="day_of_week_medium_thursday">dj.</string>
+ <string name="day_of_week_medium_friday">dv.</string>
+ <string name="day_of_week_medium_saturday">ds.</string>
+
+ <string name="day_of_week_short_sunday">dg.</string>
+ <string name="day_of_week_short_monday">dl.</string>
+ <string name="day_of_week_short_tuesday">dt.</string>
+ <string name="day_of_week_short_wednesday">dc.</string>
+ <string name="day_of_week_short_thursday">dj.</string>
+ <string name="day_of_week_short_friday">dv.</string>
+ <string name="day_of_week_short_saturday">ds.</string>
+
+ <string name="day_of_week_shortest_sunday">g</string>
+ <string name="day_of_week_shortest_monday">l</string>
+ <string name="day_of_week_shortest_tuesday">t</string>
+ <string name="day_of_week_shortest_wednesday">c</string>
+ <string name="day_of_week_shortest_thursday">j</string>
+ <string name="day_of_week_shortest_friday">v</string>
+ <string name="day_of_week_shortest_saturday">s</string>
+
+ <string name="am">a.m.</string>
+ <string name="pm">p.m.</string>
+ <string name="yesterday">ahir</string>
+ <string name="today">avui</string>
+ <string name="tomorrow">demà</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%d/%m/%Y</string>
+ <string name="numeric_date_format">dd/MM/yyyy</string>
+ <string name="numeric_date_template">"%s/%s/%s"</string>
+ <string name="month_day_year">%-e de %B de %Y</string>
+ <string name="time_of_day">%-k:%M:%S</string>
+ <string name="date_and_time">%-k:%M:%S %d/%m/%Y</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%d/%m/%Y</string>
+ <string name="month_day">%-e de %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%-B del %Y</string>
+ <string name="abbrev_month_day">%-e %b</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%3$s/%2$s - %8$s/%7$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s %3$s/%2$s - %6$s %8$s/%7$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s/%2$s/%4$s - %8$s/%7$s/%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s/%2$s/%4$s - %10$s %6$s %8$s/%7$s/%9$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s/%2$s - %10$s %8$s/%7$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s/%2$s - %10$s %6$s %8$s/%7$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s/%2$s/%4$s - %10$s %8$s/%7$s/%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s - %6$s %4$s %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s %3$s</string>
+ <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s de %2$s - %8$s de %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s de %2$s - %10$s %8$s de %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s de %2$s - %10$s %8$s de %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s %2$s - %10$s %6$s %8$s %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s de %2$s de %4$s - %10$s %8$s de %7$s de %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s de %2$s de %4$s - %10$s %8$s de %7$s de %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s %2$s %4$s - %10$s %6$s %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s %4$s - %6$s %8$s %7$s %9$s</string>
+ <string name="same_month_md1_md2">%3$s-%8$s de %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s de %2$s - %8$s de %7$s de %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s-%8$s de %2$s de %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s de %2$s - %6$s %8$s de %7$s de %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E d MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
+</resources>
diff --git a/core/res/res/values-fa/donottranslate-cldr.xml b/core/res/res/values-fa/donottranslate-cldr.xml
new file mode 100644
index 0000000..83f4942
--- /dev/null
+++ b/core/res/res/values-fa/donottranslate-cldr.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">ژانویه</string>
+ <string name="month_long_standalone_february">فوریه</string>
+ <string name="month_long_standalone_march">مارس</string>
+ <string name="month_long_standalone_april">آوریل</string>
+ <string name="month_long_standalone_may">مه</string>
+ <string name="month_long_standalone_june">ژوئن</string>
+ <string name="month_long_standalone_july">ژوئیه</string>
+ <string name="month_long_standalone_august">اوت</string>
+ <string name="month_long_standalone_september">سپتامبر</string>
+ <string name="month_long_standalone_october">اکتبر</string>
+ <string name="month_long_standalone_november">نوامبر</string>
+ <string name="month_long_standalone_december">دسامبر</string>
+
+ <string name="month_long_january">ژانویهٔ</string>
+ <string name="month_long_february">فوریهٔ</string>
+ <string name="month_long_march">مارس</string>
+ <string name="month_long_april">آوریل</string>
+ <string name="month_long_may">مهٔ</string>
+ <string name="month_long_june">ژوئن</string>
+ <string name="month_long_july">ژوئیهٔ</string>
+ <string name="month_long_august">اوت</string>
+ <string name="month_long_september">سپتامبر</string>
+ <string name="month_long_october">اکتبر</string>
+ <string name="month_long_november">نوامبر</string>
+ <string name="month_long_december">دسامبر</string>
+
+ <string name="month_medium_january">ژانویهٔ</string>
+ <string name="month_medium_february">فوریهٔ</string>
+ <string name="month_medium_march">مارس</string>
+ <string name="month_medium_april">آوریل</string>
+ <string name="month_medium_may">مهٔ</string>
+ <string name="month_medium_june">ژوئن</string>
+ <string name="month_medium_july">ژوئیهٔ</string>
+ <string name="month_medium_august">اوت</string>
+ <string name="month_medium_september">سپتامبر</string>
+ <string name="month_medium_october">اکتبر</string>
+ <string name="month_medium_november">نوامبر</string>
+ <string name="month_medium_december">دسامبر</string>
+
+ <string name="month_shortest_january">ژ</string>
+ <string name="month_shortest_february">ف</string>
+ <string name="month_shortest_march">م</string>
+ <string name="month_shortest_april">آ</string>
+ <string name="month_shortest_may">م</string>
+ <string name="month_shortest_june">ژ</string>
+ <string name="month_shortest_july">ژ</string>
+ <string name="month_shortest_august">ا</string>
+ <string name="month_shortest_september">س</string>
+ <string name="month_shortest_october">ا</string>
+ <string name="month_shortest_november">ن</string>
+ <string name="month_shortest_december">د</string>
+
+ <string name="day_of_week_long_sunday">یکشنبه</string>
+ <string name="day_of_week_long_monday">دوشنبه</string>
+ <string name="day_of_week_long_tuesday">سه‌شنبه</string>
+ <string name="day_of_week_long_wednesday">چهارشنبه</string>
+ <string name="day_of_week_long_thursday">پنجشنبه</string>
+ <string name="day_of_week_long_friday">جمعه</string>
+ <string name="day_of_week_long_saturday">شنبه</string>
+
+
+
+ <string name="day_of_week_shortest_sunday">ی</string>
+ <string name="day_of_week_shortest_monday">د</string>
+ <string name="day_of_week_shortest_tuesday">س</string>
+ <string name="day_of_week_shortest_wednesday">چ</string>
+ <string name="day_of_week_shortest_thursday">پ</string>
+ <string name="day_of_week_shortest_friday">ج</string>
+ <string name="day_of_week_shortest_saturday">ش</string>
+
+ <string name="am">قبل از ظهر</string>
+ <string name="pm">بعد از ظهر</string>
+ <string name="yesterday">دیروز</string>
+ <string name="today">امروز</string>
+ <string name="tomorrow">فردا</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%Y/%-m/%-e</string>
+ <string name="numeric_date_format">yyyy/M/d</string>
+ <string name="numeric_date_template">"%s/%s/%s"</string>
+ <string name="month_day_year">%-e %B %Y</string>
+ <string name="time_of_day">%-k:%M:%S</string>
+ <string name="date_and_time">%-k:%M:%S،‏ %Y/%-m/%-e</string>
+ <string name="date_time">%2$s،‏ %1$s</string>
+ <string name="time_date">%1$s،‏ %3$s</string>
+ <string name="abbrev_month_day_year">%Y/%-m/%-e</string>
+ <string name="month_day">%-e %-B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%-e %-b</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s تا %2$s</string>
+ <string name="date1_date2">%2$s تا %5$s</string>
+ <string name="numeric_md1_md2">%2$s/%3$s تا %7$s/%8$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s %2$s/%3$s تا %6$s %7$s/%8$s</string>
+ <string name="numeric_mdy1_mdy2">%4$s/%2$s/%3$s تا %9$s/%7$s/%8$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s %4$s/%2$s/%3$s تا %6$s %9$s/%7$s/%8$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s،‏ %1$s %4$s/%2$s/%3$s تا %10$s،‏ %6$s %9$s/%7$s/%8$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s،‏ %2$s/%3$s تا %10$s،‏ %7$s/%8$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s،‏ %1$s %2$s/%3$s تا %10$s،‏ %6$s %7$s/%8$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s،‏ %4$s/%2$s/%3$s تا %10$s،‏ %9$s/%7$s/%8$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s،‏ %1$s %2$s تا %6$s،‏ %4$s %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s %2$s تا %4$s %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s،‏ %2$s تا %6$s،‏ %5$s</string>
+ <string name="time_wday_date">%1$s،‏ %2$s %3$s</string>
+ <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday">%1$s،‏ %2$s</string>
+ <string name="same_year_md1_md2">%3$s LLLL تا %8$s LLLL</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s LLLL تا %6$s %8$s LLLL</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s،‏ %3$s LLLL تا %10$s،‏ %8$s LLLL</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s،‏ %3$s LLLL تا %10$s،‏ %8$s LLLL</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s،‏ %1$s %3$s LLLL تا %10$s،‏ %6$s %8$s LLLL</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s،‏ %1$s %3$s LLLL تا %10$s،‏ %6$s %8$s LLLL</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s،‏ %3$s %2$s %4$s تا %10$s،‏ %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s،‏ %3$s %2$s %4$s تا %10$s،‏ %8$s %7$s %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s،‏ %1$s %3$s %2$s %4$s تا %10$s،‏ %6$s %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s،‏ %1$s %3$s %2$s %4$s تا %10$s،‏ %6$s %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s %4$s تا %6$s %8$s %7$s %9$s</string>
+ <string name="same_month_md1_md2">%3$s تا %8$s LLL</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s LLLL تا %6$s %8$s LLLL</string>
+ <string name="same_year_mdy1_mdy2">%3$s LLL تا %8$s %2$s %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s تا %8$s %2$s %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s LLL تا %6$s %8$s %2$s %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E d LLLL</string>
+ <string name="abbrev_wday_month_day_year">E d MMM y</string>
+</resources>
diff --git a/core/res/res/values-fi/donottranslate-cldr.xml b/core/res/res/values-fi/donottranslate-cldr.xml
new file mode 100644
index 0000000..5146a0a
--- /dev/null
+++ b/core/res/res/values-fi/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">tammikuu</string>
+ <string name="month_long_standalone_february">helmikuu</string>
+ <string name="month_long_standalone_march">maaliskuu</string>
+ <string name="month_long_standalone_april">huhtikuu</string>
+ <string name="month_long_standalone_may">toukokuu</string>
+ <string name="month_long_standalone_june">kesäkuu</string>
+ <string name="month_long_standalone_july">heinäkuu</string>
+ <string name="month_long_standalone_august">elokuu</string>
+ <string name="month_long_standalone_september">syyskuu</string>
+ <string name="month_long_standalone_october">lokakuu</string>
+ <string name="month_long_standalone_november">marraskuu</string>
+ <string name="month_long_standalone_december">joulukuu</string>
+
+ <string name="month_long_january">tammikuuta</string>
+ <string name="month_long_february">helmikuuta</string>
+ <string name="month_long_march">maaliskuuta</string>
+ <string name="month_long_april">huhtikuuta</string>
+ <string name="month_long_may">toukokuuta</string>
+ <string name="month_long_june">kesäkuuta</string>
+ <string name="month_long_july">heinäkuuta</string>
+ <string name="month_long_august">elokuuta</string>
+ <string name="month_long_september">syyskuuta</string>
+ <string name="month_long_october">lokakuuta</string>
+ <string name="month_long_november">marraskuuta</string>
+ <string name="month_long_december">joulukuuta</string>
+
+ <string name="month_medium_january">tammikuuta</string>
+ <string name="month_medium_february">helmikuuta</string>
+ <string name="month_medium_march">maaliskuuta</string>
+ <string name="month_medium_april">huhtikuuta</string>
+ <string name="month_medium_may">toukokuuta</string>
+ <string name="month_medium_june">kesäkuuta</string>
+ <string name="month_medium_july">heinäkuuta</string>
+ <string name="month_medium_august">elokuuta</string>
+ <string name="month_medium_september">syyskuuta</string>
+ <string name="month_medium_october">lokakuuta</string>
+ <string name="month_medium_november">marraskuuta</string>
+ <string name="month_medium_december">joulukuuta</string>
+
+ <string name="month_shortest_january">T</string>
+ <string name="month_shortest_february">H</string>
+ <string name="month_shortest_march">M</string>
+ <string name="month_shortest_april">H</string>
+ <string name="month_shortest_may">T</string>
+ <string name="month_shortest_june">K</string>
+ <string name="month_shortest_july">H</string>
+ <string name="month_shortest_august">E</string>
+ <string name="month_shortest_september">S</string>
+ <string name="month_shortest_october">L</string>
+ <string name="month_shortest_november">M</string>
+ <string name="month_shortest_december">J</string>
+
+ <string name="day_of_week_long_sunday">sunnuntaina</string>
+ <string name="day_of_week_long_monday">maanantaina</string>
+ <string name="day_of_week_long_tuesday">tiistaina</string>
+ <string name="day_of_week_long_wednesday">keskiviikkona</string>
+ <string name="day_of_week_long_thursday">torstaina</string>
+ <string name="day_of_week_long_friday">perjantaina</string>
+ <string name="day_of_week_long_saturday">lauantaina</string>
+
+ <string name="day_of_week_medium_sunday">su</string>
+ <string name="day_of_week_medium_monday">ma</string>
+ <string name="day_of_week_medium_tuesday">ti</string>
+ <string name="day_of_week_medium_wednesday">ke</string>
+ <string name="day_of_week_medium_thursday">to</string>
+ <string name="day_of_week_medium_friday">pe</string>
+ <string name="day_of_week_medium_saturday">la</string>
+
+ <string name="day_of_week_short_sunday">su</string>
+ <string name="day_of_week_short_monday">ma</string>
+ <string name="day_of_week_short_tuesday">ti</string>
+ <string name="day_of_week_short_wednesday">ke</string>
+ <string name="day_of_week_short_thursday">to</string>
+ <string name="day_of_week_short_friday">pe</string>
+ <string name="day_of_week_short_saturday">la</string>
+
+ <string name="day_of_week_shortest_sunday">S</string>
+ <string name="day_of_week_shortest_monday">M</string>
+ <string name="day_of_week_shortest_tuesday">T</string>
+ <string name="day_of_week_shortest_wednesday">K</string>
+ <string name="day_of_week_shortest_thursday">T</string>
+ <string name="day_of_week_shortest_friday">P</string>
+ <string name="day_of_week_shortest_saturday">L</string>
+
+ <string name="am">ap.</string>
+ <string name="pm">ip.</string>
+ <string name="yesterday">eilen</string>
+ <string name="today">tänään</string>
+ <string name="tomorrow">huomenna</string>
+
+ <string name="hour_minute_24">%-k.%M</string>
+ <string name="hour_minute_ampm">%-l.%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l.%M %^p</string>
+ <string name="twelve_hour_time_format">h.mm a</string>
+ <string name="twenty_four_hour_time_format">H.mm</string>
+ <string name="numeric_date">%-e.%-m.%Y</string>
+ <string name="numeric_date_format">d.M.yyyy</string>
+ <string name="numeric_date_template">"%s.%s.%s"</string>
+ <string name="month_day_year">%-e. %B %Y</string>
+ <string name="time_of_day">%-k.%M.%S</string>
+ <string name="date_and_time">%-k.%M.%S %-e.%-m.%Y</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%-e.%-m.%Y</string>
+ <string name="month_day">%-e. %B</string>
+ <string name="month">%-b</string>
+ <string name="month_year">%-B %Y</string>
+ <string name="abbrev_month_day">%-e. %b</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%-b %Y</string>
+ <string name="time1_time2">%1$s–%2$s</string>
+ <string name="date1_date2">%2$s–%5$s</string>
+ <string name="numeric_md1_md2">%3$s.%2$s.–%8$s.%7$s.</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s %3$s.%2$s. – %6$s %8$s.%7$s.</string>
+ <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s–%8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s %3$s.%2$s.%4$s – %6$s %8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s.%2$s.%4$s–%10$s %6$s %8$s.%7$s.%9$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s.–%10$s %8$s.%7$s.</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s.%2$s.–%10$s %6$s %8$s.%7$s.</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s–%10$s %8$s.%7$s.%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s–%6$s %4$s %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s %2$s–%4$s %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s–%6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s %3$s</string>
+ <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s. %2$s–%8$s. %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s. %2$s–%6$s %8$s. %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s. %2$s–%10$s %8$s. %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s. %2$s–%10$s %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s. %2$s–%10$s %6$s %8$s. %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s. %2$s–%10$s %6$s %8$s. %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s–%10$s %8$s. %7$s %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s–%10$s %8$s. %7$s %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s. %2$s %4$s–%10$s %6$s %8$s. %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s %3$s. %2$s %4$s–%10$s %6$s %8$s. %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s %4$s–%6$s %8$s. %7$s %9$s</string>
+ <string name="same_month_md1_md2">%3$s.–%8$s. %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s. %2$s–%6$s %8$s. %7$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s. %2$s – %8$s. %7$s %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s.–%8$s. %2$s %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s. %2$s – %6$s %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E d. MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE d. MMM y</string>
+</resources>
diff --git a/core/res/res/values-hr/donottranslate-cldr.xml b/core/res/res/values-hr/donottranslate-cldr.xml
new file mode 100644
index 0000000..23332aa
--- /dev/null
+++ b/core/res/res/values-hr/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">siječanj</string>
+ <string name="month_long_standalone_february">veljača</string>
+ <string name="month_long_standalone_march">ožujak</string>
+ <string name="month_long_standalone_april">travanj</string>
+ <string name="month_long_standalone_may">svibanj</string>
+ <string name="month_long_standalone_june">lipanj</string>
+ <string name="month_long_standalone_july">srpanj</string>
+ <string name="month_long_standalone_august">kolovoz</string>
+ <string name="month_long_standalone_september">rujan</string>
+ <string name="month_long_standalone_october">listopad</string>
+ <string name="month_long_standalone_november">studeni</string>
+ <string name="month_long_standalone_december">prosinac</string>
+
+ <string name="month_long_january">siječnja</string>
+ <string name="month_long_february">veljače</string>
+ <string name="month_long_march">ožujka</string>
+ <string name="month_long_april">travnja</string>
+ <string name="month_long_may">svibnja</string>
+ <string name="month_long_june">lipnja</string>
+ <string name="month_long_july">srpnja</string>
+ <string name="month_long_august">kolovoza</string>
+ <string name="month_long_september">rujna</string>
+ <string name="month_long_october">listopada</string>
+ <string name="month_long_november">studenoga</string>
+ <string name="month_long_december">prosinca</string>
+
+ <string name="month_medium_january">01.</string>
+ <string name="month_medium_february">02.</string>
+ <string name="month_medium_march">03.</string>
+ <string name="month_medium_april">04.</string>
+ <string name="month_medium_may">05.</string>
+ <string name="month_medium_june">06.</string>
+ <string name="month_medium_july">07.</string>
+ <string name="month_medium_august">08.</string>
+ <string name="month_medium_september">09.</string>
+ <string name="month_medium_october">10.</string>
+ <string name="month_medium_november">11.</string>
+ <string name="month_medium_december">12.</string>
+
+ <string name="month_shortest_january">1.</string>
+ <string name="month_shortest_february">2.</string>
+ <string name="month_shortest_march">3.</string>
+ <string name="month_shortest_april">4.</string>
+ <string name="month_shortest_may">5.</string>
+ <string name="month_shortest_june">6.</string>
+ <string name="month_shortest_july">7.</string>
+ <string name="month_shortest_august">8.</string>
+ <string name="month_shortest_september">9.</string>
+ <string name="month_shortest_october">10.</string>
+ <string name="month_shortest_november">11.</string>
+ <string name="month_shortest_december">12.</string>
+
+ <string name="day_of_week_long_sunday">nedjelja</string>
+ <string name="day_of_week_long_monday">ponedjeljak</string>
+ <string name="day_of_week_long_tuesday">utorak</string>
+ <string name="day_of_week_long_wednesday">srijeda</string>
+ <string name="day_of_week_long_thursday">četvrtak</string>
+ <string name="day_of_week_long_friday">petak</string>
+ <string name="day_of_week_long_saturday">subota</string>
+
+ <string name="day_of_week_medium_sunday">ned</string>
+ <string name="day_of_week_medium_monday">pon</string>
+ <string name="day_of_week_medium_tuesday">uto</string>
+ <string name="day_of_week_medium_wednesday">sri</string>
+ <string name="day_of_week_medium_thursday">čet</string>
+ <string name="day_of_week_medium_friday">pet</string>
+ <string name="day_of_week_medium_saturday">sub</string>
+
+ <string name="day_of_week_short_sunday">ned</string>
+ <string name="day_of_week_short_monday">pon</string>
+ <string name="day_of_week_short_tuesday">uto</string>
+ <string name="day_of_week_short_wednesday">sri</string>
+ <string name="day_of_week_short_thursday">čet</string>
+ <string name="day_of_week_short_friday">pet</string>
+ <string name="day_of_week_short_saturday">sub</string>
+
+ <string name="day_of_week_shortest_sunday">n</string>
+ <string name="day_of_week_shortest_monday">p</string>
+ <string name="day_of_week_shortest_tuesday">u</string>
+ <string name="day_of_week_shortest_wednesday">s</string>
+ <string name="day_of_week_shortest_thursday">č</string>
+ <string name="day_of_week_shortest_friday">p</string>
+ <string name="day_of_week_shortest_saturday">s</string>
+
+ <string name="am">AM</string>
+ <string name="pm">PM</string>
+ <string name="yesterday">jučer</string>
+ <string name="today">danas</string>
+ <string name="tomorrow">sutra</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%-e.%-m.%Y.</string>
+ <string name="numeric_date_format">d.M.yyyy.</string>
+ <string name="numeric_date_template">"%s.%s.%s."</string>
+ <string name="month_day_year">%-e. %B %Y.</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %-e.%b.%Y.</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%-e.%b.%Y.</string>
+ <string name="month_day">%-e. %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y.</string>
+ <string name="abbrev_month_day">%-e.%b.</string>
+ <string name="abbrev_month">%-b.</string>
+ <string name="abbrev_month_year">%b.%Y.</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%3$s.%2$s. - %8$s.%7$s.</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s. - %6$s, %8$s.%7$s.</string>
+ <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s. - %8$s.%7$s.%9$s.</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s. - %6$s, %8$s.%7$s.%9$s.</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s. - %10$s %6$s, %8$s.%7$s.%9$s.</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s. - %10$s %8$s.%7$s.</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s.</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s. - %10$s %8$s.%7$s.%9$s.</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s, %3$s</string>
+ <string name="wday_date">%2$s, %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s. %2$s - %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s. - %10$s %8$s.%7$s.%9$s.</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s. - %10$s %8$s.%7$s.%9$s.</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s. - %10$s %6$s, %8$s.%7$s.%9$s.</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s. - %10$s %6$s, %8$s.%7$s.%9$s.</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s. - %6$s, %8$s.%7$s.%9$s.</string>
+ <string name="same_month_md1_md2">%3$s. - %8$s.%2$s.</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s.%2$s. - %8$s.%7$s.%9$s.</string>
+ <string name="same_month_mdy1_mdy2">%3$s. - %8$s.%2$s.%9$s.</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s. - %6$s, %8$s.%7$s.%9$s.</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E, d. MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE, d.MMM.y.</string>
+</resources>
diff --git a/core/res/res/values-hu/donottranslate-cldr.xml b/core/res/res/values-hu/donottranslate-cldr.xml
new file mode 100644
index 0000000..996eefb
--- /dev/null
+++ b/core/res/res/values-hu/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">január</string>
+ <string name="month_long_standalone_february">február</string>
+ <string name="month_long_standalone_march">március</string>
+ <string name="month_long_standalone_april">április</string>
+ <string name="month_long_standalone_may">május</string>
+ <string name="month_long_standalone_june">június</string>
+ <string name="month_long_standalone_july">július</string>
+ <string name="month_long_standalone_august">augusztus</string>
+ <string name="month_long_standalone_september">szeptember</string>
+ <string name="month_long_standalone_october">október</string>
+ <string name="month_long_standalone_november">november</string>
+ <string name="month_long_standalone_december">december</string>
+
+ <string name="month_long_january">január</string>
+ <string name="month_long_february">február</string>
+ <string name="month_long_march">március</string>
+ <string name="month_long_april">április</string>
+ <string name="month_long_may">május</string>
+ <string name="month_long_june">június</string>
+ <string name="month_long_july">július</string>
+ <string name="month_long_august">augusztus</string>
+ <string name="month_long_september">szeptember</string>
+ <string name="month_long_october">október</string>
+ <string name="month_long_november">november</string>
+ <string name="month_long_december">december</string>
+
+ <string name="month_medium_january">jan.</string>
+ <string name="month_medium_february">febr.</string>
+ <string name="month_medium_march">márc.</string>
+ <string name="month_medium_april">ápr.</string>
+ <string name="month_medium_may">máj.</string>
+ <string name="month_medium_june">jún.</string>
+ <string name="month_medium_july">júl.</string>
+ <string name="month_medium_august">aug.</string>
+ <string name="month_medium_september">szept.</string>
+ <string name="month_medium_october">okt.</string>
+ <string name="month_medium_november">nov.</string>
+ <string name="month_medium_december">dec.</string>
+
+ <string name="month_shortest_january">J</string>
+ <string name="month_shortest_february">F</string>
+ <string name="month_shortest_march">M</string>
+ <string name="month_shortest_april">Á</string>
+ <string name="month_shortest_may">M</string>
+ <string name="month_shortest_june">J</string>
+ <string name="month_shortest_july">J</string>
+ <string name="month_shortest_august">A</string>
+ <string name="month_shortest_september">S</string>
+ <string name="month_shortest_october">O</string>
+ <string name="month_shortest_november">N</string>
+ <string name="month_shortest_december">D</string>
+
+ <string name="day_of_week_long_sunday">vasárnap</string>
+ <string name="day_of_week_long_monday">hétfő</string>
+ <string name="day_of_week_long_tuesday">kedd</string>
+ <string name="day_of_week_long_wednesday">szerda</string>
+ <string name="day_of_week_long_thursday">csütörtök</string>
+ <string name="day_of_week_long_friday">péntek</string>
+ <string name="day_of_week_long_saturday">szombat</string>
+
+ <string name="day_of_week_medium_sunday">V</string>
+ <string name="day_of_week_medium_monday">H</string>
+ <string name="day_of_week_medium_tuesday">K</string>
+ <string name="day_of_week_medium_wednesday">Sze</string>
+ <string name="day_of_week_medium_thursday">Cs</string>
+ <string name="day_of_week_medium_friday">P</string>
+ <string name="day_of_week_medium_saturday">Szo</string>
+
+ <string name="day_of_week_short_sunday">V</string>
+ <string name="day_of_week_short_monday">H</string>
+ <string name="day_of_week_short_tuesday">K</string>
+ <string name="day_of_week_short_wednesday">Sze</string>
+ <string name="day_of_week_short_thursday">Cs</string>
+ <string name="day_of_week_short_friday">P</string>
+ <string name="day_of_week_short_saturday">Szo</string>
+
+ <string name="day_of_week_shortest_sunday">V</string>
+ <string name="day_of_week_shortest_monday">H</string>
+ <string name="day_of_week_shortest_tuesday">K</string>
+ <string name="day_of_week_shortest_wednesday">S</string>
+ <string name="day_of_week_shortest_thursday">C</string>
+ <string name="day_of_week_shortest_friday">P</string>
+ <string name="day_of_week_shortest_saturday">S</string>
+
+ <string name="am">de.</string>
+ <string name="pm">du.</string>
+ <string name="yesterday">tegnap</string>
+ <string name="today">ma</string>
+ <string name="tomorrow">holnap</string>
+
+ <string name="hour_minute_24">%H:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">HH:mm</string>
+ <string name="numeric_date">%Y.%m.%d.</string>
+ <string name="numeric_date_format">yyyy.MM.dd.</string>
+ <string name="numeric_date_template">"%s.%s.%s."</string>
+ <string name="month_day_year">%Y. %B %-e.</string>
+ <string name="time_of_day">%-k:%M:%S</string>
+ <string name="date_and_time">%-k:%M:%S %Y.%m.%d.</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%Y.%m.%d.</string>
+ <string name="month_day">%B %-e.</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%Y. %B</string>
+ <string name="abbrev_month_day">%b %-e.</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%Y. %b</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%2$s.%3$s. - %7$s.%8$s.</string>
+ <string name="numeric_wday1_md1_wday2_md2">%2$s.%3$s., %1$s - %7$s.%8$s., %6$s</string>
+ <string name="numeric_mdy1_mdy2">%4$s.%2$s.%3$s. - %9$s.%7$s.%8$s.</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%4$s.%2$s.%3$s., %1$s - %9$s.%7$s.%8$s., %6$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s.%2$s.%3$s., %1$s - %10$s %9$s.%7$s.%8$s., %6$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %2$s. %3$s. - %10$s %7$s. %8$s.</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %2$s. %3$s., %1$s - %10$s %7$s. %8$s., %6$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s.%2$s.%3$s. - %10$s %9$s.%7$s.%8$s.</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %2$s, %1$s - %6$s %5$s, %4$s</string>
+ <string name="wday1_date1_wday2_date2">%2$s, %1$s - %5$s, %4$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %3$s, %2$s</string>
+ <string name="wday_date">%3$s, %2$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%2$s %3$s. - %7$s %8$s.</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s. - %10$s %7$s %8$s.</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s. - %10$s %7$s %8$s.</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s. %2$s %3$s. - %10$s %9$s. %7$s %8$s.</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s. %2$s %3$s. - %10$s %9$s. %7$s %8$s.</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s. %2$s %3$s., %1$s - %10$s %9$s. %7$s %8$s., %6$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s. %2$s %3$s., %1$s - %10$s %9$s. %7$s %8$s., %6$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%4$s. %2$s %3$s., %1$s - %9$s. %7$s %8$s., %6$s</string>
+ <string name="same_month_md1_md2">%2$s %3$s-%8$s.</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_mdy2">%9$s. %2$s %3$s. - %7$s %8$s.</string>
+ <string name="same_month_mdy1_mdy2">%9$s. %2$s %3$s-%8$s.</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s. %2$s %3$s., %1$s - %7$s %8$s., %6$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E MMMM d</string>
+ <string name="abbrev_wday_month_day_year">y. MMM d., E</string>
+</resources>
diff --git a/core/res/res/values-in-rID/donottranslate-cldr.xml b/core/res/res/values-in-rID/donottranslate-cldr.xml
new file mode 100644
index 0000000..4d4ebb2
--- /dev/null
+++ b/core/res/res/values-in-rID/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">Januari</string>
+ <string name="month_long_standalone_february">Februari</string>
+ <string name="month_long_standalone_march">Maret</string>
+ <string name="month_long_standalone_april">April</string>
+ <string name="month_long_standalone_may">Mei</string>
+ <string name="month_long_standalone_june">Juni</string>
+ <string name="month_long_standalone_july">Juli</string>
+ <string name="month_long_standalone_august">Agustus</string>
+ <string name="month_long_standalone_september">September</string>
+ <string name="month_long_standalone_october">Oktober</string>
+ <string name="month_long_standalone_november">November</string>
+ <string name="month_long_standalone_december">Desember</string>
+
+ <string name="month_long_january">Januari</string>
+ <string name="month_long_february">Februari</string>
+ <string name="month_long_march">Maret</string>
+ <string name="month_long_april">April</string>
+ <string name="month_long_may">Mei</string>
+ <string name="month_long_june">Juni</string>
+ <string name="month_long_july">Juli</string>
+ <string name="month_long_august">Agustus</string>
+ <string name="month_long_september">September</string>
+ <string name="month_long_october">Oktober</string>
+ <string name="month_long_november">November</string>
+ <string name="month_long_december">Desember</string>
+
+ <string name="month_medium_january">Jan</string>
+ <string name="month_medium_february">Feb</string>
+ <string name="month_medium_march">Mar</string>
+ <string name="month_medium_april">Apr</string>
+ <string name="month_medium_may">Mei</string>
+ <string name="month_medium_june">Jun</string>
+ <string name="month_medium_july">Jul</string>
+ <string name="month_medium_august">Agu</string>
+ <string name="month_medium_september">Sep</string>
+ <string name="month_medium_october">Okt</string>
+ <string name="month_medium_november">Nov</string>
+ <string name="month_medium_december">Des</string>
+
+ <string name="month_shortest_january">1</string>
+ <string name="month_shortest_february">2</string>
+ <string name="month_shortest_march">3</string>
+ <string name="month_shortest_april">4</string>
+ <string name="month_shortest_may">5</string>
+ <string name="month_shortest_june">6</string>
+ <string name="month_shortest_july">7</string>
+ <string name="month_shortest_august">8</string>
+ <string name="month_shortest_september">9</string>
+ <string name="month_shortest_october">10</string>
+ <string name="month_shortest_november">11</string>
+ <string name="month_shortest_december">12</string>
+
+ <string name="day_of_week_long_sunday">Minggu</string>
+ <string name="day_of_week_long_monday">Senin</string>
+ <string name="day_of_week_long_tuesday">Selasa</string>
+ <string name="day_of_week_long_wednesday">Rabu</string>
+ <string name="day_of_week_long_thursday">Kamis</string>
+ <string name="day_of_week_long_friday">Jumat</string>
+ <string name="day_of_week_long_saturday">Sabtu</string>
+
+ <string name="day_of_week_medium_sunday">Min</string>
+ <string name="day_of_week_medium_monday">Sen</string>
+ <string name="day_of_week_medium_tuesday">Sel</string>
+ <string name="day_of_week_medium_wednesday">Rab</string>
+ <string name="day_of_week_medium_thursday">Kam</string>
+ <string name="day_of_week_medium_friday">Jum</string>
+ <string name="day_of_week_medium_saturday">Sab</string>
+
+ <string name="day_of_week_short_sunday">Min</string>
+ <string name="day_of_week_short_monday">Sen</string>
+ <string name="day_of_week_short_tuesday">Sel</string>
+ <string name="day_of_week_short_wednesday">Rab</string>
+ <string name="day_of_week_short_thursday">Kam</string>
+ <string name="day_of_week_short_friday">Jum</string>
+ <string name="day_of_week_short_saturday">Sab</string>
+
+ <string name="day_of_week_shortest_sunday">1</string>
+ <string name="day_of_week_shortest_monday">2</string>
+ <string name="day_of_week_shortest_tuesday">3</string>
+ <string name="day_of_week_shortest_wednesday">4</string>
+ <string name="day_of_week_shortest_thursday">5</string>
+ <string name="day_of_week_shortest_friday">6</string>
+ <string name="day_of_week_shortest_saturday">7</string>
+
+ <string name="am">AM</string>
+ <string name="pm">PM</string>
+ <string name="yesterday">Yesterday</string>
+ <string name="today">Today</string>
+ <string name="tomorrow">Tomorrow</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%d/%m/%Y</string>
+ <string name="numeric_date_format">dd/MM/yyyy</string>
+ <string name="numeric_date_template">"%s/%s/%s"</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%-e %b %Y</string>
+ <string name="month_day">%-e %B</string>
+ <string name="month">%-B</string>
+ <string name="month_day_year">%-e %B %Y</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%-e %b</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s – %2$s</string>
+ <string name="date1_date2">%2$s – %5$s</string>
+ <string name="numeric_md1_md2">%3$s-%2$s – %8$s-%7$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s-%2$s – %6$s, %8$s-%7$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s-%2$s-%4$s – %8$s-%7$s-%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s-%2$s-%4$s – %6$s, %8$s-%7$s-%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s-%2$s-%4$s – %10$s %6$s, %8$s-%7$s-%9$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s-%2$s – %10$s %8$s-%7$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s-%2$s – %10$s %6$s, %8$s-%7$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s – %6$s %4$s, %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s, %2$s – %4$s, %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s, %3$s</string>
+ <string name="wday_date">%2$s, %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s %2$s – %8$s %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s %2$s – %6$s, %8$s %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s – %10$s %8$s %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s – %10$s %8$s %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s – %6$s, %8$s %7$s %9$s</string>
+ <string name="same_month_md1_md2">%3$s - %8$s %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s %2$s – %6$s, %8$s %7$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s - %8$s %2$s %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">EEEE MMMM d</string>
+ <string name="abbrev_wday_month_day_year">E, d MMM yyyy</string>
+</resources>
diff --git a/core/res/res/values-in/donottranslate-cldr.xml b/core/res/res/values-in/donottranslate-cldr.xml
new file mode 100644
index 0000000..7a58a19
--- /dev/null
+++ b/core/res/res/values-in/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">Januari</string>
+ <string name="month_long_standalone_february">Februari</string>
+ <string name="month_long_standalone_march">Maret</string>
+ <string name="month_long_standalone_april">April</string>
+ <string name="month_long_standalone_may">Mei</string>
+ <string name="month_long_standalone_june">Juni</string>
+ <string name="month_long_standalone_july">Juli</string>
+ <string name="month_long_standalone_august">Agustus</string>
+ <string name="month_long_standalone_september">September</string>
+ <string name="month_long_standalone_october">Oktober</string>
+ <string name="month_long_standalone_november">November</string>
+ <string name="month_long_standalone_december">Desember</string>
+
+ <string name="month_long_january">Januari</string>
+ <string name="month_long_february">Februari</string>
+ <string name="month_long_march">Maret</string>
+ <string name="month_long_april">April</string>
+ <string name="month_long_may">Mei</string>
+ <string name="month_long_june">Juni</string>
+ <string name="month_long_july">Juli</string>
+ <string name="month_long_august">Agustus</string>
+ <string name="month_long_september">September</string>
+ <string name="month_long_october">Oktober</string>
+ <string name="month_long_november">November</string>
+ <string name="month_long_december">Desember</string>
+
+ <string name="month_medium_january">Jan</string>
+ <string name="month_medium_february">Feb</string>
+ <string name="month_medium_march">Mar</string>
+ <string name="month_medium_april">Apr</string>
+ <string name="month_medium_may">Mei</string>
+ <string name="month_medium_june">Jun</string>
+ <string name="month_medium_july">Jul</string>
+ <string name="month_medium_august">Agu</string>
+ <string name="month_medium_september">Sep</string>
+ <string name="month_medium_october">Okt</string>
+ <string name="month_medium_november">Nov</string>
+ <string name="month_medium_december">Des</string>
+
+ <string name="month_shortest_january">1</string>
+ <string name="month_shortest_february">2</string>
+ <string name="month_shortest_march">3</string>
+ <string name="month_shortest_april">4</string>
+ <string name="month_shortest_may">5</string>
+ <string name="month_shortest_june">6</string>
+ <string name="month_shortest_july">7</string>
+ <string name="month_shortest_august">8</string>
+ <string name="month_shortest_september">9</string>
+ <string name="month_shortest_october">10</string>
+ <string name="month_shortest_november">11</string>
+ <string name="month_shortest_december">12</string>
+
+ <string name="day_of_week_long_sunday">Minggu</string>
+ <string name="day_of_week_long_monday">Senin</string>
+ <string name="day_of_week_long_tuesday">Selasa</string>
+ <string name="day_of_week_long_wednesday">Rabu</string>
+ <string name="day_of_week_long_thursday">Kamis</string>
+ <string name="day_of_week_long_friday">Jumat</string>
+ <string name="day_of_week_long_saturday">Sabtu</string>
+
+ <string name="day_of_week_medium_sunday">Min</string>
+ <string name="day_of_week_medium_monday">Sen</string>
+ <string name="day_of_week_medium_tuesday">Sel</string>
+ <string name="day_of_week_medium_wednesday">Rab</string>
+ <string name="day_of_week_medium_thursday">Kam</string>
+ <string name="day_of_week_medium_friday">Jum</string>
+ <string name="day_of_week_medium_saturday">Sab</string>
+
+ <string name="day_of_week_short_sunday">Min</string>
+ <string name="day_of_week_short_monday">Sen</string>
+ <string name="day_of_week_short_tuesday">Sel</string>
+ <string name="day_of_week_short_wednesday">Rab</string>
+ <string name="day_of_week_short_thursday">Kam</string>
+ <string name="day_of_week_short_friday">Jum</string>
+ <string name="day_of_week_short_saturday">Sab</string>
+
+ <string name="day_of_week_shortest_sunday">1</string>
+ <string name="day_of_week_shortest_monday">2</string>
+ <string name="day_of_week_shortest_tuesday">3</string>
+ <string name="day_of_week_shortest_wednesday">4</string>
+ <string name="day_of_week_shortest_thursday">5</string>
+ <string name="day_of_week_shortest_friday">6</string>
+ <string name="day_of_week_shortest_saturday">7</string>
+
+ <string name="am">AM</string>
+ <string name="pm">PM</string>
+ <string name="yesterday">Yesterday</string>
+ <string name="today">Today</string>
+ <string name="tomorrow">Tomorrow</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%d/%m/%Y</string>
+ <string name="numeric_date_format">dd/MM/yyyy</string>
+ <string name="numeric_date_template">"%s/%s/%s"</string>
+ <string name="month_day_year">%-e %B %Y</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%-e %b %Y</string>
+ <string name="month_day">%B %-e</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%b %-e</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%Y %b</string>
+ <string name="time1_time2">%1$s – %2$s</string>
+ <string name="date1_date2">%2$s – %5$s</string>
+ <string name="numeric_md1_md2">%2$s-%3$s – %7$s-%8$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s – %6$s, %7$s-%8$s</string>
+ <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s – %9$s-%7$s-%8$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s – %10$s %7$s-%8$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s %3$s</string>
+ <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%2$s %3$s – %7$s %8$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s</string>
+ <string name="same_month_md1_md2">%2$s-%3$s – %8$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string>
+ <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E MMMM d</string>
+ <string name="abbrev_wday_month_day_year">EEE, y MMM d</string>
+</resources>
diff --git a/core/res/res/values-iw-rIL/arrays.xml b/core/res/res/values-iw-rIL/arrays.xml
new file mode 100644
index 0000000..87c1231
--- /dev/null
+++ b/core/res/res/values-iw-rIL/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_lat_lng">
+ <item>31046051</item>
+ <item>34851612</item>
+ </integer-array>
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_zoom">
+ <item>4</item>
+ </integer-array>
+
+</resources>
diff --git a/core/res/res/values-iw/donottranslate-cldr.xml b/core/res/res/values-iw/donottranslate-cldr.xml
new file mode 100644
index 0000000..d373a34
--- /dev/null
+++ b/core/res/res/values-iw/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">ינואר</string>
+ <string name="month_long_standalone_february">פברואר</string>
+ <string name="month_long_standalone_march">מרס</string>
+ <string name="month_long_standalone_april">אפריל</string>
+ <string name="month_long_standalone_may">מאי</string>
+ <string name="month_long_standalone_june">יוני</string>
+ <string name="month_long_standalone_july">יולי</string>
+ <string name="month_long_standalone_august">אוגוסט</string>
+ <string name="month_long_standalone_september">ספטמבר</string>
+ <string name="month_long_standalone_october">אוקטובר</string>
+ <string name="month_long_standalone_november">נובמבר</string>
+ <string name="month_long_standalone_december">דצמבר</string>
+
+ <string name="month_long_january">ינואר</string>
+ <string name="month_long_february">פברואר</string>
+ <string name="month_long_march">מרס</string>
+ <string name="month_long_april">אפריל</string>
+ <string name="month_long_may">מאי</string>
+ <string name="month_long_june">יוני</string>
+ <string name="month_long_july">יולי</string>
+ <string name="month_long_august">אוגוסט</string>
+ <string name="month_long_september">ספטמבר</string>
+ <string name="month_long_october">אוקטובר</string>
+ <string name="month_long_november">נובמבר</string>
+ <string name="month_long_december">דצמבר</string>
+
+ <string name="month_medium_january">ינו</string>
+ <string name="month_medium_february">פבר</string>
+ <string name="month_medium_march">מרס</string>
+ <string name="month_medium_april">אפר</string>
+ <string name="month_medium_may">מאי</string>
+ <string name="month_medium_june">יונ</string>
+ <string name="month_medium_july">יול</string>
+ <string name="month_medium_august">אוג</string>
+ <string name="month_medium_september">ספט</string>
+ <string name="month_medium_october">אוק</string>
+ <string name="month_medium_november">נוב</string>
+ <string name="month_medium_december">דצמ</string>
+
+ <string name="month_shortest_january">1</string>
+ <string name="month_shortest_february">2</string>
+ <string name="month_shortest_march">3</string>
+ <string name="month_shortest_april">4</string>
+ <string name="month_shortest_may">5</string>
+ <string name="month_shortest_june">6</string>
+ <string name="month_shortest_july">7</string>
+ <string name="month_shortest_august">8</string>
+ <string name="month_shortest_september">9</string>
+ <string name="month_shortest_october">10</string>
+ <string name="month_shortest_november">11</string>
+ <string name="month_shortest_december">12</string>
+
+ <string name="day_of_week_long_sunday">יום ראשון</string>
+ <string name="day_of_week_long_monday">יום שני</string>
+ <string name="day_of_week_long_tuesday">יום שלישי</string>
+ <string name="day_of_week_long_wednesday">יום רביעי</string>
+ <string name="day_of_week_long_thursday">יום חמישי</string>
+ <string name="day_of_week_long_friday">יום שישי</string>
+ <string name="day_of_week_long_saturday">יום שבת</string>
+
+ <string name="day_of_week_medium_sunday">יום א\'</string>
+ <string name="day_of_week_medium_monday">יום ב\'</string>
+ <string name="day_of_week_medium_tuesday">יום ג\'</string>
+ <string name="day_of_week_medium_wednesday">יום ד\'</string>
+ <string name="day_of_week_medium_thursday">יום ה\'</string>
+ <string name="day_of_week_medium_friday">יום ו\'</string>
+ <string name="day_of_week_medium_saturday">שבת</string>
+
+ <string name="day_of_week_short_sunday">יום א\'</string>
+ <string name="day_of_week_short_monday">יום ב\'</string>
+ <string name="day_of_week_short_tuesday">יום ג\'</string>
+ <string name="day_of_week_short_wednesday">יום ד\'</string>
+ <string name="day_of_week_short_thursday">יום ה\'</string>
+ <string name="day_of_week_short_friday">יום ו\'</string>
+ <string name="day_of_week_short_saturday">שבת</string>
+
+ <string name="day_of_week_shortest_sunday">א</string>
+ <string name="day_of_week_shortest_monday">ב</string>
+ <string name="day_of_week_shortest_tuesday">ג</string>
+ <string name="day_of_week_shortest_wednesday">ד</string>
+ <string name="day_of_week_shortest_thursday">ה</string>
+ <string name="day_of_week_shortest_friday">ו</string>
+ <string name="day_of_week_shortest_saturday">ש</string>
+
+ <string name="am">לפנה"צ</string>
+ <string name="pm">אחה"צ</string>
+ <string name="yesterday">אתמול</string>
+ <string name="today">היום</string>
+ <string name="tomorrow">מחר</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%d/%m/%Y</string>
+ <string name="numeric_date_format">dd/MM/yyyy</string>
+ <string name="numeric_date_template">"%s/%s/%s"</string>
+ <string name="month_day_year">%-e ב%B %Y</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %-e.%-m.%Y</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%-e.%-m.%Y</string>
+ <string name="month_day">%-e ב%B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%b %-e</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%Y %b</string>
+ <string name="time1_time2">%1$s – %2$s</string>
+ <string name="date1_date2">%2$s – %5$s</string>
+ <string name="numeric_md1_md2">%3$s/%2$s - %8$s/%7$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s %3$s/%2$s - %6$s %8$s/%7$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s/%2$s/%4$s - %8$s/%7$s/%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s %3$s/%2$s/%4$s - %6$s %8$s/%7$s/%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s – %10$s %6$s, %8$s.%7$s.%9$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s/%2$s – %10$s %8$s/%7$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s/%2$s/%4$s – %10$s %8$s/%7$s/%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s %3$s</string>
+ <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s ב%2$s – %8$s ב%7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s ב%2$s – %10$s %8$s ב%7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s ב%2$s – %10$s %8$s ב%7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s</string>
+ <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s - %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E MMMM d</string>
+ <string name="abbrev_wday_month_day_year">EEE, y MMM d</string>
+</resources>
diff --git a/core/res/res/values-lt/donottranslate-cldr.xml b/core/res/res/values-lt/donottranslate-cldr.xml
new file mode 100644
index 0000000..25458bd
--- /dev/null
+++ b/core/res/res/values-lt/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">Sausis</string>
+ <string name="month_long_standalone_february">Vasaris</string>
+ <string name="month_long_standalone_march">Kovas</string>
+ <string name="month_long_standalone_april">Balandis</string>
+ <string name="month_long_standalone_may">Gegužė</string>
+ <string name="month_long_standalone_june">Birželis</string>
+ <string name="month_long_standalone_july">Liepa</string>
+ <string name="month_long_standalone_august">Rugpjūtis</string>
+ <string name="month_long_standalone_september">Rugsėjis</string>
+ <string name="month_long_standalone_october">Spalis</string>
+ <string name="month_long_standalone_november">Lapkritis</string>
+ <string name="month_long_standalone_december">Gruodis</string>
+
+ <string name="month_long_january">sausio</string>
+ <string name="month_long_february">vasario</string>
+ <string name="month_long_march">kovo</string>
+ <string name="month_long_april">balandžio</string>
+ <string name="month_long_may">gegužės</string>
+ <string name="month_long_june">birželio</string>
+ <string name="month_long_july">liepos</string>
+ <string name="month_long_august">rugpjūčio</string>
+ <string name="month_long_september">rugsėjo</string>
+ <string name="month_long_october">spalio</string>
+ <string name="month_long_november">lapkričio</string>
+ <string name="month_long_december">gruodžio</string>
+
+ <string name="month_medium_january">Sau</string>
+ <string name="month_medium_february">Vas</string>
+ <string name="month_medium_march">Kov</string>
+ <string name="month_medium_april">Bal</string>
+ <string name="month_medium_may">Geg</string>
+ <string name="month_medium_june">Bir</string>
+ <string name="month_medium_july">Lie</string>
+ <string name="month_medium_august">Rgp</string>
+ <string name="month_medium_september">Rgs</string>
+ <string name="month_medium_october">Spl</string>
+ <string name="month_medium_november">Lap</string>
+ <string name="month_medium_december">Grd</string>
+
+ <string name="month_shortest_january">S</string>
+ <string name="month_shortest_february">V</string>
+ <string name="month_shortest_march">K</string>
+ <string name="month_shortest_april">B</string>
+ <string name="month_shortest_may">G</string>
+ <string name="month_shortest_june">B</string>
+ <string name="month_shortest_july">L</string>
+ <string name="month_shortest_august">R</string>
+ <string name="month_shortest_september">R</string>
+ <string name="month_shortest_october">S</string>
+ <string name="month_shortest_november">L</string>
+ <string name="month_shortest_december">G</string>
+
+ <string name="day_of_week_long_sunday">sekmadienis</string>
+ <string name="day_of_week_long_monday">pirmadienis</string>
+ <string name="day_of_week_long_tuesday">antradienis</string>
+ <string name="day_of_week_long_wednesday">trečiadienis</string>
+ <string name="day_of_week_long_thursday">ketvirtadienis</string>
+ <string name="day_of_week_long_friday">penktadienis</string>
+ <string name="day_of_week_long_saturday">šeštadienis</string>
+
+ <string name="day_of_week_medium_sunday">Sk</string>
+ <string name="day_of_week_medium_monday">Pr</string>
+ <string name="day_of_week_medium_tuesday">An</string>
+ <string name="day_of_week_medium_wednesday">Tr</string>
+ <string name="day_of_week_medium_thursday">Kt</string>
+ <string name="day_of_week_medium_friday">Pn</string>
+ <string name="day_of_week_medium_saturday">Št</string>
+
+ <string name="day_of_week_short_sunday">Sk</string>
+ <string name="day_of_week_short_monday">Pr</string>
+ <string name="day_of_week_short_tuesday">An</string>
+ <string name="day_of_week_short_wednesday">Tr</string>
+ <string name="day_of_week_short_thursday">Kt</string>
+ <string name="day_of_week_short_friday">Pn</string>
+ <string name="day_of_week_short_saturday">Št</string>
+
+ <string name="day_of_week_shortest_sunday">S</string>
+ <string name="day_of_week_shortest_monday">P</string>
+ <string name="day_of_week_shortest_tuesday">A</string>
+ <string name="day_of_week_shortest_wednesday">T</string>
+ <string name="day_of_week_shortest_thursday">K</string>
+ <string name="day_of_week_shortest_friday">P</string>
+ <string name="day_of_week_shortest_saturday">Š</string>
+
+ <string name="am">priešpiet</string>
+ <string name="pm">popiet</string>
+ <string name="yesterday">vakar</string>
+ <string name="today">šiandien</string>
+ <string name="tomorrow">rytoj</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%Y-%m-%d</string>
+ <string name="numeric_date_format">yyyy-MM-dd</string>
+ <string name="numeric_date_template">"%s-%s-%s"</string>
+ <string name="month_day_year">%Y m. %B %-e d.</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %Y.%m.%d</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%Y.%m.%d</string>
+ <string name="month_day">%B %-e</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%Y %B</string>
+ <string name="abbrev_month_day">%b %-e d.</string>
+ <string name="abbrev_month">%b</string>
+ <string name="abbrev_month_year">%Y m. %b</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%2$s-%3$s - %7$s-%8$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%2$s-%3$s%1$s - %7$s-%8$s%6$s</string>
+ <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s - %9$s-%7$s-%8$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%4$s-%2$s-%3$s%1$s - %9$s-%7$s-%8$s%6$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s-%2$s-%3$s%1$s - %10$s %9$s-%7$s-%8$s%6$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s - %10$s %7$s-%8$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %2$s-%3$s%1$s - %10$s %7$s-%8$s%6$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s - %10$s %9$s-%7$s-%8$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %2$s%1$s - %6$s %5$s%4$s</string>
+ <string name="wday1_date1_wday2_date2">%2$s%1$s - %5$s%4$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %3$s%2$s</string>
+ <string name="wday_date">%3$s%2$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%2$s %3$s - %7$s %8$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s - %10$s %7$s %8$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s m. %2$s %3$s d. - %10$s %9$s m. %7$s %8$s d.</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s m. %2$s %3$s d. - %10$s %9$s m. %7$s %8$s d.</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s m. %2$s %3$s d.,%1$s - %10$s %9$s m. %7$s %8$s d.,%6$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %4$s m. %2$s %3$s d.,%1$s - %10$s %9$s m. %7$s %8$s d.,%6$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%4$s m. %2$s %3$s d.,%1$s - %9$s m. %7$s %8$s d.,%6$s</string>
+ <string name="same_month_md1_md2">%2$s %3$s d.-%8$s d.</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_mdy2">%9$s m. %2$s %3$s d. - %7$s %8$s d.</string>
+ <string name="same_month_mdy1_mdy2">%9$s m. %2$s %3$s d.-%8$s d.</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%9$s m. %2$s %3$s d.,%1$s - %7$s %8$s d.,%6$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E MMMM d</string>
+ <string name="abbrev_wday_month_day_year">y \'m\'. MMM d \'d\'.,E</string>
+</resources>
diff --git a/core/res/res/values-lv/donottranslate-cldr.xml b/core/res/res/values-lv/donottranslate-cldr.xml
new file mode 100644
index 0000000..2de9367
--- /dev/null
+++ b/core/res/res/values-lv/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">janvāris</string>
+ <string name="month_long_standalone_february">februāris</string>
+ <string name="month_long_standalone_march">marts</string>
+ <string name="month_long_standalone_april">aprīlis</string>
+ <string name="month_long_standalone_may">maijs</string>
+ <string name="month_long_standalone_june">jūnijs</string>
+ <string name="month_long_standalone_july">jūlijs</string>
+ <string name="month_long_standalone_august">augusts</string>
+ <string name="month_long_standalone_september">septembris</string>
+ <string name="month_long_standalone_october">oktobris</string>
+ <string name="month_long_standalone_november">novembris</string>
+ <string name="month_long_standalone_december">decembris</string>
+
+ <string name="month_long_january">janvāris</string>
+ <string name="month_long_february">februāris</string>
+ <string name="month_long_march">marts</string>
+ <string name="month_long_april">aprīlis</string>
+ <string name="month_long_may">maijs</string>
+ <string name="month_long_june">jūnijs</string>
+ <string name="month_long_july">jūlijs</string>
+ <string name="month_long_august">augusts</string>
+ <string name="month_long_september">septembris</string>
+ <string name="month_long_october">oktobris</string>
+ <string name="month_long_november">novembris</string>
+ <string name="month_long_december">decembris</string>
+
+ <string name="month_medium_january">janv.</string>
+ <string name="month_medium_february">febr.</string>
+ <string name="month_medium_march">marts</string>
+ <string name="month_medium_april">apr.</string>
+ <string name="month_medium_may">maijs</string>
+ <string name="month_medium_june">jūn.</string>
+ <string name="month_medium_july">jūl.</string>
+ <string name="month_medium_august">aug.</string>
+ <string name="month_medium_september">sept.</string>
+ <string name="month_medium_october">okt.</string>
+ <string name="month_medium_november">nov.</string>
+ <string name="month_medium_december">dec.</string>
+
+ <string name="month_shortest_january">J</string>
+ <string name="month_shortest_february">F</string>
+ <string name="month_shortest_march">M</string>
+ <string name="month_shortest_april">A</string>
+ <string name="month_shortest_may">M</string>
+ <string name="month_shortest_june">J</string>
+ <string name="month_shortest_july">J</string>
+ <string name="month_shortest_august">A</string>
+ <string name="month_shortest_september">S</string>
+ <string name="month_shortest_october">O</string>
+ <string name="month_shortest_november">N</string>
+ <string name="month_shortest_december">D</string>
+
+ <string name="day_of_week_long_sunday">svētdiena</string>
+ <string name="day_of_week_long_monday">pirmdiena</string>
+ <string name="day_of_week_long_tuesday">otrdiena</string>
+ <string name="day_of_week_long_wednesday">trešdiena</string>
+ <string name="day_of_week_long_thursday">ceturtdiena</string>
+ <string name="day_of_week_long_friday">piektdiena</string>
+ <string name="day_of_week_long_saturday">sestdiena</string>
+
+ <string name="day_of_week_medium_sunday">Sv</string>
+ <string name="day_of_week_medium_monday">Pr</string>
+ <string name="day_of_week_medium_tuesday">Ot</string>
+ <string name="day_of_week_medium_wednesday">Tr</string>
+ <string name="day_of_week_medium_thursday">Ce</string>
+ <string name="day_of_week_medium_friday">Pk</string>
+ <string name="day_of_week_medium_saturday">Se</string>
+
+ <string name="day_of_week_short_sunday">Sv</string>
+ <string name="day_of_week_short_monday">Pr</string>
+ <string name="day_of_week_short_tuesday">Ot</string>
+ <string name="day_of_week_short_wednesday">Tr</string>
+ <string name="day_of_week_short_thursday">Ce</string>
+ <string name="day_of_week_short_friday">Pk</string>
+ <string name="day_of_week_short_saturday">Se</string>
+
+ <string name="day_of_week_shortest_sunday">S</string>
+ <string name="day_of_week_shortest_monday">P</string>
+ <string name="day_of_week_shortest_tuesday">O</string>
+ <string name="day_of_week_shortest_wednesday">T</string>
+ <string name="day_of_week_shortest_thursday">C</string>
+ <string name="day_of_week_shortest_friday">P</string>
+ <string name="day_of_week_shortest_saturday">S</string>
+
+ <string name="am">AM</string>
+ <string name="pm">PM</string>
+ <string name="yesterday">vakar</string>
+ <string name="today">šodien</string>
+ <string name="tomorrow">rīt</string>
+
+ <string name="hour_minute_24">%H:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">HH:mm</string>
+ <string name="numeric_date">%d.%m.%Y</string>
+ <string name="numeric_date_format">dd.MM.yyyy</string>
+ <string name="numeric_date_template">"%s.%s.%s"</string>
+ <string name="month_day_year">%Y. gada %-e. %B</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %Y. gada %-e. %b</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%Y. gada %-e. %b</string>
+ <string name="month_day">%-e. %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%Y. g. %B</string>
+ <string name="abbrev_month_day">%-e. %b</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%Y. g. %b</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%3$s.mm–%8$s.mm</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s - %6$s, %8$s.%7$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s.mm.%4$s.–%8$s.mm.%9$s.</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.mm.%4$s. – %6$s, %8$s.mm.%9$s.</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.mm.%4$s. - %10$s %6$s, %8$s.mm.%9$s.</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s.mm. - %10$s %8$s.mm.</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s.</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s, %3$s</string>
+ <string name="wday_date">%2$s, %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s. %2$s - %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s. gada %3$s. %2$s - %10$s %9$s. gada %8$s. %7$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s. gada %3$s. %2$s - %10$s %9$s. gada %8$s. %7$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s. g. %3$s. %2$s - %10$s %6$s, %9$s. g. %8$s. %7$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s. g. %3$s. %2$s - %10$s %6$s, %9$s. g. %8$s. %7$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s. g. %3$s. %2$s - %6$s, %9$s. g. %8$s. %7$s</string>
+ <string name="same_month_md1_md2">%3$s.-%8$s. %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
+ <string name="same_year_mdy1_mdy2">%9$s. gada %3$s. %2$s - %8$s. %7$s</string>
+ <string name="same_month_mdy1_mdy2">%9$s. gada %3$s.-%8$s. %2$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s. gada %3$s. %2$s - %6$s, y. gada %8$s. %7$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E, d. MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE, yyyy. \'g\'. dd. MMM</string>
+</resources>
diff --git a/core/res/res/values-rm-rCH/arrays.xml b/core/res/res/values-rm-rCH/arrays.xml
new file mode 100644
index 0000000..f2982e9
--- /dev/null
+++ b/core/res/res/values-rm-rCH/arrays.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/* //device/apps/common/assets/res/any/colors.xml
+**
+** Copyright 2006, Google Inc.
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+<resources>
+
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_lat_lng">
+ <item>46948020</item>
+ <item>7448206</item>
+ </integer-array>
+ <!-- Do not translate. -->
+ <integer-array name="maps_starting_zoom">
+ <item>4</item>
+ </integer-array>
+
+</resources>
diff --git a/core/res/res/values-rm/donottranslate-cldr.xml b/core/res/res/values-rm/donottranslate-cldr.xml
new file mode 100644
index 0000000..ccdb17c
--- /dev/null
+++ b/core/res/res/values-rm/donottranslate-cldr.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">schaner</string>
+ <string name="month_long_standalone_february">favrer</string>
+ <string name="month_long_standalone_march">mars</string>
+ <string name="month_long_standalone_april">avrigl</string>
+ <string name="month_long_standalone_may">matg</string>
+ <string name="month_long_standalone_june">zercladur</string>
+ <string name="month_long_standalone_july">fanadur</string>
+ <string name="month_long_standalone_august">avust</string>
+ <string name="month_long_standalone_september">settember</string>
+ <string name="month_long_standalone_october">october</string>
+ <string name="month_long_standalone_november">november</string>
+ <string name="month_long_standalone_december">december</string>
+
+ <string name="month_long_january">schaner</string>
+ <string name="month_long_february">favrer</string>
+ <string name="month_long_march">mars</string>
+ <string name="month_long_april">avrigl</string>
+ <string name="month_long_may">matg</string>
+ <string name="month_long_june">zercladur</string>
+ <string name="month_long_july">fanadur</string>
+ <string name="month_long_august">avust</string>
+ <string name="month_long_september">settember</string>
+ <string name="month_long_october">october</string>
+ <string name="month_long_november">november</string>
+ <string name="month_long_december">december</string>
+
+ <string name="month_medium_january">schan.</string>
+ <string name="month_medium_february">favr.</string>
+ <string name="month_medium_march">mars</string>
+ <string name="month_medium_april">avr.</string>
+ <string name="month_medium_may">matg</string>
+ <string name="month_medium_june">zercl.</string>
+ <string name="month_medium_july">fan.</string>
+ <string name="month_medium_august">avust</string>
+ <string name="month_medium_september">sett.</string>
+ <string name="month_medium_october">oct.</string>
+ <string name="month_medium_november">nov.</string>
+ <string name="month_medium_december">dec.</string>
+
+ <string name="month_shortest_january">S</string>
+ <string name="month_shortest_february">F</string>
+ <string name="month_shortest_march">M</string>
+ <string name="month_shortest_april">A</string>
+ <string name="month_shortest_may">M</string>
+ <string name="month_shortest_june">Z</string>
+ <string name="month_shortest_july">F</string>
+ <string name="month_shortest_august">A</string>
+ <string name="month_shortest_september">S</string>
+ <string name="month_shortest_october">O</string>
+ <string name="month_shortest_november">N</string>
+ <string name="month_shortest_december">D</string>
+
+ <string name="day_of_week_long_sunday">dumengia</string>
+ <string name="day_of_week_long_monday">glindesdi</string>
+ <string name="day_of_week_long_tuesday">mardi</string>
+ <string name="day_of_week_long_wednesday">mesemna</string>
+ <string name="day_of_week_long_thursday">gievgia</string>
+ <string name="day_of_week_long_friday">venderdi</string>
+ <string name="day_of_week_long_saturday">sonda</string>
+
+ <string name="day_of_week_medium_sunday">du</string>
+ <string name="day_of_week_medium_monday">gli</string>
+ <string name="day_of_week_medium_tuesday">ma</string>
+ <string name="day_of_week_medium_wednesday">me</string>
+ <string name="day_of_week_medium_thursday">gie</string>
+ <string name="day_of_week_medium_friday">ve</string>
+ <string name="day_of_week_medium_saturday">so</string>
+
+ <string name="day_of_week_short_sunday">du</string>
+ <string name="day_of_week_short_monday">gli</string>
+ <string name="day_of_week_short_tuesday">ma</string>
+ <string name="day_of_week_short_wednesday">me</string>
+ <string name="day_of_week_short_thursday">gie</string>
+ <string name="day_of_week_short_friday">ve</string>
+ <string name="day_of_week_short_saturday">so</string>
+
+ <string name="day_of_week_shortest_sunday">D</string>
+ <string name="day_of_week_shortest_monday">G</string>
+ <string name="day_of_week_shortest_tuesday">M</string>
+ <string name="day_of_week_shortest_wednesday">M</string>
+ <string name="day_of_week_shortest_thursday">G</string>
+ <string name="day_of_week_shortest_friday">V</string>
+ <string name="day_of_week_shortest_saturday">S</string>
+
+ <string name="yesterday">ier</string>
+ <string name="today">oz</string>
+ <string name="tomorrow">damaun</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%d.%m.%Y</string>
+ <string name="numeric_date_format">dd.MM.yyyy</string>
+ <string name="numeric_date_template">"%s.%s.%s"</string>
+ <string name="month_day_year">%-e. %B %Y</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %d.%m.%Y</string>
+ <string name="date_time">%1$s, %2$s</string>
+ <string name="time_date">%3$s, %1$s</string>
+ <string name="abbrev_month_day_year">%d.%m.%Y</string>
+ <string name="month_day">%-e. %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%-e. %b</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%3$s.%2$s. - %8$s.%7$s.</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s. - %6$s, %8$s.%7$s.</string>
+ <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s - %10$s %6$s, %9$s-%7$s-%8$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s. - %10$s %8$s.%7$s.</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s.</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s - %6$s %4$s %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s %3$s</string>
+ <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s. %2$s - %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s. %2$s - %6$s %8$s. %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %3$s. %2$s - %10$s %6$s %8$s. %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="same_month_md1_md2">%3$s.-%8$s. %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s. %2$s - %6$s %8$s. %7$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
+</resources>
diff --git a/core/res/res/values-ro/donottranslate-cldr.xml b/core/res/res/values-ro/donottranslate-cldr.xml
new file mode 100644
index 0000000..ef34103
--- /dev/null
+++ b/core/res/res/values-ro/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">ianuarie</string>
+ <string name="month_long_standalone_february">februarie</string>
+ <string name="month_long_standalone_march">martie</string>
+ <string name="month_long_standalone_april">aprilie</string>
+ <string name="month_long_standalone_may">mai</string>
+ <string name="month_long_standalone_june">iunie</string>
+ <string name="month_long_standalone_july">iulie</string>
+ <string name="month_long_standalone_august">august</string>
+ <string name="month_long_standalone_september">septembrie</string>
+ <string name="month_long_standalone_october">octombrie</string>
+ <string name="month_long_standalone_november">noiembrie</string>
+ <string name="month_long_standalone_december">decembrie</string>
+
+ <string name="month_long_january">ianuarie</string>
+ <string name="month_long_february">februarie</string>
+ <string name="month_long_march">martie</string>
+ <string name="month_long_april">aprilie</string>
+ <string name="month_long_may">mai</string>
+ <string name="month_long_june">iunie</string>
+ <string name="month_long_july">iulie</string>
+ <string name="month_long_august">august</string>
+ <string name="month_long_september">septembrie</string>
+ <string name="month_long_october">octombrie</string>
+ <string name="month_long_november">noiembrie</string>
+ <string name="month_long_december">decembrie</string>
+
+ <string name="month_medium_january">ian.</string>
+ <string name="month_medium_february">feb.</string>
+ <string name="month_medium_march">mar.</string>
+ <string name="month_medium_april">apr.</string>
+ <string name="month_medium_may">mai</string>
+ <string name="month_medium_june">iun.</string>
+ <string name="month_medium_july">iul.</string>
+ <string name="month_medium_august">aug.</string>
+ <string name="month_medium_september">sept.</string>
+ <string name="month_medium_october">oct.</string>
+ <string name="month_medium_november">nov.</string>
+ <string name="month_medium_december">dec.</string>
+
+ <string name="month_shortest_january">I</string>
+ <string name="month_shortest_february">F</string>
+ <string name="month_shortest_march">M</string>
+ <string name="month_shortest_april">A</string>
+ <string name="month_shortest_may">M</string>
+ <string name="month_shortest_june">I</string>
+ <string name="month_shortest_july">I</string>
+ <string name="month_shortest_august">A</string>
+ <string name="month_shortest_september">S</string>
+ <string name="month_shortest_october">O</string>
+ <string name="month_shortest_november">N</string>
+ <string name="month_shortest_december">D</string>
+
+ <string name="day_of_week_long_sunday">duminică</string>
+ <string name="day_of_week_long_monday">luni</string>
+ <string name="day_of_week_long_tuesday">marți</string>
+ <string name="day_of_week_long_wednesday">miercuri</string>
+ <string name="day_of_week_long_thursday">joi</string>
+ <string name="day_of_week_long_friday">vineri</string>
+ <string name="day_of_week_long_saturday">sâmbătă</string>
+
+ <string name="day_of_week_medium_sunday">Du</string>
+ <string name="day_of_week_medium_monday">Lu</string>
+ <string name="day_of_week_medium_tuesday">Ma</string>
+ <string name="day_of_week_medium_wednesday">Mi</string>
+ <string name="day_of_week_medium_thursday">Jo</string>
+ <string name="day_of_week_medium_friday">Vi</string>
+ <string name="day_of_week_medium_saturday">Sâ</string>
+
+ <string name="day_of_week_short_sunday">Du</string>
+ <string name="day_of_week_short_monday">Lu</string>
+ <string name="day_of_week_short_tuesday">Ma</string>
+ <string name="day_of_week_short_wednesday">Mi</string>
+ <string name="day_of_week_short_thursday">Jo</string>
+ <string name="day_of_week_short_friday">Vi</string>
+ <string name="day_of_week_short_saturday">Sâ</string>
+
+ <string name="day_of_week_shortest_sunday">D</string>
+ <string name="day_of_week_shortest_monday">L</string>
+ <string name="day_of_week_shortest_tuesday">M</string>
+ <string name="day_of_week_shortest_wednesday">M</string>
+ <string name="day_of_week_shortest_thursday">J</string>
+ <string name="day_of_week_shortest_friday">V</string>
+ <string name="day_of_week_shortest_saturday">S</string>
+
+ <string name="am">AM</string>
+ <string name="pm">PM</string>
+ <string name="yesterday">ieri</string>
+ <string name="today">azi</string>
+ <string name="tomorrow">mâine</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%d.%m.%Y</string>
+ <string name="numeric_date_format">dd.MM.yyyy</string>
+ <string name="numeric_date_template">"%s.%s.%s"</string>
+ <string name="month_day_year">%-e %B %Y</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S, %d.%m.%Y</string>
+ <string name="date_time">%2$s, %1$s</string>
+ <string name="time_date">%1$s, %3$s</string>
+ <string name="abbrev_month_day_year">%d.%m.%Y</string>
+ <string name="month_day">%-e %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%-e %b</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%3$s.%2$s - %8$s.%7$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s - %6$s, %8$s.%7$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s, %1$s, %3$s/%2$s/%4$s - %10$s, %6$s, %8$s/%7$s/%9$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s, %3$s.%2$s - %10$s, %8$s.%7$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s, %1$s, %3$s %2$s - %10$s, %6$s, %8$s %7$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s, %3$s.%2$s.%4$s - %10$s, %8$s.%7$s.%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s, %1$s, %2$s - %6$s, %4$s, %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s, %2$s - %6$s, %5$s</string>
+ <string name="time_wday_date">%1$s, %2$s, %3$s</string>
+ <string name="wday_date">%2$s, %3$s</string>
+ <string name="time_wday">%1$s, %2$s</string>
+ <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s %2$s - %6$s, %8$s %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s, %3$s %2$s - %10$s, %8$s %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s, %3$s %2$s - %10$s, %8$s %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s, %1$s, %3$s %2$s - %10$s, %6$s, %8$s %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s, %1$s, %3$s %2$s - %10$s, %6$s, %8$s %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s, %3$s %2$s %4$s - %10$s, %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s, %3$s %2$s %4$s - %10$s, %8$s %7$s %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s, %1$s, %3$s %2$s %4$s - %10$s, %6$s, %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s, %1$s, %3$s %2$s %4$s - %10$s, %6$s, %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="same_month_md1_md2">%3$s-%8$s %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s %2$s - %6$s, %8$s %7$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s %2$s - %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s-%8$s %2$s %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E, d MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
+</resources>
diff --git a/core/res/res/values-sk/donottranslate-cldr.xml b/core/res/res/values-sk/donottranslate-cldr.xml
new file mode 100644
index 0000000..b2ed9b7
--- /dev/null
+++ b/core/res/res/values-sk/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">január</string>
+ <string name="month_long_standalone_february">február</string>
+ <string name="month_long_standalone_march">marec</string>
+ <string name="month_long_standalone_april">apríl</string>
+ <string name="month_long_standalone_may">máj</string>
+ <string name="month_long_standalone_june">jún</string>
+ <string name="month_long_standalone_july">júl</string>
+ <string name="month_long_standalone_august">august</string>
+ <string name="month_long_standalone_september">september</string>
+ <string name="month_long_standalone_october">október</string>
+ <string name="month_long_standalone_november">november</string>
+ <string name="month_long_standalone_december">december</string>
+
+ <string name="month_long_january">januára</string>
+ <string name="month_long_february">februára</string>
+ <string name="month_long_march">marca</string>
+ <string name="month_long_april">apríla</string>
+ <string name="month_long_may">mája</string>
+ <string name="month_long_june">júna</string>
+ <string name="month_long_july">júla</string>
+ <string name="month_long_august">augusta</string>
+ <string name="month_long_september">septembra</string>
+ <string name="month_long_october">októbra</string>
+ <string name="month_long_november">novembra</string>
+ <string name="month_long_december">decembra</string>
+
+ <string name="month_medium_january">jan</string>
+ <string name="month_medium_february">feb</string>
+ <string name="month_medium_march">mar</string>
+ <string name="month_medium_april">apr</string>
+ <string name="month_medium_may">máj</string>
+ <string name="month_medium_june">jún</string>
+ <string name="month_medium_july">júl</string>
+ <string name="month_medium_august">aug</string>
+ <string name="month_medium_september">sep</string>
+ <string name="month_medium_october">okt</string>
+ <string name="month_medium_november">nov</string>
+ <string name="month_medium_december">dec</string>
+
+ <string name="month_shortest_january">j</string>
+ <string name="month_shortest_february">f</string>
+ <string name="month_shortest_march">m</string>
+ <string name="month_shortest_april">a</string>
+ <string name="month_shortest_may">m</string>
+ <string name="month_shortest_june">j</string>
+ <string name="month_shortest_july">j</string>
+ <string name="month_shortest_august">a</string>
+ <string name="month_shortest_september">s</string>
+ <string name="month_shortest_october">o</string>
+ <string name="month_shortest_november">n</string>
+ <string name="month_shortest_december">d</string>
+
+ <string name="day_of_week_long_sunday">nedeľa</string>
+ <string name="day_of_week_long_monday">pondelok</string>
+ <string name="day_of_week_long_tuesday">utorok</string>
+ <string name="day_of_week_long_wednesday">streda</string>
+ <string name="day_of_week_long_thursday">štvrtok</string>
+ <string name="day_of_week_long_friday">piatok</string>
+ <string name="day_of_week_long_saturday">sobota</string>
+
+ <string name="day_of_week_medium_sunday">ne</string>
+ <string name="day_of_week_medium_monday">po</string>
+ <string name="day_of_week_medium_tuesday">ut</string>
+ <string name="day_of_week_medium_wednesday">st</string>
+ <string name="day_of_week_medium_thursday">št</string>
+ <string name="day_of_week_medium_friday">pi</string>
+ <string name="day_of_week_medium_saturday">so</string>
+
+ <string name="day_of_week_short_sunday">ne</string>
+ <string name="day_of_week_short_monday">po</string>
+ <string name="day_of_week_short_tuesday">ut</string>
+ <string name="day_of_week_short_wednesday">st</string>
+ <string name="day_of_week_short_thursday">št</string>
+ <string name="day_of_week_short_friday">pi</string>
+ <string name="day_of_week_short_saturday">so</string>
+
+ <string name="day_of_week_shortest_sunday">N</string>
+ <string name="day_of_week_shortest_monday">P</string>
+ <string name="day_of_week_shortest_tuesday">U</string>
+ <string name="day_of_week_shortest_wednesday">S</string>
+ <string name="day_of_week_shortest_thursday">Š</string>
+ <string name="day_of_week_shortest_friday">P</string>
+ <string name="day_of_week_shortest_saturday">S</string>
+
+ <string name="am">dopoludnia</string>
+ <string name="pm">popoludní</string>
+ <string name="yesterday">Včera</string>
+ <string name="today">Dnes</string>
+ <string name="tomorrow">Zajtra</string>
+
+ <string name="hour_minute_24">%H:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">HH:mm</string>
+ <string name="numeric_date">%-e.%-m.%Y</string>
+ <string name="numeric_date_format">d.M.yyyy</string>
+ <string name="numeric_date_template">"%s.%s.%s"</string>
+ <string name="month_day_year">%-e. %B %Y</string>
+ <string name="time_of_day">%-k:%M:%S</string>
+ <string name="date_and_time">%-k:%M:%S %-e.%-m.%Y</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%-e.%-m.%Y</string>
+ <string name="month_day">%-e. %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%-e. %b</string>
+ <string name="abbrev_month">%b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%3$s.%2$s. - %8$s.%7$s.</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s. - %6$s, %8$s.%7$s.</string>
+ <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s - %8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s - %6$s, %8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s - %10$s %6$s, %8$s.%7$s.%9$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s. - %10$s %8$s.%7$s.</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s. - %10$s %6$s, %8$s.%7$s.</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s - %10$s %8$s.%7$s.%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s, %3$s</string>
+ <string name="wday_date">%2$s, %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s. %2$s - %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s. %2$s - %10$s %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s. %2$s - %10$s %6$s, %8$s. %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s - %10$s %8$s. %7$s %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s - %10$s %6$s, %8$s. %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s %4$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="same_month_md1_md2">%3$s. - %8$s. %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s. - %8$s. %2$s %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E, d. MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE, d. MMM y</string>
+</resources>
diff --git a/core/res/res/values-sl/donottranslate-cldr.xml b/core/res/res/values-sl/donottranslate-cldr.xml
new file mode 100644
index 0000000..372b0d5
--- /dev/null
+++ b/core/res/res/values-sl/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">januar</string>
+ <string name="month_long_standalone_february">februar</string>
+ <string name="month_long_standalone_march">marec</string>
+ <string name="month_long_standalone_april">april</string>
+ <string name="month_long_standalone_may">maj</string>
+ <string name="month_long_standalone_june">junij</string>
+ <string name="month_long_standalone_july">julij</string>
+ <string name="month_long_standalone_august">avgust</string>
+ <string name="month_long_standalone_september">september</string>
+ <string name="month_long_standalone_october">oktober</string>
+ <string name="month_long_standalone_november">november</string>
+ <string name="month_long_standalone_december">december</string>
+
+ <string name="month_long_january">januar</string>
+ <string name="month_long_february">februar</string>
+ <string name="month_long_march">marec</string>
+ <string name="month_long_april">april</string>
+ <string name="month_long_may">maj</string>
+ <string name="month_long_june">junij</string>
+ <string name="month_long_july">julij</string>
+ <string name="month_long_august">avgust</string>
+ <string name="month_long_september">september</string>
+ <string name="month_long_october">oktober</string>
+ <string name="month_long_november">november</string>
+ <string name="month_long_december">december</string>
+
+ <string name="month_medium_january">jan</string>
+ <string name="month_medium_february">feb</string>
+ <string name="month_medium_march">mar</string>
+ <string name="month_medium_april">apr</string>
+ <string name="month_medium_may">maj</string>
+ <string name="month_medium_june">jun</string>
+ <string name="month_medium_july">jul</string>
+ <string name="month_medium_august">avg</string>
+ <string name="month_medium_september">sep</string>
+ <string name="month_medium_october">okt</string>
+ <string name="month_medium_november">nov</string>
+ <string name="month_medium_december">dec</string>
+
+ <string name="month_shortest_january">j</string>
+ <string name="month_shortest_february">f</string>
+ <string name="month_shortest_march">m</string>
+ <string name="month_shortest_april">a</string>
+ <string name="month_shortest_may">m</string>
+ <string name="month_shortest_june">j</string>
+ <string name="month_shortest_july">j</string>
+ <string name="month_shortest_august">a</string>
+ <string name="month_shortest_september">s</string>
+ <string name="month_shortest_october">o</string>
+ <string name="month_shortest_november">n</string>
+ <string name="month_shortest_december">d</string>
+
+ <string name="day_of_week_long_sunday">nedelja</string>
+ <string name="day_of_week_long_monday">ponedeljek</string>
+ <string name="day_of_week_long_tuesday">torek</string>
+ <string name="day_of_week_long_wednesday">sreda</string>
+ <string name="day_of_week_long_thursday">četrtek</string>
+ <string name="day_of_week_long_friday">petek</string>
+ <string name="day_of_week_long_saturday">sobota</string>
+
+ <string name="day_of_week_medium_sunday">ned</string>
+ <string name="day_of_week_medium_monday">pon</string>
+ <string name="day_of_week_medium_tuesday">tor</string>
+ <string name="day_of_week_medium_wednesday">sre</string>
+ <string name="day_of_week_medium_thursday">čet</string>
+ <string name="day_of_week_medium_friday">pet</string>
+ <string name="day_of_week_medium_saturday">sob</string>
+
+ <string name="day_of_week_short_sunday">ned</string>
+ <string name="day_of_week_short_monday">pon</string>
+ <string name="day_of_week_short_tuesday">tor</string>
+ <string name="day_of_week_short_wednesday">sre</string>
+ <string name="day_of_week_short_thursday">čet</string>
+ <string name="day_of_week_short_friday">pet</string>
+ <string name="day_of_week_short_saturday">sob</string>
+
+ <string name="day_of_week_shortest_sunday">n</string>
+ <string name="day_of_week_shortest_monday">p</string>
+ <string name="day_of_week_shortest_tuesday">t</string>
+ <string name="day_of_week_shortest_wednesday">s</string>
+ <string name="day_of_week_shortest_thursday">č</string>
+ <string name="day_of_week_shortest_friday">p</string>
+ <string name="day_of_week_shortest_saturday">s</string>
+
+ <string name="am">dop.</string>
+ <string name="pm">pop.</string>
+ <string name="yesterday">Včeraj</string>
+ <string name="today">Danes</string>
+ <string name="tomorrow">Jutri</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%-e. %m. %Y</string>
+ <string name="numeric_date_format">d. MM. yyyy</string>
+ <string name="numeric_date_template">"%s. %s. %s"</string>
+ <string name="month_day_year">%d. %B %Y</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %-e. %b. %Y</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%-e. %b. %Y</string>
+ <string name="month_day">%-e. %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%-e. %b.</string>
+ <string name="abbrev_month">%b</string>
+ <string name="abbrev_month_year">%b. %Y</string>
+ <string name="time1_time2">%1$s – %2$s</string>
+ <string name="date1_date2">%2$s – %5$s</string>
+ <string name="numeric_md1_md2">%3$s. %2$s. – %8$s. %7$s.</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s., %3$s. %2$s. – %6$s., %8$s. %7$s.</string>
+ <string name="numeric_mdy1_mdy2">%3$s. %2$s. %4$s – %8$s. %7$s. %9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s., %3$s. %2$s. %4$s – %6$s., %8$s. %7$s. %9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s., %3$s. %2$s. %4$s – %10$s %6$s., %8$s. %7$s. %9$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s. %2$s. – %10$s %8$s. %7$s.</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s., %3$s. %2$s. – %10$s %6$s., %8$s. %7$s.</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s. %4$s – %10$s %8$s. %7$s. %9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s., %2$s – %6$s %4$s., %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s., %2$s – %4$s., %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s., %3$s</string>
+ <string name="wday_date">%2$s., %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s. %2$s – %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s. %2$s – %10$s %8$s. %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s. %2$s – %10$s %8$s. %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s. %4$s – %10$s %8$s. %7$s. %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s. %4$s – %10$s %8$s. %7$s. %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s., %3$s. %2$s. %4$s – %10$s %6$s., %8$s. %7$s. %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s., %3$s. %2$s. %4$s – %10$s %6$s., %8$s. %7$s. %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s., %3$s. %2$s. %4$s – %6$s., %8$s. %7$s. %9$s</string>
+ <string name="same_month_md1_md2">%3$s.–%8$s. %2$s.</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s. %2$s. – %8$s. %7$s. %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s.–%8$s. %2$s. %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s., %3$s. %2$s. – %6$s., %8$s. %7$s. %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E MMMM d</string>
+ <string name="abbrev_wday_month_day_year">E., d. MMM. y</string>
+</resources>
diff --git a/core/res/res/values-sr/donottranslate-cldr.xml b/core/res/res/values-sr/donottranslate-cldr.xml
new file mode 100644
index 0000000..7c5c6a9
--- /dev/null
+++ b/core/res/res/values-sr/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">јануар</string>
+ <string name="month_long_standalone_february">фебруар</string>
+ <string name="month_long_standalone_march">март</string>
+ <string name="month_long_standalone_april">април</string>
+ <string name="month_long_standalone_may">мај</string>
+ <string name="month_long_standalone_june">јун</string>
+ <string name="month_long_standalone_july">јул</string>
+ <string name="month_long_standalone_august">август</string>
+ <string name="month_long_standalone_september">септембар</string>
+ <string name="month_long_standalone_october">октобар</string>
+ <string name="month_long_standalone_november">новембар</string>
+ <string name="month_long_standalone_december">децембар</string>
+
+ <string name="month_long_january">јануар</string>
+ <string name="month_long_february">фебруар</string>
+ <string name="month_long_march">март</string>
+ <string name="month_long_april">април</string>
+ <string name="month_long_may">мај</string>
+ <string name="month_long_june">јун</string>
+ <string name="month_long_july">јул</string>
+ <string name="month_long_august">август</string>
+ <string name="month_long_september">септембар</string>
+ <string name="month_long_october">октобар</string>
+ <string name="month_long_november">новембар</string>
+ <string name="month_long_december">децембар</string>
+
+ <string name="month_medium_january">јан</string>
+ <string name="month_medium_february">феб</string>
+ <string name="month_medium_march">мар</string>
+ <string name="month_medium_april">апр</string>
+ <string name="month_medium_may">мај</string>
+ <string name="month_medium_june">јун</string>
+ <string name="month_medium_july">јул</string>
+ <string name="month_medium_august">авг</string>
+ <string name="month_medium_september">сеп</string>
+ <string name="month_medium_october">окт</string>
+ <string name="month_medium_november">нов</string>
+ <string name="month_medium_december">дец</string>
+
+ <string name="month_shortest_january">ј</string>
+ <string name="month_shortest_february">ф</string>
+ <string name="month_shortest_march">м</string>
+ <string name="month_shortest_april">а</string>
+ <string name="month_shortest_may">м</string>
+ <string name="month_shortest_june">ј</string>
+ <string name="month_shortest_july">ј</string>
+ <string name="month_shortest_august">а</string>
+ <string name="month_shortest_september">с</string>
+ <string name="month_shortest_october">о</string>
+ <string name="month_shortest_november">н</string>
+ <string name="month_shortest_december">д</string>
+
+ <string name="day_of_week_long_sunday">недеља</string>
+ <string name="day_of_week_long_monday">понедељак</string>
+ <string name="day_of_week_long_tuesday">уторак</string>
+ <string name="day_of_week_long_wednesday">среда</string>
+ <string name="day_of_week_long_thursday">четвртак</string>
+ <string name="day_of_week_long_friday">петак</string>
+ <string name="day_of_week_long_saturday">субота</string>
+
+ <string name="day_of_week_medium_sunday">нед</string>
+ <string name="day_of_week_medium_monday">пон</string>
+ <string name="day_of_week_medium_tuesday">уто</string>
+ <string name="day_of_week_medium_wednesday">сре</string>
+ <string name="day_of_week_medium_thursday">чет</string>
+ <string name="day_of_week_medium_friday">пет</string>
+ <string name="day_of_week_medium_saturday">суб</string>
+
+ <string name="day_of_week_short_sunday">нед</string>
+ <string name="day_of_week_short_monday">пон</string>
+ <string name="day_of_week_short_tuesday">уто</string>
+ <string name="day_of_week_short_wednesday">сре</string>
+ <string name="day_of_week_short_thursday">чет</string>
+ <string name="day_of_week_short_friday">пет</string>
+ <string name="day_of_week_short_saturday">суб</string>
+
+ <string name="day_of_week_shortest_sunday">н</string>
+ <string name="day_of_week_shortest_monday">п</string>
+ <string name="day_of_week_shortest_tuesday">у</string>
+ <string name="day_of_week_shortest_wednesday">с</string>
+ <string name="day_of_week_shortest_thursday">ч</string>
+ <string name="day_of_week_shortest_friday">п</string>
+ <string name="day_of_week_shortest_saturday">с</string>
+
+ <string name="am">пре подне</string>
+ <string name="pm">поподне</string>
+ <string name="yesterday">јуче</string>
+ <string name="today">данас</string>
+ <string name="tomorrow">сутра</string>
+
+ <string name="hour_minute_24">%H.%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">HH.mm</string>
+ <string name="numeric_date">%-e.%-m.%Y.</string>
+ <string name="numeric_date_format">d.M.yyyy.</string>
+ <string name="numeric_date_template">"%s.%s.%s."</string>
+ <string name="month_day_year">%d. %B %Y.</string>
+ <string name="time_of_day">%H.%M.%S</string>
+ <string name="date_and_time">%H.%M.%S %d.%m.%Y.</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%d.%m.%Y.</string>
+ <string name="month_day">%B %-e.</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%Y %B</string>
+ <string name="abbrev_month_day">%b %-e.</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%b. %Y</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%3$s.%2$s - %8$s.%7$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s - %6$s, %8$s.%7$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s. - %8$s.%7$s.%9$s.</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s. - %6$s, %8$s.%7$s.%9$s.</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s. %4$s. - %10$s %6$s, %8$s. %7$s. %9$s.</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s/%2$s - %10$s %8$s/%7$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s - %10$s %6$s, %7$s-%8$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s. - %10$s %8$s.%7$s.%9$s.</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s - %6$s %4$s, %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s, %2$s - %4$s, %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s - %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s, %3$s</string>
+ <string name="wday_date">%2$s, %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%2$s %3$s. - %7$s %8$s.</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s. - %10$s %7$s %8$s.</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s. - %10$s %7$s %8$s.</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s - %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s. - %10$s %8$s. %7$s %9$s.</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s. %2$s %4$s. - %10$s %8$s. %7$s %9$s.</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s. - %10$s %6$s, %8$s. %7$s %9$s.</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s. %2$s %4$s. - %10$s %6$s, %8$s. %7$s %9$s.</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s %4$s. - %6$s, %8$s. %7$s %9$s.</string>
+ <string name="same_month_md1_md2">%3$s.-%8$s. %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s - %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s. %2$s - %8$s. %7$s %9$s.</string>
+ <string name="same_month_mdy1_mdy2">%3$s.-%8$s. %2$s %9$s.</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s. %2$s - %6$s, %8$s. %7$s %9$s.</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E MMMM d</string>
+ <string name="abbrev_wday_month_day_year">EEE, d. MMM y.</string>
+</resources>
diff --git a/core/res/res/values-th/donottranslate-cldr.xml b/core/res/res/values-th/donottranslate-cldr.xml
new file mode 100644
index 0000000..4e6bafe
--- /dev/null
+++ b/core/res/res/values-th/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">มกราคม</string>
+ <string name="month_long_standalone_february">กุมภาพันธ์</string>
+ <string name="month_long_standalone_march">มีนาคม</string>
+ <string name="month_long_standalone_april">เมษายน</string>
+ <string name="month_long_standalone_may">พฤษภาคม</string>
+ <string name="month_long_standalone_june">มิถุนายน</string>
+ <string name="month_long_standalone_july">กรกฎาคม</string>
+ <string name="month_long_standalone_august">สิงหาคม</string>
+ <string name="month_long_standalone_september">กันยายน</string>
+ <string name="month_long_standalone_october">ตุลาคม</string>
+ <string name="month_long_standalone_november">พฤศจิกายน</string>
+ <string name="month_long_standalone_december">ธันวาคม</string>
+
+ <string name="month_long_january">มกราคม</string>
+ <string name="month_long_february">กุมภาพันธ์</string>
+ <string name="month_long_march">มีนาคม</string>
+ <string name="month_long_april">เมษายน</string>
+ <string name="month_long_may">พฤษภาคม</string>
+ <string name="month_long_june">มิถุนายน</string>
+ <string name="month_long_july">กรกฎาคม</string>
+ <string name="month_long_august">สิงหาคม</string>
+ <string name="month_long_september">กันยายน</string>
+ <string name="month_long_october">ตุลาคม</string>
+ <string name="month_long_november">พฤศจิกายน</string>
+ <string name="month_long_december">ธันวาคม</string>
+
+ <string name="month_medium_january">ม.ค.</string>
+ <string name="month_medium_february">ก.พ.</string>
+ <string name="month_medium_march">มี.ค.</string>
+ <string name="month_medium_april">เม.ย.</string>
+ <string name="month_medium_may">พ.ค.</string>
+ <string name="month_medium_june">มิ.ย.</string>
+ <string name="month_medium_july">ก.ค.</string>
+ <string name="month_medium_august">ส.ค.</string>
+ <string name="month_medium_september">ก.ย.</string>
+ <string name="month_medium_october">ต.ค.</string>
+ <string name="month_medium_november">พ.ย.</string>
+ <string name="month_medium_december">ธ.ค.</string>
+
+ <string name="month_shortest_january">ม.ค.</string>
+ <string name="month_shortest_february">ก.พ.</string>
+ <string name="month_shortest_march">มี.ค.</string>
+ <string name="month_shortest_april">เม.ย.</string>
+ <string name="month_shortest_may">พ.ค.</string>
+ <string name="month_shortest_june">มิ.ย.</string>
+ <string name="month_shortest_july">ก.ค.</string>
+ <string name="month_shortest_august">ส.ค.</string>
+ <string name="month_shortest_september">ก.ย.</string>
+ <string name="month_shortest_october">ต.ค.</string>
+ <string name="month_shortest_november">พ.ย.</string>
+ <string name="month_shortest_december">ธ.ค.</string>
+
+ <string name="day_of_week_long_sunday">วันอาทิตย์</string>
+ <string name="day_of_week_long_monday">วันจันทร์</string>
+ <string name="day_of_week_long_tuesday">วันอังคาร</string>
+ <string name="day_of_week_long_wednesday">วันพุธ</string>
+ <string name="day_of_week_long_thursday">วันพฤหัสบดี</string>
+ <string name="day_of_week_long_friday">วันศุกร์</string>
+ <string name="day_of_week_long_saturday">วันเสาร์</string>
+
+ <string name="day_of_week_medium_sunday">อา.</string>
+ <string name="day_of_week_medium_monday">จ.</string>
+ <string name="day_of_week_medium_tuesday">อ.</string>
+ <string name="day_of_week_medium_wednesday">พ.</string>
+ <string name="day_of_week_medium_thursday">พฤ.</string>
+ <string name="day_of_week_medium_friday">ศ.</string>
+ <string name="day_of_week_medium_saturday">ส.</string>
+
+ <string name="day_of_week_short_sunday">อา.</string>
+ <string name="day_of_week_short_monday">จ.</string>
+ <string name="day_of_week_short_tuesday">อ.</string>
+ <string name="day_of_week_short_wednesday">พ.</string>
+ <string name="day_of_week_short_thursday">พฤ.</string>
+ <string name="day_of_week_short_friday">ศ.</string>
+ <string name="day_of_week_short_saturday">ส.</string>
+
+ <string name="day_of_week_shortest_sunday">อ</string>
+ <string name="day_of_week_shortest_monday">จ</string>
+ <string name="day_of_week_shortest_tuesday">อ</string>
+ <string name="day_of_week_shortest_wednesday">พ</string>
+ <string name="day_of_week_shortest_thursday">พ</string>
+ <string name="day_of_week_shortest_friday">ศ</string>
+ <string name="day_of_week_shortest_saturday">ส</string>
+
+ <string name="am">ก่อนเที่ยง</string>
+ <string name="pm">หลังเที่ยง</string>
+ <string name="yesterday">เมื่อวาน</string>
+ <string name="today">วันนี้</string>
+ <string name="tomorrow">พรุ่งนี้</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%-e/%-m/%Y</string>
+ <string name="numeric_date_format">d/M/yyyy</string>
+ <string name="numeric_date_template">"%s/%s/%s"</string>
+ <string name="month_day_year">%-e %B %Y</string>
+ <string name="time_of_day">%-k:%M:%S</string>
+ <string name="date_and_time">%-k:%M:%S, %-e %b %Y</string>
+ <string name="date_time">%2$s, %1$s</string>
+ <string name="time_date">%1$s, %3$s</string>
+ <string name="abbrev_month_day_year">%-e %b %Y</string>
+ <string name="month_day">%-e %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%-e %b</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%3$s/%2$s - %8$s/%7$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s %3$s – %6$s %8$s/%2$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s/%2$s/%4$s – %8$s/%7$s/%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s %3$s/%2$s/%4$s – %6$s %8$s/%7$s/%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s, %1$s %3$s/%2$s/%4$s - %10$s, %6$s %8$s/%7$s/%9$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s, %3$s/%2$s - %10$s, %8$s/%7$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s, %1$s, %3$s/%2$s - %10$s, %6$s, %8$s/%7$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s, %3$s/%2$s/%4$s - %10$s, %8$s/%7$s/%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s, %1$s %2$s - %6$s, %4$s %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s, %2$s - %6$s, %5$s</string>
+ <string name="time_wday_date">%1$s, %2$s %3$s</string>
+ <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday">%1$s, %2$s</string>
+ <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s, %3$s %2$s - %10$s, %8$s %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s, %3$s %2$s - %10$s, %8$s %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s, %1$s %3$s %2$s - %10$s, %6$s %8$s %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s, %1$s %3$s %2$s - %10$s, %6$s %8$s %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s, %3$s %2$s %4$s - %10$s, %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s, %3$s %2$s %4$s - %10$s, %8$s %7$s %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s, %1$s %3$s %2$s %4$s - %10$s, %6$s %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s, %1$s %3$s %2$s %4$s - %10$s, %6$s %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s %4$s - %6$s %8$s %7$s %9$s</string>
+ <string name="same_month_md1_md2">%3$s – %8$s %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s %2$s – %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s %3$s %2$s – %6$s %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E d MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE d MMM y</string>
+</resources>
diff --git a/core/res/res/values-tl/donottranslate-cldr.xml b/core/res/res/values-tl/donottranslate-cldr.xml
new file mode 100644
index 0000000..e3106c7
--- /dev/null
+++ b/core/res/res/values-tl/donottranslate-cldr.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">1</string>
+ <string name="month_long_standalone_february">2</string>
+ <string name="month_long_standalone_march">3</string>
+ <string name="month_long_standalone_april">4</string>
+ <string name="month_long_standalone_may">5</string>
+ <string name="month_long_standalone_june">6</string>
+ <string name="month_long_standalone_july">7</string>
+ <string name="month_long_standalone_august">8</string>
+ <string name="month_long_standalone_september">9</string>
+ <string name="month_long_standalone_october">10</string>
+ <string name="month_long_standalone_november">11</string>
+ <string name="month_long_standalone_december">12</string>
+
+ <string name="month_long_january">1</string>
+ <string name="month_long_february">2</string>
+ <string name="month_long_march">3</string>
+ <string name="month_long_april">4</string>
+ <string name="month_long_may">5</string>
+ <string name="month_long_june">6</string>
+ <string name="month_long_july">7</string>
+ <string name="month_long_august">8</string>
+ <string name="month_long_september">9</string>
+ <string name="month_long_october">10</string>
+ <string name="month_long_november">11</string>
+ <string name="month_long_december">12</string>
+
+
+ <string name="month_shortest_january">1</string>
+ <string name="month_shortest_february">2</string>
+ <string name="month_shortest_march">3</string>
+ <string name="month_shortest_april">4</string>
+ <string name="month_shortest_may">5</string>
+ <string name="month_shortest_june">6</string>
+ <string name="month_shortest_july">7</string>
+ <string name="month_shortest_august">8</string>
+ <string name="month_shortest_september">9</string>
+ <string name="month_shortest_october">10</string>
+ <string name="month_shortest_november">11</string>
+ <string name="month_shortest_december">12</string>
+
+ <string name="day_of_week_long_sunday">1</string>
+ <string name="day_of_week_long_monday">2</string>
+ <string name="day_of_week_long_tuesday">3</string>
+ <string name="day_of_week_long_wednesday">4</string>
+ <string name="day_of_week_long_thursday">5</string>
+ <string name="day_of_week_long_friday">6</string>
+ <string name="day_of_week_long_saturday">7</string>
+
+
+
+ <string name="day_of_week_shortest_sunday">1</string>
+ <string name="day_of_week_shortest_monday">2</string>
+ <string name="day_of_week_shortest_tuesday">3</string>
+ <string name="day_of_week_shortest_wednesday">4</string>
+ <string name="day_of_week_shortest_thursday">5</string>
+ <string name="day_of_week_shortest_friday">6</string>
+ <string name="day_of_week_shortest_saturday">7</string>
+
+ <string name="am">AM</string>
+ <string name="pm">PM</string>
+ <string name="yesterday">Yesterday</string>
+ <string name="today">Today</string>
+ <string name="tomorrow">Tomorrow</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%Y-%m-%d</string>
+ <string name="numeric_date_format">yyyy-MM-dd</string>
+ <string name="numeric_date_template">"%s-%s-%s"</string>
+ <string name="month_day_year">%Y %B %-e</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %Y %b %-e</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%Y %b %-e</string>
+ <string name="month_day">%B %-e</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%Y %B</string>
+ <string name="abbrev_month_day">%b %-e</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%Y %b</string>
+ <string name="time1_time2">%1$s – %2$s</string>
+ <string name="date1_date2">%2$s – %5$s</string>
+ <string name="numeric_md1_md2">%2$s-%3$s – %7$s-%8$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %2$s-%3$s – %6$s, %7$s-%8$s</string>
+ <string name="numeric_mdy1_mdy2">%4$s-%2$s-%3$s – %9$s-%7$s-%8$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %4$s-%2$s-%3$s – %6$s, %9$s-%7$s-%8$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s-%2$s-%3$s – %10$s %6$s, %9$s-%7$s-%8$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %2$s-%3$s – %10$s %7$s-%8$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %2$s-%3$s – %10$s %6$s, %7$s-%8$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s %2$s – %6$s %4$s %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s %2$s – %4$s %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s %3$s</string>
+ <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%2$s %3$s – %7$s %8$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %2$s %3$s – %10$s %7$s %8$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s %2$s %3$s – %10$s %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %4$s-%2$s-%3$s – %10$s %9$s-%7$s-%8$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %4$s %2$s %3$s – %10$s %6$s, %9$s %7$s %8$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %4$s %2$s %3$s – %6$s, %9$s %7$s %8$s</string>
+ <string name="same_month_md1_md2">%2$s-%3$s – %8$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %2$s %3$s – %6$s %7$s %8$s</string>
+ <string name="same_year_mdy1_mdy2">%9$s-%2$s-%3$s – %7$s-%8$s</string>
+ <string name="same_month_mdy1_mdy2">%9$s-%2$s-%3$s – %8$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %9$s-%2$s-%3$s – %6$s, yyyy-%7$s-%8$s</string>
+ <string name="short_format_month">%B</string>
+ <string name="full_wday_month_day_no_year">E MMMM d</string>
+ <string name="abbrev_wday_month_day_year">EEE, y MMM d</string>
+</resources>
diff --git a/core/res/res/values-uk/donottranslate-cldr.xml b/core/res/res/values-uk/donottranslate-cldr.xml
new file mode 100644
index 0000000..0a49c20
--- /dev/null
+++ b/core/res/res/values-uk/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">Січень</string>
+ <string name="month_long_standalone_february">Лютий</string>
+ <string name="month_long_standalone_march">Березень</string>
+ <string name="month_long_standalone_april">Квітень</string>
+ <string name="month_long_standalone_may">Травень</string>
+ <string name="month_long_standalone_june">Червень</string>
+ <string name="month_long_standalone_july">Липень</string>
+ <string name="month_long_standalone_august">Серпень</string>
+ <string name="month_long_standalone_september">Вересень</string>
+ <string name="month_long_standalone_october">Жовтень</string>
+ <string name="month_long_standalone_november">Листопад</string>
+ <string name="month_long_standalone_december">Грудень</string>
+
+ <string name="month_long_january">січня</string>
+ <string name="month_long_february">лютого</string>
+ <string name="month_long_march">березня</string>
+ <string name="month_long_april">квітня</string>
+ <string name="month_long_may">травня</string>
+ <string name="month_long_june">червня</string>
+ <string name="month_long_july">липня</string>
+ <string name="month_long_august">серпня</string>
+ <string name="month_long_september">вересня</string>
+ <string name="month_long_october">жовтня</string>
+ <string name="month_long_november">листопада</string>
+ <string name="month_long_december">грудня</string>
+
+ <string name="month_medium_january">січ.</string>
+ <string name="month_medium_february">лют.</string>
+ <string name="month_medium_march">бер.</string>
+ <string name="month_medium_april">квіт.</string>
+ <string name="month_medium_may">трав.</string>
+ <string name="month_medium_june">черв.</string>
+ <string name="month_medium_july">лип.</string>
+ <string name="month_medium_august">серп.</string>
+ <string name="month_medium_september">вер.</string>
+ <string name="month_medium_october">жовт.</string>
+ <string name="month_medium_november">лист.</string>
+ <string name="month_medium_december">груд.</string>
+
+ <string name="month_shortest_january">С</string>
+ <string name="month_shortest_february">Л</string>
+ <string name="month_shortest_march">Б</string>
+ <string name="month_shortest_april">К</string>
+ <string name="month_shortest_may">Т</string>
+ <string name="month_shortest_june">Ч</string>
+ <string name="month_shortest_july">Л</string>
+ <string name="month_shortest_august">С</string>
+ <string name="month_shortest_september">В</string>
+ <string name="month_shortest_october">Ж</string>
+ <string name="month_shortest_november">Л</string>
+ <string name="month_shortest_december">Г</string>
+
+ <string name="day_of_week_long_sunday">Неділя</string>
+ <string name="day_of_week_long_monday">Понеділок</string>
+ <string name="day_of_week_long_tuesday">Вівторок</string>
+ <string name="day_of_week_long_wednesday">Середа</string>
+ <string name="day_of_week_long_thursday">Четвер</string>
+ <string name="day_of_week_long_friday">Пʼятниця</string>
+ <string name="day_of_week_long_saturday">Субота</string>
+
+ <string name="day_of_week_medium_sunday">Нд</string>
+ <string name="day_of_week_medium_monday">Пн</string>
+ <string name="day_of_week_medium_tuesday">Вт</string>
+ <string name="day_of_week_medium_wednesday">Ср</string>
+ <string name="day_of_week_medium_thursday">Чт</string>
+ <string name="day_of_week_medium_friday">Пт</string>
+ <string name="day_of_week_medium_saturday">Сб</string>
+
+ <string name="day_of_week_short_sunday">Нд</string>
+ <string name="day_of_week_short_monday">Пн</string>
+ <string name="day_of_week_short_tuesday">Вт</string>
+ <string name="day_of_week_short_wednesday">Ср</string>
+ <string name="day_of_week_short_thursday">Чт</string>
+ <string name="day_of_week_short_friday">Пт</string>
+ <string name="day_of_week_short_saturday">Сб</string>
+
+ <string name="day_of_week_shortest_sunday">Н</string>
+ <string name="day_of_week_shortest_monday">П</string>
+ <string name="day_of_week_shortest_tuesday">В</string>
+ <string name="day_of_week_shortest_wednesday">С</string>
+ <string name="day_of_week_shortest_thursday">Ч</string>
+ <string name="day_of_week_shortest_friday">П</string>
+ <string name="day_of_week_shortest_saturday">С</string>
+
+ <string name="am">дп</string>
+ <string name="pm">пп</string>
+ <string name="yesterday">Вчора</string>
+ <string name="today">Сьогодні</string>
+ <string name="tomorrow">Завтра</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%d.%m.%Y</string>
+ <string name="numeric_date_format">dd.MM.yyyy</string>
+ <string name="numeric_date_template">"%s.%s.%s"</string>
+ <string name="month_day_year">%-e %B %Y р.</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%H:%M:%S %-e %b %Y</string>
+ <string name="date_time">%2$s %1$s</string>
+ <string name="time_date">%1$s %3$s</string>
+ <string name="abbrev_month_day_year">%-e %b %Y</string>
+ <string name="month_day">%-e %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%-B %Y</string>
+ <string name="abbrev_month_day">%-e %b</string>
+ <string name="abbrev_month">%-b</string>
+ <string name="abbrev_month_year">%-b %Y</string>
+ <string name="time1_time2">%1$s – %2$s</string>
+ <string name="date1_date2">%2$s – %5$s</string>
+ <string name="numeric_md1_md2">%3$s.%2$s – %8$s.%7$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s.%2$s – %6$s, %8$s.%7$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s.%2$s.%4$s – %8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s.%2$s.%4$s – %6$s, %8$s.%7$s.%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s.%2$s.%4$s – %10$s %6$s, %8$s.%7$s.%9$s</string>
+ <string name="numeric_md1_time1_md2_time2">%5$s %3$s.%2$s – %10$s %8$s.%7$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s.%2$s – %10$s %6$s, %8$s.%7$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%5$s %3$s.%2$s.%4$s – %10$s %8$s.%7$s.%9$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%3$s %1$s, %2$s – %6$s %4$s, %5$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s, %2$s – %4$s, %5$s</string>
+ <string name="date1_time1_date2_time2">%3$s %2$s – %6$s %5$s</string>
+ <string name="time_wday_date">%1$s %2$s, %3$s</string>
+ <string name="wday_date">%2$s, %3$s</string>
+ <string name="time_wday">%1$s %2$s</string>
+ <string name="same_year_md1_md2">%3$s %2$s – %8$s %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s, %3$s %2$s – %6$s, %8$s %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%5$s %3$s %2$s – %10$s %8$s %7$s</string>
+ <string name="same_month_md1_time1_md2_time2">%5$s %3$s %2$s – %10$s %8$s %7$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%5$s %1$s, %3$s %2$s – %10$s %6$s, %8$s %7$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">%5$s %3$s %2$s %4$s – %10$s %8$s %7$s %9$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%5$s %1$s, %3$s %2$s %4$s – %10$s %6$s, %8$s %7$s %9$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s – %6$s, %8$s %7$s %9$s</string>
+ <string name="same_month_md1_md2">%3$s–%8$s %2$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s, %3$s %2$s – %6$s, %8$s %7$s</string>
+ <string name="same_year_mdy1_mdy2">%3$s %2$s – %8$s %7$s %9$s</string>
+ <string name="same_month_mdy1_mdy2">%3$s–%8$s %2$s %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s – %6$s, %8$s %7$s %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E, d MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
+</resources>
diff --git a/core/res/res/values-vi/donottranslate-cldr.xml b/core/res/res/values-vi/donottranslate-cldr.xml
new file mode 100644
index 0000000..30e0887
--- /dev/null
+++ b/core/res/res/values-vi/donottranslate-cldr.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="month_long_standalone_january">tháng một</string>
+ <string name="month_long_standalone_february">tháng hai</string>
+ <string name="month_long_standalone_march">tháng ba</string>
+ <string name="month_long_standalone_april">tháng tư</string>
+ <string name="month_long_standalone_may">tháng năm</string>
+ <string name="month_long_standalone_june">tháng sáu</string>
+ <string name="month_long_standalone_july">tháng bảy</string>
+ <string name="month_long_standalone_august">tháng tám</string>
+ <string name="month_long_standalone_september">tháng chín</string>
+ <string name="month_long_standalone_october">tháng mười</string>
+ <string name="month_long_standalone_november">tháng mười một</string>
+ <string name="month_long_standalone_december">tháng mười hai</string>
+
+ <string name="month_long_january">tháng một</string>
+ <string name="month_long_february">tháng hai</string>
+ <string name="month_long_march">tháng ba</string>
+ <string name="month_long_april">tháng tư</string>
+ <string name="month_long_may">tháng năm</string>
+ <string name="month_long_june">tháng sáu</string>
+ <string name="month_long_july">tháng bảy</string>
+ <string name="month_long_august">tháng tám</string>
+ <string name="month_long_september">tháng chín</string>
+ <string name="month_long_october">tháng mười</string>
+ <string name="month_long_november">tháng mười một</string>
+ <string name="month_long_december">tháng mười hai</string>
+
+ <string name="month_medium_january">thg 1</string>
+ <string name="month_medium_february">thg 2</string>
+ <string name="month_medium_march">thg 3</string>
+ <string name="month_medium_april">thg 4</string>
+ <string name="month_medium_may">thg 5</string>
+ <string name="month_medium_june">thg 6</string>
+ <string name="month_medium_july">thg 7</string>
+ <string name="month_medium_august">thg 8</string>
+ <string name="month_medium_september">thg 9</string>
+ <string name="month_medium_october">thg 10</string>
+ <string name="month_medium_november">thg 11</string>
+ <string name="month_medium_december">thg 12</string>
+
+ <string name="month_shortest_january">1</string>
+ <string name="month_shortest_february">2</string>
+ <string name="month_shortest_march">3</string>
+ <string name="month_shortest_april">4</string>
+ <string name="month_shortest_may">5</string>
+ <string name="month_shortest_june">6</string>
+ <string name="month_shortest_july">7</string>
+ <string name="month_shortest_august">8</string>
+ <string name="month_shortest_september">9</string>
+ <string name="month_shortest_october">10</string>
+ <string name="month_shortest_november">11</string>
+ <string name="month_shortest_december">12</string>
+
+ <string name="day_of_week_long_sunday">Chủ nhật</string>
+ <string name="day_of_week_long_monday">Thứ hai</string>
+ <string name="day_of_week_long_tuesday">Thứ ba</string>
+ <string name="day_of_week_long_wednesday">Thứ tư</string>
+ <string name="day_of_week_long_thursday">Thứ năm</string>
+ <string name="day_of_week_long_friday">Thứ sáu</string>
+ <string name="day_of_week_long_saturday">Thứ bảy</string>
+
+ <string name="day_of_week_medium_sunday">CN</string>
+ <string name="day_of_week_medium_monday">Th 2</string>
+ <string name="day_of_week_medium_tuesday">Th 3</string>
+ <string name="day_of_week_medium_wednesday">Th 4</string>
+ <string name="day_of_week_medium_thursday">Th 5</string>
+ <string name="day_of_week_medium_friday">Th 6</string>
+ <string name="day_of_week_medium_saturday">Th 7</string>
+
+ <string name="day_of_week_short_sunday">CN</string>
+ <string name="day_of_week_short_monday">Th 2</string>
+ <string name="day_of_week_short_tuesday">Th 3</string>
+ <string name="day_of_week_short_wednesday">Th 4</string>
+ <string name="day_of_week_short_thursday">Th 5</string>
+ <string name="day_of_week_short_friday">Th 6</string>
+ <string name="day_of_week_short_saturday">Th 7</string>
+
+ <string name="day_of_week_shortest_sunday">1</string>
+ <string name="day_of_week_shortest_monday">2</string>
+ <string name="day_of_week_shortest_tuesday">3</string>
+ <string name="day_of_week_shortest_wednesday">4</string>
+ <string name="day_of_week_shortest_thursday">5</string>
+ <string name="day_of_week_shortest_friday">6</string>
+ <string name="day_of_week_shortest_saturday">7</string>
+
+ <string name="am">SA</string>
+ <string name="pm">CH</string>
+ <string name="yesterday">Yesterday</string>
+ <string name="today">Today</string>
+ <string name="tomorrow">Tomorrow</string>
+
+ <string name="hour_minute_24">%-k:%M</string>
+ <string name="hour_minute_ampm">%-l:%M %p</string>
+ <string name="hour_minute_cap_ampm">%-l:%M %^p</string>
+ <string name="twelve_hour_time_format">h:mm a</string>
+ <string name="twenty_four_hour_time_format">H:mm</string>
+ <string name="numeric_date">%d/%m/%Y</string>
+ <string name="numeric_date_format">dd/MM/yyyy</string>
+ <string name="numeric_date_template">"%s/%s/%s"</string>
+ <string name="month_day_year">Ngày %d tháng %-m năm %Y</string>
+ <string name="time_of_day">%H:%M:%S</string>
+ <string name="date_and_time">%d-%m-%Y %H:%M:%S</string>
+ <string name="date_time">%1$s %2$s</string>
+ <string name="time_date">%3$s %1$s</string>
+ <string name="abbrev_month_day_year">%d-%m-%Y</string>
+ <string name="month_day">%-e %B</string>
+ <string name="month">%-B</string>
+ <string name="month_year">%B %Y</string>
+ <string name="abbrev_month_day">%-e %b</string>
+ <string name="abbrev_month">%b</string>
+ <string name="abbrev_month_year">%b %Y</string>
+ <string name="time1_time2">%1$s - %2$s</string>
+ <string name="date1_date2">%2$s - %5$s</string>
+ <string name="numeric_md1_md2">%3$s/%2$s - %8$s/%7$s</string>
+ <string name="numeric_wday1_md1_wday2_md2">%1$s, %3$s/%2$s - %6$s, %8$s/%7$s</string>
+ <string name="numeric_mdy1_mdy2">%3$s/%2$s/%4$s - %8$s/%7$s/%9$s</string>
+ <string name="numeric_wday1_mdy1_wday2_mdy2">%1$s, %3$s/%2$s/%4$s - %6$s, %8$s/%7$s/%9$s</string>
+ <string name="numeric_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s-%2$s-%4$s %5$s - %6$s, %8$s-%7$s-%9$s %10$s</string>
+ <string name="numeric_md1_time1_md2_time2">%3$s-%2$s %5$s - %8$s-%7$s %10$s</string>
+ <string name="numeric_wday1_md1_time1_wday2_md2_time2">%1$s, %3$s-%2$s %5$s - %6$s, %8$s-%7$s %10$s</string>
+ <string name="numeric_mdy1_time1_mdy2_time2">%3$s/%2$s/%4$s %5$s - %8$s/%7$s/%9$s %10$s</string>
+ <string name="wday1_date1_time1_wday2_date2_time2">%1$s %2$s %3$s - %4$s %5$s %6$s</string>
+ <string name="wday1_date1_wday2_date2">%1$s %2$s - %4$s %5$s</string>
+ <string name="date1_time1_date2_time2">%2$s %3$s - %5$s %6$s</string>
+ <string name="time_wday_date">%2$s %3$s %1$s</string>
+ <string name="wday_date">%2$s %3$s</string>
+ <string name="time_wday">%2$s %1$s</string>
+ <string name="same_year_md1_md2">%3$s %2$s - %8$s %7$s</string>
+ <string name="same_year_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
+ <string name="same_year_md1_time1_md2_time2">%3$s %2$s %5$s - %8$s %7$s %10$s</string>
+ <string name="same_month_md1_time1_md2_time2">%3$s %2$s %5$s - %8$s %7$s %10$s</string>
+ <string name="same_year_wday1_md1_time1_wday2_md2_time2">%1$s %3$s %2$s %5$s - %6$s %8$s %7$s %10$s</string>
+ <string name="same_month_wday1_md1_time1_wday2_md2_time2">%1$s %3$s %2$s %5$s - %6$s %8$s %7$s %10$s</string>
+ <string name="same_year_mdy1_time1_mdy2_time2">Ngày %3$s tháng %2$s năm %4$s %5$s - \'Ngày %8$s tháng %7$s năm %9$s %10$s</string>
+ <string name="same_month_mdy1_time1_mdy2_time2">Ngày %3$s tháng %2$s năm %4$s %5$s - \'Ngày %8$s tháng %7$s năm %9$s %10$s</string>
+ <string name="same_year_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s %2$s %4$s %5$s - %6$s, %8$s %7$s %9$s %10$s</string>
+ <string name="same_month_wday1_mdy1_time1_wday2_mdy2_time2">%1$s, %3$s %2$s %4$s %5$s - %6$s, %8$s %7$s %9$s %10$s</string>
+ <string name="same_month_wday1_mdy1_wday2_mdy2">%1$s, %3$s %2$s %4$s - %6$s, %8$s %7$s %9$s</string>
+ <string name="same_month_md1_md2">Ngày %3$s tháng %2$s - Ngày %8$s tháng %7$s</string>
+ <string name="same_month_wday1_md1_wday2_md2">%1$s %3$s %2$s - %6$s %8$s %7$s</string>
+ <string name="same_year_mdy1_mdy2">Ngày %3$s tháng %2$s - Ngày %8$s tháng %7$s năm %9$s</string>
+ <string name="same_month_mdy1_mdy2">Ngày %3$s tháng %2$s - Ngày %8$s tháng M năm %9$s</string>
+ <string name="same_year_wday1_mdy1_wday2_mdy2">%1$s, ngày %3$s %2$s - %6$s, ngày %8$s %7$s năm %9$s</string>
+ <string name="short_format_month">%b</string>
+ <string name="full_wday_month_day_no_year">E d MMMM</string>
+ <string name="abbrev_wday_month_day_year">EEE, d MMM y</string>
+</resources>
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index d5f385b..c8a4593 100755
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -47,6 +47,7 @@ import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.util.Arrays;
public class PackageManagerTests extends AndroidTestCase {
private static final boolean localLOGV = true;
@@ -2838,6 +2839,164 @@ public class PackageManagerTests extends AndroidTestCase {
installFromRawResource("install.apk", rapk2, PackageManager.INSTALL_REPLACE_EXISTING, true,
fail, retCode, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
}
+
+ @LargeTest
+ public void testPackageObbPaths_Nonexistent() {
+ try {
+ final PackageManager pm = getPm();
+
+ // Invalid Java package name.
+ pm.getPackageObbPaths("=non-existent");
+
+ fail("Should not be able to get package OBB paths for non-existent package");
+ } catch (IllegalArgumentException e) {
+ // pass
+ }
+ }
+
+ @LargeTest
+ public void testPackageObbPaths_Initial() {
+ InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
+
+ try {
+ final PackageManager pm = getPm();
+
+ assertEquals("Initial obb paths should be null",
+ null, pm.getPackageObbPaths(ip.pkg.packageName));
+ } finally {
+ cleanUpInstall(ip);
+ }
+ }
+
+ @LargeTest
+ public void testPackageObbPaths_Null() {
+ InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
+
+ try {
+ final PackageManager pm = getPm();
+
+ pm.setPackageObbPaths(ip.pkg.packageName, null);
+
+ assertEquals("Returned paths should be null",
+ null, pm.getPackageObbPaths(ip.pkg.packageName));
+ } finally {
+ cleanUpInstall(ip);
+ }
+ }
+
+ @LargeTest
+ public void testPackageObbPaths_Empty() {
+ InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
+
+ try {
+ final PackageManager pm = getPm();
+
+ final String[] paths = new String[0];
+
+ pm.setPackageObbPaths(ip.pkg.packageName, paths);
+
+ assertEquals("Empty list should be interpreted as null",
+ null, pm.getPackageObbPaths(ip.pkg.packageName));
+ } finally {
+ cleanUpInstall(ip);
+ }
+ }
+
+ @LargeTest
+ public void testPackageObbPaths_Single() {
+ InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
+
+ try {
+ final PackageManager pm = getPm();
+
+ final String[] paths = new String[] {
+ "/example/test",
+ };
+
+ pm.setPackageObbPaths(ip.pkg.packageName, paths.clone());
+
+ assertTrue("Previously set paths should be the same as the returned paths.",
+ Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName)));
+ } finally {
+ cleanUpInstall(ip);
+ }
+ }
+
+ @LargeTest
+ public void testPackageObbPaths_Multiple() {
+ InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
+
+ try {
+ final PackageManager pm = getPm();
+
+ final String[] paths = new String[] {
+ "/example/test1",
+ "/example/test2",
+ };
+
+ pm.setPackageObbPaths(ip.pkg.packageName, paths.clone());
+
+ assertTrue("Previously set paths should be the same as the returned paths.",
+ Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName)));
+ } finally {
+ cleanUpInstall(ip);
+ }
+ }
+
+ @LargeTest
+ public void testPackageObbPaths_Twice() {
+ InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
+
+ try {
+ final PackageManager pm = getPm();
+
+ final String[] paths = new String[] {
+ "/example/test1",
+ "/example/test2",
+ };
+
+ pm.setPackageObbPaths(ip.pkg.packageName, paths.clone());
+
+ assertTrue("Previously set paths should be the same as the returned paths.",
+ Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName)));
+
+ paths[0] = "/example/test3";
+ pm.setPackageObbPaths(ip.pkg.packageName, paths.clone());
+
+ assertTrue("Previously set paths should be the same as the returned paths.",
+ Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName)));
+ } finally {
+ cleanUpInstall(ip);
+ }
+ }
+
+ @LargeTest
+ public void testPackageObbPaths_ReplacePackage() {
+ InstallParams ip = sampleInstallFromRawResource(PackageManager.INSTALL_INTERNAL, false);
+
+ try {
+ final PackageManager pm = getPm();
+
+ final String[] paths = new String[] {
+ "/example/test1",
+ "/example/test2",
+ };
+
+ pm.setPackageObbPaths(ip.pkg.packageName, paths.clone());
+
+ Log.i(TAG, "Creating replaceReceiver");
+ final GenericReceiver receiver = new ReplaceReceiver(ip.pkg.packageName);
+
+ final int flags = PackageManager.INSTALL_REPLACE_EXISTING;
+ invokeInstallPackage(ip.packageURI, flags, receiver);
+ assertInstall(ip.pkg, flags, ip.pkg.installLocation);
+
+ assertTrue("Previously set paths should be the same as the returned paths.",
+ Arrays.equals(paths, pm.getPackageObbPaths(ip.pkg.packageName)));
+ } finally {
+ cleanUpInstall(ip);
+ }
+ }
/*---------- Recommended install location tests ----*/
/*
* TODO's
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index 7b49bc5..3f1a566 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -206,10 +206,20 @@ public class BitmapFactory {
public boolean inNativeAlloc;
/**
+ * If inPreferQualityOverSpeed is set to true, the decoder will try to
+ * decode the reconstructed image to a higher quality even at the
+ * expense of the decoding speed. Currently the field only affects JPEG
+ * decode, in the case of which a more accurate, but slightly slower,
+ * IDCT method will be used instead.
+ */
+ public boolean inPreferQualityOverSpeed;
+
+ /**
* The resulting width of the bitmap, set independent of the state of
* inJustDecodeBounds. However, if there is an error trying to decode,
* outWidth will be set to -1.
*/
+
public int outWidth;
/**
diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java
new file mode 100644
index 0000000..496e0c7
--- /dev/null
+++ b/graphics/java/android/graphics/BitmapRegionDecoder.java
@@ -0,0 +1,263 @@
+/* Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.graphics;
+
+import android.content.res.AssetManager;
+
+import java.io.BufferedInputStream;
+import java.io.FileDescriptor;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * BitmapRegionDecoder can be used to decode a rectangle region from an image.
+ * BitmapRegionDecoder is particularly useful when an original image is large and
+ * you only need parts of the image.
+ *
+ * <p>To create a BitmapRegionDecoder, call newInstance(...).
+ * Given a BitmapRegionDecoder, users can call decodeRegion() repeatedly
+ * to get a decoded Bitmap of the specified region.
+ *
+ */
+public final class BitmapRegionDecoder {
+ private int mNativeBitmapRegionDecoder;
+ private boolean mRecycled;
+
+ /**
+ * Create a BitmapRegionDecoder from the specified byte array.
+ * Currently only the JPEG and PNG formats are supported.
+ *
+ * @param data byte array of compressed image data.
+ * @param offset offset into data for where the decoder should begin
+ * parsing.
+ * @param length the number of bytes, beginning at offset, to parse
+ * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+ * shallow reference to the input. If this is false,
+ * then the BitmapRegionDecoder will explicitly make a copy of the
+ * input data, and keep that. Even if sharing is allowed,
+ * the implementation may still decide to make a deep
+ * copy of the input data. If an image is progressively encoded,
+ * allowing sharing may degrade the decoding speed.
+ * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+ * @throws IOException if the image format is not supported or can not be decoded.
+ */
+ public static BitmapRegionDecoder newInstance(byte[] data,
+ int offset, int length, boolean isShareable) throws IOException {
+ if ((offset | length) < 0 || data.length < offset + length) {
+ throw new ArrayIndexOutOfBoundsException();
+ }
+ return nativeNewInstance(data, offset, length, isShareable);
+ }
+
+ /**
+ * Create a BitmapRegionDecoder from the file descriptor.
+ * The position within the descriptor will not be changed when
+ * this returns, so the descriptor can be used again as is.
+ * Currently only the JPEG and PNG formats are supported.
+ *
+ * @param fd The file descriptor containing the data to decode
+ * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+ * shallow reference to the input. If this is false,
+ * then the BitmapRegionDecoder will explicitly make a copy of the
+ * input data, and keep that. Even if sharing is allowed,
+ * the implementation may still decide to make a deep
+ * copy of the input data. If an image is progressively encoded,
+ * allowing sharing may degrade the decoding speed.
+ * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+ * @throws IOException if the image format is not supported or can not be decoded.
+ */
+ public static BitmapRegionDecoder newInstance(
+ FileDescriptor fd, boolean isShareable) throws IOException {
+ return nativeNewInstance(fd, isShareable);
+ }
+
+ /**
+ * Create a BitmapRegionDecoder from an input stream.
+ * The stream's position will be where ever it was after the encoded data
+ * was read.
+ * Currently only the JPEG and PNG formats are supported.
+ *
+ * @param is The input stream that holds the raw data to be decoded into a
+ * BitmapRegionDecoder.
+ * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+ * shallow reference to the input. If this is false,
+ * then the BitmapRegionDecoder will explicitly make a copy of the
+ * input data, and keep that. Even if sharing is allowed,
+ * the implementation may still decide to make a deep
+ * copy of the input data. If an image is progressively encoded,
+ * allowing sharing may degrade the decoding speed.
+ * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+ * @throws IOException if the image format is not supported or can not be decoded.
+ */
+ public static BitmapRegionDecoder newInstance(InputStream is,
+ boolean isShareable) throws IOException {
+ // we need mark/reset to work properly in JNI
+
+ if (!is.markSupported()) {
+ is = new BufferedInputStream(is, 16 * 1024);
+ }
+
+ if (is instanceof AssetManager.AssetInputStream) {
+ return nativeNewInstance(
+ ((AssetManager.AssetInputStream) is).getAssetInt(),
+ isShareable);
+ } else {
+ // pass some temp storage down to the native code. 1024 is made up,
+ // but should be large enough to avoid too many small calls back
+ // into is.read(...).
+ byte [] tempStorage = new byte[16 * 1024];
+ return nativeNewInstance(is, tempStorage, isShareable);
+ }
+ }
+
+ /**
+ * Create a BitmapRegionDecoder from a file path.
+ * Currently only the JPEG and PNG formats are supported.
+ *
+ * @param pathName complete path name for the file to be decoded.
+ * @param isShareable If this is true, then the BitmapRegionDecoder may keep a
+ * shallow reference to the input. If this is false,
+ * then the BitmapRegionDecoder will explicitly make a copy of the
+ * input data, and keep that. Even if sharing is allowed,
+ * the implementation may still decide to make a deep
+ * copy of the input data. If an image is progressively encoded,
+ * allowing sharing may degrade the decoding speed.
+ * @return BitmapRegionDecoder, or null if the image data could not be decoded.
+ * @throws IOException if the image format is not supported or can not be decoded.
+ */
+ public static BitmapRegionDecoder newInstance(String pathName,
+ boolean isShareable) throws IOException {
+ BitmapRegionDecoder decoder = null;
+ InputStream stream = null;
+
+ try {
+ stream = new FileInputStream(pathName);
+ decoder = newInstance(stream, isShareable);
+ } finally {
+ if (stream != null) {
+ try {
+ stream.close();
+ } catch (IOException e) {
+ // do nothing here
+ }
+ }
+ }
+ return decoder;
+ }
+
+ /* Private constructor that must receive an already allocated native
+ region decoder int (pointer).
+
+ This can be called from JNI code.
+ */
+ private BitmapRegionDecoder(int decoder) {
+ mNativeBitmapRegionDecoder = decoder;
+ mRecycled = false;
+ }
+
+ /**
+ * Decodes a rectangle region in the image specified by rect.
+ *
+ * @param rect The rectangle that specified the region to be decode.
+ * @param options null-ok; Options that control downsampling.
+ * inPurgeable is not supported.
+ * @return The decoded bitmap, or null if the image data could not be
+ * decoded.
+ */
+ public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) {
+ checkRecycled("decodeRegion called on recycled region decoder");
+ if (rect.left < 0 || rect.top < 0 || rect.right > getWidth()
+ || rect.bottom > getHeight())
+ throw new IllegalArgumentException("rectangle is not inside the image");
+ return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top,
+ rect.right - rect.left, rect.bottom - rect.top, options);
+ }
+
+ /** Returns the original image's width */
+ public int getWidth() {
+ checkRecycled("getWidth called on recycled region decoder");
+ return nativeGetWidth(mNativeBitmapRegionDecoder);
+ }
+
+ /** Returns the original image's height */
+ public int getHeight() {
+ checkRecycled("getHeight called on recycled region decoder");
+ return nativeGetHeight(mNativeBitmapRegionDecoder);
+ }
+
+ /**
+ * Frees up the memory associated with this region decoder, and mark the
+ * region decoder as "dead", meaning it will throw an exception if decodeRegion(),
+ * getWidth() or getHeight() is called.
+ *
+ * <p>This operation cannot be reversed, so it should only be called if you are
+ * sure there are no further uses for the region decoder. This is an advanced call,
+ * and normally need not be called, since the normal GC process will free up this
+ * memory when there are no more references to this region decoder.
+ */
+ public void recycle() {
+ if (!mRecycled) {
+ nativeClean(mNativeBitmapRegionDecoder);
+ mRecycled = true;
+ }
+ }
+
+ /**
+ * Returns true if this region decoder has been recycled.
+ * If so, then it is an error to try use its method.
+ *
+ * @return true if the region decoder has been recycled
+ */
+ public final boolean isRecycled() {
+ return mRecycled;
+ }
+
+ /**
+ * Called by methods that want to throw an exception if the region decoder
+ * has already been recycled.
+ */
+ private void checkRecycled(String errorMessage) {
+ if (mRecycled) {
+ throw new IllegalStateException(errorMessage);
+ }
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ recycle();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ private static native Bitmap nativeDecodeRegion(int lbm,
+ int start_x, int start_y, int width, int height,
+ BitmapFactory.Options options);
+ private static native int nativeGetWidth(int lbm);
+ private static native int nativeGetHeight(int lbm);
+ private static native void nativeClean(int lbm);
+
+ private static native BitmapRegionDecoder nativeNewInstance(
+ byte[] data, int offset, int length, boolean isShareable);
+ private static native BitmapRegionDecoder nativeNewInstance(
+ FileDescriptor fd, boolean isShareable);
+ private static native BitmapRegionDecoder nativeNewInstance(
+ InputStream is, byte[] storage, boolean isShareable);
+ private static native BitmapRegionDecoder nativeNewInstance(
+ int asset, boolean isShareable);
+}
diff --git a/include/media/IMediaMetadataRetriever.h b/include/media/IMediaMetadataRetriever.h
index 9baba8e..8e3cdbb 100644
--- a/include/media/IMediaMetadataRetriever.h
+++ b/include/media/IMediaMetadataRetriever.h
@@ -32,9 +32,7 @@ public:
virtual void disconnect() = 0;
virtual status_t setDataSource(const char* srcUrl) = 0;
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
- virtual status_t setMode(int mode) = 0;
- virtual status_t getMode(int* mode) const = 0;
- virtual sp<IMemory> captureFrame() = 0;
+ virtual sp<IMemory> getFrameAtTime(int64_t timeUs, int option) = 0;
virtual sp<IMemory> extractAlbumArt() = 0;
virtual const char* extractMetadata(int keyCode) = 0;
};
diff --git a/include/media/MediaMetadataRetrieverInterface.h b/include/media/MediaMetadataRetrieverInterface.h
index ff57774..0449122 100644
--- a/include/media/MediaMetadataRetrieverInterface.h
+++ b/include/media/MediaMetadataRetrieverInterface.h
@@ -32,9 +32,7 @@ public:
virtual ~MediaMetadataRetrieverBase() {}
virtual status_t setDataSource(const char *url) = 0;
virtual status_t setDataSource(int fd, int64_t offset, int64_t length) = 0;
- virtual status_t setMode(int mode) = 0;
- virtual status_t getMode(int* mode) const = 0;
- virtual VideoFrame* captureFrame() = 0;
+ virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) = 0;
virtual MediaAlbumArt* extractAlbumArt() = 0;
virtual const char* extractMetadata(int keyCode) = 0;
};
@@ -43,35 +41,12 @@ public:
class MediaMetadataRetrieverInterface : public MediaMetadataRetrieverBase
{
public:
- MediaMetadataRetrieverInterface()
- : mMode(0) {
- }
+ MediaMetadataRetrieverInterface() {}
virtual ~MediaMetadataRetrieverInterface() {}
-
- // @param mode The intended mode of operations:
- // can be any of the following:
- // METADATA_MODE_NOOP: Experimental - just add and remove data source.
- // METADATA_MODE_FRAME_CAPTURE_ONLY: For capture frame/thumbnail only.
- // METADATA_MODE_METADATA_RETRIEVAL_ONLY: For meta data retrieval only.
- // METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL: For both frame
- // capture and meta data retrieval.
- virtual status_t setMode(int mode) {
- if (mode < METADATA_MODE_NOOP ||
- mode > METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL) {
- return BAD_VALUE;
- }
-
- mMode = mode;
- return NO_ERROR;
- }
-
- virtual status_t getMode(int* mode) const { *mode = mMode; return NO_ERROR; }
- virtual VideoFrame* captureFrame() { return NULL; }
+ virtual VideoFrame* getFrameAtTime(int64_t timeUs, int option) { return NULL; }
virtual MediaAlbumArt* extractAlbumArt() { return NULL; }
virtual const char* extractMetadata(int keyCode) { return NULL; }
-
- uint32_t mMode;
};
}; // namespace android
diff --git a/include/media/mediametadataretriever.h b/include/media/mediametadataretriever.h
index ddc07f6..e905006 100644
--- a/include/media/mediametadataretriever.h
+++ b/include/media/mediametadataretriever.h
@@ -42,37 +42,14 @@ enum {
METADATA_KEY_YEAR = 8,
METADATA_KEY_DURATION = 9,
METADATA_KEY_NUM_TRACKS = 10,
- METADATA_KEY_IS_DRM_CRIPPLED = 11,
- METADATA_KEY_CODEC = 12,
- METADATA_KEY_RATING = 13,
- METADATA_KEY_COMMENT = 14,
- METADATA_KEY_COPYRIGHT = 15,
- METADATA_KEY_BIT_RATE = 16,
- METADATA_KEY_FRAME_RATE = 17,
- METADATA_KEY_VIDEO_FORMAT = 18,
- METADATA_KEY_VIDEO_HEIGHT = 19,
- METADATA_KEY_VIDEO_WIDTH = 20,
- METADATA_KEY_WRITER = 21,
- METADATA_KEY_MIMETYPE = 22,
- METADATA_KEY_DISC_NUMBER = 23,
- METADATA_KEY_ALBUMARTIST = 24,
- METADATA_KEY_COMPILATION = 25,
+ METADATA_KEY_WRITER = 11,
+ METADATA_KEY_MIMETYPE = 12,
+ METADATA_KEY_ALBUMARTIST = 13,
+ METADATA_KEY_DISC_NUMBER = 14,
+ METADATA_KEY_COMPILATION = 15,
// Add more here...
};
-// The intended mode of operations:$
-// METADATA_MODE_NOOP: Experimental - just add and remove data source.$
-// METADATA_MODE_FRAME_CAPTURE_ONLY: For capture frame/thumbnail only.$
-// METADATA_MODE_METADATA_RETRIEVAL_ONLY: For meta data retrieval only.$
-// METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL: For both frame capture
-// and meta data retrieval.$
-enum {
- METADATA_MODE_NOOP = 0x00,
- METADATA_MODE_METADATA_RETRIEVAL_ONLY = 0x01,
- METADATA_MODE_FRAME_CAPTURE_ONLY = 0x02,
- METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL = 0x03
-};
-
class MediaMetadataRetriever: public RefBase
{
public:
@@ -81,9 +58,7 @@ public:
void disconnect();
status_t setDataSource(const char* dataSourceUrl);
status_t setDataSource(int fd, int64_t offset, int64_t length);
- status_t setMode(int mode);
- status_t getMode(int* mode);
- sp<IMemory> captureFrame();
+ sp<IMemory> getFrameAtTime(int64_t timeUs, int option);
sp<IMemory> extractAlbumArt();
const char* extractMetadata(int keyCode);
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index f6c55e4..ad9a94f 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -774,6 +774,9 @@ int Thread::_threadLoop(void* user)
self->mExitPending = true;
self->mLock.lock();
self->mRunning = false;
+ // clear thread ID so that requestExitAndWait() does not exit if
+ // called by a new thread using the same thread ID as this one.
+ self->mThread = thread_id_t(-1);
self->mThreadExitedCondition.broadcast();
self->mLock.unlock();
break;
diff --git a/media/java/android/media/MediaMetadataRetriever.java b/media/java/android/media/MediaMetadataRetriever.java
index 008528d..77e939e 100644
--- a/media/java/android/media/MediaMetadataRetriever.java
+++ b/media/java/android/media/MediaMetadataRetriever.java
@@ -29,7 +29,6 @@ import java.io.IOException;
/**
* MediaMetadataRetriever class provides a unified interface for retrieving
* frame and meta data from an input media file.
- * {@hide}
*/
public class MediaMetadataRetriever
{
@@ -42,41 +41,13 @@ public class MediaMetadataRetriever
@SuppressWarnings("unused")
private int mNativeContext;
+ private static final int EMBEDDED_PICTURE_TYPE_ANY = 0xFFFF;
+
public MediaMetadataRetriever() {
native_setup();
}
/**
- * Call this method before setDataSource() so that the mode becomes
- * effective for subsequent operations. This method can be called only once
- * at the beginning if the intended mode of operation for a
- * MediaMetadataRetriever object remains the same for its whole lifetime,
- * and thus it is unnecessary to call this method each time setDataSource()
- * is called. If this is not never called (which is allowed), by default the
- * intended mode of operation is to both capture frame and retrieve meta
- * data (i.e., MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY).
- * Often, this may not be what one wants, since doing this has negative
- * performance impact on execution time of a call to setDataSource(), since
- * both types of operations may be time consuming.
- *
- * @param mode The intended mode of operation. Can be any combination of
- * MODE_GET_METADATA_ONLY and MODE_CAPTURE_FRAME_ONLY:
- * 1. MODE_GET_METADATA_ONLY & MODE_CAPTURE_FRAME_ONLY:
- * For neither frame capture nor meta data retrieval
- * 2. MODE_GET_METADATA_ONLY: For meta data retrieval only
- * 3. MODE_CAPTURE_FRAME_ONLY: For frame capture only
- * 4. MODE_GET_METADATA_ONLY | MODE_CAPTURE_FRAME_ONLY:
- * For both frame capture and meta data retrieval
- */
- public native void setMode(int mode);
-
- /**
- * @return the current mode of operation. A negative return value indicates
- * some runtime error has occurred.
- */
- public native int getMode();
-
- /**
* Sets the data source (file pathname) to use. Call this
* method before the rest of the methods in this class. This method may be
* time-consuming.
@@ -190,22 +161,99 @@ public class MediaMetadataRetriever
/**
* Call this method after setDataSource(). This method finds a
- * representative frame if successful and returns it as a bitmap. This is
- * useful for generating a thumbnail for an input media source.
- *
+ * representative frame close to the given time position by considering
+ * the given option if possible, and returns it as a bitmap. This is
+ * useful for generating a thumbnail for an input data source or just
+ * obtain and display a frame at the given time position.
+ *
+ * @param timeUs The time position where the frame will be retrieved.
+ * When retrieving the frame at the given time position, there is no
+ * guarantee that the data source has a frame located at the position.
+ * When this happens, a frame nearby will be returned. If timeUs is
+ * negative, time position and option will ignored, and any frame
+ * that the implementation considers as representative may be returned.
+ *
+ * @param option a hint on how the frame is found. Use
+ * {@link #OPTION_PREVIOUS_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp earlier than or the same as timeUs. Use
+ * {@link #OPTION_NEXT_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp later than or the same as timeUs. Use
+ * {@link #OPTION_CLOSEST_SYNC} if one wants to retrieve a sync frame
+ * that has a timestamp closest to or the same as timeUs. Use
+ * {@link #OPTION_CLOSEST} if one wants to retrieve a frame that may
+ * or may not be a sync frame but is closest to or the same as timeUs.
+ * {@link #OPTION_CLOSEST} often has larger performance overhead compared
+ * to the other options if there is no sync frame located at timeUs.
+ *
* @return A Bitmap containing a representative video frame, which
* can be null, if such a frame cannot be retrieved.
*/
- public native Bitmap captureFrame();
+ public Bitmap getFrameAtTime(long timeUs, int option) {
+ if (option < OPTION_PREVIOUS_SYNC ||
+ option > OPTION_CLOSEST) {
+ throw new IllegalArgumentException("Unsupported option: " + option);
+ }
+
+ return _getFrameAtTime(timeUs, option);
+ }
+
+ /**
+ * Call this method after setDataSource(). This method finds a
+ * representative frame close to the given time position if possible,
+ * and returns it as a bitmap. This is useful for generating a thumbnail
+ * for an input data source. Call this method if one does not care
+ * how the frame is found as long as it is close to the given time;
+ * otherwise, please call {@link #getFrameAtTime(long, int)}.
+ *
+ * @param timeUs The time position where the frame will be retrieved.
+ * When retrieving the frame at the given time position, there is no
+ * guarentee that the data source has a frame located at the position.
+ * When this happens, a frame nearby will be returned. If timeUs is
+ * negative, time position and option will ignored, and any frame
+ * that the implementation considers as representative may be returned.
+ *
+ * @return A Bitmap containing a representative video frame, which
+ * can be null, if such a frame cannot be retrieved.
+ *
+ * @see #getFrameAtTime(long, int)
+ */
+ public Bitmap getFrameAtTime(long timeUs) {
+ return getFrameAtTime(timeUs, OPTION_CLOSEST_SYNC);
+ }
+
+ /**
+ * Call this method after setDataSource(). This method finds a
+ * representative frame at any time position if possible,
+ * and returns it as a bitmap. This is useful for generating a thumbnail
+ * for an input data source. Call this method if one does not
+ * care about where the frame is located; otherwise, please call
+ * {@link #getFrameAtTime(long)} or {@link #getFrameAtTime(long, int)}
+ *
+ * @return A Bitmap containing a representative video frame, which
+ * can be null, if such a frame cannot be retrieved.
+ *
+ * @see #getFrameAtTime(long)
+ * @see #getFrameAtTime(long, int)
+ */
+ public Bitmap getFrameAtTime() {
+ return getFrameAtTime(-1, OPTION_CLOSEST_SYNC);
+ }
+
+ private native Bitmap _getFrameAtTime(long timeUs, int option);
+
/**
* Call this method after setDataSource(). This method finds the optional
- * graphic or album art associated (embedded or external url linked) the
- * related data source.
+ * graphic or album art associated associated with the data source. If
+ * there are more than one pictures, (any) one of them is returned.
*
* @return null if no such graphic is found.
*/
- public native byte[] extractAlbumArt();
+ public byte[] getEmbeddedPicture() {
+ return getEmbeddedPicture(EMBEDDED_PICTURE_TYPE_ANY);
+ }
+
+ private native byte[] getEmbeddedPicture(int pictureType);
/**
* Call it when one is done with the object. This method releases the memory
@@ -226,38 +274,129 @@ public class MediaMetadataRetriever
}
}
- public static final int MODE_GET_METADATA_ONLY = 0x01;
- public static final int MODE_CAPTURE_FRAME_ONLY = 0x02;
+ /**
+ * Option used in method {@link #getFrameAtTime(long, int)} to get a
+ * frame at a specified location.
+ *
+ * @see #getFrameAtTime(long, int)
+ */
+ /* Do not change these option values without updating their counterparts
+ * in include/media/stagefright/MediaSource.h!
+ */
+ /**
+ * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
+ * a sync (or key) frame associated with a data source that is located
+ * right before or at the given time.
+ *
+ * @see #getFrameAtTime(long, int)
+ */
+ public static final int OPTION_PREVIOUS_SYNC = 0x00;
+ /**
+ * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
+ * a sync (or key) frame associated with a data source that is located
+ * right after or at the given time.
+ *
+ * @see #getFrameAtTime(long, int)
+ */
+ public static final int OPTION_NEXT_SYNC = 0x01;
+ /**
+ * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
+ * a sync (or key) frame associated with a data source that is located
+ * closest to (in time) or at the given time.
+ *
+ * @see #getFrameAtTime(long, int)
+ */
+ public static final int OPTION_CLOSEST_SYNC = 0x02;
+ /**
+ * This option is used with {@link #getFrameAtTime(long, int)} to retrieve
+ * a frame (not necessarily a key frame) associated with a data source that
+ * is located closest to or at the given time.
+ *
+ * @see #getFrameAtTime(long, int)
+ */
+ public static final int OPTION_CLOSEST = 0x03;
/*
- * Do not change these values without updating their counterparts
- * in include/media/mediametadataretriever.h!
+ * Do not change these metadata key values without updating their
+ * counterparts in include/media/mediametadataretriever.h!
+ */
+ /**
+ * The metadata key to retrieve the numberic string describing the
+ * order of the audio data source on its original recording.
*/
public static final int METADATA_KEY_CD_TRACK_NUMBER = 0;
+ /**
+ * The metadata key to retrieve the information about the album title
+ * of the data source.
+ */
public static final int METADATA_KEY_ALBUM = 1;
+ /**
+ * The metadata key to retrieve the information about the artist of
+ * the data source.
+ */
public static final int METADATA_KEY_ARTIST = 2;
+ /**
+ * The metadata key to retrieve the information about the author of
+ * the data source.
+ */
public static final int METADATA_KEY_AUTHOR = 3;
+ /**
+ * The metadata key to retrieve the information about the composer of
+ * the data source.
+ */
public static final int METADATA_KEY_COMPOSER = 4;
+ /**
+ * The metadata key to retrieve the date when the data source was created
+ * or modified.
+ */
public static final int METADATA_KEY_DATE = 5;
+ /**
+ * The metadata key to retrieve the content type or genre of the data
+ * source.
+ */
public static final int METADATA_KEY_GENRE = 6;
+ /**
+ * The metadata key to retrieve the data source title.
+ */
public static final int METADATA_KEY_TITLE = 7;
+ /**
+ * The metadata key to retrieve the year when the data source was created
+ * or modified.
+ */
public static final int METADATA_KEY_YEAR = 8;
+ /**
+ * The metadata key to retrieve the playback duration of the data source.
+ */
public static final int METADATA_KEY_DURATION = 9;
+ /**
+ * The metadata key to retrieve the number of tracks, such as audio, video,
+ * text, in the data source, such as a mp4 or 3gpp file.
+ */
public static final int METADATA_KEY_NUM_TRACKS = 10;
- public static final int METADATA_KEY_IS_DRM_CRIPPLED = 11;
- public static final int METADATA_KEY_CODEC = 12;
- public static final int METADATA_KEY_RATING = 13;
- public static final int METADATA_KEY_COMMENT = 14;
- public static final int METADATA_KEY_COPYRIGHT = 15;
- public static final int METADATA_KEY_BIT_RATE = 16;
- public static final int METADATA_KEY_FRAME_RATE = 17;
- public static final int METADATA_KEY_VIDEO_FORMAT = 18;
- public static final int METADATA_KEY_VIDEO_HEIGHT = 19;
- public static final int METADATA_KEY_VIDEO_WIDTH = 20;
- public static final int METADATA_KEY_WRITER = 21;
- public static final int METADATA_KEY_MIMETYPE = 22;
- public static final int METADATA_KEY_DISCNUMBER = 23;
- public static final int METADATA_KEY_ALBUMARTIST = 24;
- public static final int METADATA_KEY_COMPILATION = 25;
+ /**
+ * The metadata key to retrieve the information of the writer (such as
+ * lyricist) of the data source.
+ */
+ public static final int METADATA_KEY_WRITER = 11;
+ /**
+ * The metadata key to retrieve the mime type of the data source. Some
+ * example mime types include: "video/mp4", "audio/mp4", "audio/amr-wb",
+ * etc.
+ */
+ public static final int METADATA_KEY_MIMETYPE = 12;
+ /**
+ * The metadata key to retrieve the information about the performers or
+ * artist associated with the data source.
+ */
+ public static final int METADATA_KEY_ALBUMARTIST = 13;
+ /**
+ * The metadata key to retrieve the numberic string that describes which
+ * part of a set the audio data source comes from.
+ */
+ public static final int METADATA_KEY_DISC_NUMBER = 14;
+ /**
+ * The metadata key to retrieve the music album compilation status.
+ */
+ public static final int METADATA_KEY_COMPILATION = 15;
// Add more here...
}
diff --git a/media/java/android/media/ThumbnailUtils.java b/media/java/android/media/ThumbnailUtils.java
index 3d85e31..494b4cb 100644
--- a/media/java/android/media/ThumbnailUtils.java
+++ b/media/java/android/media/ThumbnailUtils.java
@@ -146,9 +146,8 @@ public class ThumbnailUtils {
Bitmap bitmap = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
try {
- retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
retriever.setDataSource(filePath);
- bitmap = retriever.captureFrame();
+ bitmap = retriever.getFrameAtTime(-1);
} catch (IllegalArgumentException ex) {
// Assume this is a corrupt video file
} catch (RuntimeException ex) {
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 63e9dc8..c5e58f7 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -131,33 +131,9 @@ static void android_media_MediaMetadataRetriever_setDataSourceFD(JNIEnv *env, jo
process_media_retriever_call(env, retriever->setDataSource(fd, offset, length), "java/lang/RuntimeException", "setDataSource failed");
}
-static void android_media_MediaMetadataRetriever_setMode(JNIEnv *env, jobject thiz, jint mode)
+static jobject android_media_MediaMetadataRetriever_getFrameAtTime(JNIEnv *env, jobject thiz, jlong timeUs, jint option)
{
- LOGV("setMode");
- MediaMetadataRetriever* retriever = getRetriever(env, thiz);
- if (retriever == 0) {
- jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
- return;
- }
- process_media_retriever_call(env, retriever->setMode(mode), "java/lang/RuntimeException", "setMode failed");
-}
-
-static int android_media_MediaMetadataRetriever_getMode(JNIEnv *env, jobject thiz)
-{
- LOGV("getMode");
- MediaMetadataRetriever* retriever = getRetriever(env, thiz);
- if (retriever == 0) {
- jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
- return -1; // Error
- }
- int mode = -1;
- retriever->getMode(&mode);
- return mode;
-}
-
-static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jobject thiz)
-{
- LOGV("captureFrame");
+ LOGV("getFrameAtTime: %lld us option: %d", timeUs, option);
MediaMetadataRetriever* retriever = getRetriever(env, thiz);
if (retriever == 0) {
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
@@ -166,12 +142,12 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo
// Call native method to retrieve a video frame
VideoFrame *videoFrame = NULL;
- sp<IMemory> frameMemory = retriever->captureFrame();
+ sp<IMemory> frameMemory = retriever->getFrameAtTime(timeUs, option);
if (frameMemory != 0) { // cast the shared structure to a VideoFrame object
videoFrame = static_cast<VideoFrame *>(frameMemory->pointer());
}
if (videoFrame == NULL) {
- LOGE("captureFrame: videoFrame is a NULL pointer");
+ LOGE("getFrameAtTime: videoFrame is a NULL pointer");
return NULL;
}
@@ -213,7 +189,7 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo
// Create a SkBitmap to hold the pixels
SkBitmap *bitmap = new SkBitmap();
if (bitmap == NULL) {
- LOGE("captureFrame: cannot instantiate a SkBitmap object.");
+ LOGE("getFrameAtTime: cannot instantiate a SkBitmap object.");
return NULL;
}
bitmap->setConfig(SkBitmap::kRGB_565_Config, videoFrame->mDisplayWidth, videoFrame->mDisplayHeight);
@@ -242,21 +218,26 @@ static jobject android_media_MediaMetadataRetriever_captureFrame(JNIEnv *env, jo
false); // filter
}
-static jbyteArray android_media_MediaMetadataRetriever_extractAlbumArt(JNIEnv *env, jobject thiz)
+static jbyteArray android_media_MediaMetadataRetriever_getEmbeddedPicture(
+ JNIEnv *env, jobject thiz, jint pictureType)
{
- LOGV("extractAlbumArt");
+ LOGV("getEmbeddedPicture: %d", pictureType);
MediaMetadataRetriever* retriever = getRetriever(env, thiz);
if (retriever == 0) {
jniThrowException(env, "java/lang/IllegalStateException", "No retriever available");
return NULL;
}
MediaAlbumArt* mediaAlbumArt = NULL;
+
+ // FIXME:
+ // Use pictureType to retrieve the intended embedded picture and also change
+ // the method name to getEmbeddedPicture().
sp<IMemory> albumArtMemory = retriever->extractAlbumArt();
if (albumArtMemory != 0) { // cast the shared structure to a MediaAlbumArt object
mediaAlbumArt = static_cast<MediaAlbumArt *>(albumArtMemory->pointer());
}
if (mediaAlbumArt == NULL) {
- LOGE("extractAlbumArt: Call to extractAlbumArt failed.");
+ LOGE("getEmbeddedPicture: Call to getEmbeddedPicture failed.");
return NULL;
}
@@ -264,7 +245,7 @@ static jbyteArray android_media_MediaMetadataRetriever_extractAlbumArt(JNIEnv *e
char* data = (char*) mediaAlbumArt + sizeof(MediaAlbumArt);
jbyteArray array = env->NewByteArray(len);
if (!array) { // OutOfMemoryError exception has already been thrown.
- LOGE("extractAlbumArt: OutOfMemoryError is thrown.");
+ LOGE("getEmbeddedPicture: OutOfMemoryError is thrown.");
} else {
jbyte* bytes = env->GetByteArrayElements(array, NULL);
if (bytes != NULL) {
@@ -365,11 +346,9 @@ static void android_media_MediaMetadataRetriever_native_setup(JNIEnv *env, jobje
static JNINativeMethod nativeMethods[] = {
{"setDataSource", "(Ljava/lang/String;)V", (void *)android_media_MediaMetadataRetriever_setDataSource},
{"setDataSource", "(Ljava/io/FileDescriptor;JJ)V", (void *)android_media_MediaMetadataRetriever_setDataSourceFD},
- {"setMode", "(I)V", (void *)android_media_MediaMetadataRetriever_setMode},
- {"getMode", "()I", (void *)android_media_MediaMetadataRetriever_getMode},
- {"captureFrame", "()Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_captureFrame},
+ {"_getFrameAtTime", "(JI)Landroid/graphics/Bitmap;", (void *)android_media_MediaMetadataRetriever_getFrameAtTime},
{"extractMetadata", "(I)Ljava/lang/String;", (void *)android_media_MediaMetadataRetriever_extractMetadata},
- {"extractAlbumArt", "()[B", (void *)android_media_MediaMetadataRetriever_extractAlbumArt},
+ {"getEmbeddedPicture", "(I)[B", (void *)android_media_MediaMetadataRetriever_getEmbeddedPicture},
{"release", "()V", (void *)android_media_MediaMetadataRetriever_release},
{"native_finalize", "()V", (void *)android_media_MediaMetadataRetriever_native_finalize},
{"native_setup", "()V", (void *)android_media_MediaMetadataRetriever_native_setup},
diff --git a/media/libmedia/IMediaMetadataRetriever.cpp b/media/libmedia/IMediaMetadataRetriever.cpp
index e529d25..d5298c9 100644
--- a/media/libmedia/IMediaMetadataRetriever.cpp
+++ b/media/libmedia/IMediaMetadataRetriever.cpp
@@ -81,9 +81,7 @@ enum {
DISCONNECT = IBinder::FIRST_CALL_TRANSACTION,
SET_DATA_SOURCE_URL,
SET_DATA_SOURCE_FD,
- SET_MODE,
- GET_MODE,
- CAPTURE_FRAME,
+ GET_FRAME_AT_TIME,
EXTRACT_ALBUM_ART,
EXTRACT_METADATA,
};
@@ -124,32 +122,17 @@ public:
return reply.readInt32();
}
- status_t setMode(int mode)
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
- data.writeInt32(mode);
- remote()->transact(SET_MODE, data, &reply);
- return reply.readInt32();
- }
-
- status_t getMode(int* mode) const
- {
- Parcel data, reply;
- data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
- remote()->transact(GET_MODE, data, &reply);
- *mode = reply.readInt32();
- return reply.readInt32();
- }
-
- sp<IMemory> captureFrame()
+ sp<IMemory> getFrameAtTime(int64_t timeUs, int option)
{
+ LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
Parcel data, reply;
data.writeInterfaceToken(IMediaMetadataRetriever::getInterfaceDescriptor());
+ data.writeInt64(timeUs);
+ data.writeInt32(option);
#ifndef DISABLE_GROUP_SCHEDULE_HACK
sendSchedPolicy(data);
#endif
- remote()->transact(CAPTURE_FRAME, data, &reply);
+ remote()->transact(GET_FRAME_AT_TIME, data, &reply);
status_t ret = reply.readInt32();
if (ret != NO_ERROR) {
return NULL;
@@ -216,26 +199,15 @@ status_t BnMediaMetadataRetriever::onTransact(
reply->writeInt32(setDataSource(fd, offset, length));
return NO_ERROR;
} break;
- case SET_MODE: {
- CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
- int mode = data.readInt32();
- reply->writeInt32(setMode(mode));
- return NO_ERROR;
- } break;
- case GET_MODE: {
- CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
- int mode;
- status_t status = getMode(&mode);
- reply->writeInt32(mode);
- reply->writeInt32(status);
- return NO_ERROR;
- } break;
- case CAPTURE_FRAME: {
+ case GET_FRAME_AT_TIME: {
CHECK_INTERFACE(IMediaMetadataRetriever, data, reply);
+ int64_t timeUs = data.readInt64();
+ int option = data.readInt32();
+ LOGV("getTimeAtTime: time(%lld us) and option(%d)", timeUs, option);
#ifndef DISABLE_GROUP_SCHEDULE_HACK
setSchedPolicy(data);
#endif
- sp<IMemory> bitmap = captureFrame();
+ sp<IMemory> bitmap = getFrameAtTime(timeUs, option);
if (bitmap != 0) { // Don't send NULL across the binder interface
reply->writeInt32(NO_ERROR);
reply->writeStrongBinder(bitmap->asBinder());
diff --git a/media/libmedia/mediametadataretriever.cpp b/media/libmedia/mediametadataretriever.cpp
index e2712ba..8dfcb3b 100644
--- a/media/libmedia/mediametadataretriever.cpp
+++ b/media/libmedia/mediametadataretriever.cpp
@@ -123,37 +123,15 @@ status_t MediaMetadataRetriever::setDataSource(int fd, int64_t offset, int64_t l
return mRetriever->setDataSource(fd, offset, length);
}
-status_t MediaMetadataRetriever::setMode(int mode)
+sp<IMemory> MediaMetadataRetriever::getFrameAtTime(int64_t timeUs, int option)
{
- LOGV("setMode(%d)", mode);
- Mutex::Autolock _l(mLock);
- if (mRetriever == 0) {
- LOGE("retriever is not initialized");
- return INVALID_OPERATION;
- }
- return mRetriever->setMode(mode);
-}
-
-status_t MediaMetadataRetriever::getMode(int* mode)
-{
- LOGV("getMode");
- Mutex::Autolock _l(mLock);
- if (mRetriever == 0) {
- LOGE("retriever is not initialized");
- return INVALID_OPERATION;
- }
- return mRetriever->getMode(mode);
-}
-
-sp<IMemory> MediaMetadataRetriever::captureFrame()
-{
- LOGV("captureFrame");
+ LOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
Mutex::Autolock _l(mLock);
if (mRetriever == 0) {
LOGE("retriever is not initialized");
return NULL;
}
- return mRetriever->captureFrame();
+ return mRetriever->getFrameAtTime(timeUs, option);
}
const char* MediaMetadataRetriever::extractMetadata(int keyCode)
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.cpp b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
index 39fce81..713e441 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.cpp
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.cpp
@@ -65,7 +65,6 @@ MetadataRetrieverClient::MetadataRetrieverClient(pid_t pid)
mThumbnail = NULL;
mAlbumArt = NULL;
mRetriever = NULL;
- mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
}
MetadataRetrieverClient::~MetadataRetrieverClient()
@@ -80,7 +79,7 @@ status_t MetadataRetrieverClient::dump(int fd, const Vector<String16>& args) con
char buffer[SIZE];
String8 result;
result.append(" MetadataRetrieverClient\n");
- snprintf(buffer, 255, " pid(%d) mode(%d)\n", mPid, mMode);
+ snprintf(buffer, 255, " pid(%d)\n", mPid);
result.append(buffer);
write(fd, result.string(), result.size());
write(fd, "\n", 1);
@@ -94,7 +93,6 @@ void MetadataRetrieverClient::disconnect()
mRetriever.clear();
mThumbnail.clear();
mAlbumArt.clear();
- mMode = METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL;
IPCThreadState::self()->flushCommands();
}
@@ -140,10 +138,7 @@ status_t MetadataRetrieverClient::setDataSource(const char *url)
LOGV("player type = %d", playerType);
sp<MediaMetadataRetrieverBase> p = createRetriever(playerType);
if (p == NULL) return NO_INIT;
- status_t ret = p->setMode(mMode);
- if (ret == NO_ERROR) {
- ret = p->setDataSource(url);
- }
+ status_t ret = p->setDataSource(url);
if (ret == NO_ERROR) mRetriever = p;
return ret;
}
@@ -181,55 +176,22 @@ status_t MetadataRetrieverClient::setDataSource(int fd, int64_t offset, int64_t
::close(fd);
return NO_INIT;
}
- status_t status = p->setMode(mMode);
- if (status == NO_ERROR) {
- p->setDataSource(fd, offset, length);
- }
+ status_t status = p->setDataSource(fd, offset, length);
if (status == NO_ERROR) mRetriever = p;
::close(fd);
return status;
}
-status_t MetadataRetrieverClient::setMode(int mode)
-{
- LOGV("setMode");
- Mutex::Autolock lock(mLock);
- if (mode < METADATA_MODE_NOOP ||
- mode > METADATA_MODE_FRAME_CAPTURE_AND_METADATA_RETRIEVAL) {
- LOGE("invalid mode %d", mode);
- return BAD_VALUE;
- }
- mMode = mode;
- return NO_ERROR;
-}
-
-status_t MetadataRetrieverClient::getMode(int* mode) const
-{
- LOGV("getMode");
- Mutex::Autolock lock(mLock);
-
- // TODO:
- // This may not be necessary.
- // If setDataSource() has not been called, return the cached value
- // otherwise, return the value retrieved from the retriever
- if (mRetriever == NULL) {
- *mode = mMode;
- } else {
- mRetriever->getMode(mode);
- }
- return NO_ERROR;
-}
-
-sp<IMemory> MetadataRetrieverClient::captureFrame()
+sp<IMemory> MetadataRetrieverClient::getFrameAtTime(int64_t timeUs, int option)
{
- LOGV("captureFrame");
+ LOGV("getFrameAtTime: time(%lld us) option(%d)", timeUs, option);
Mutex::Autolock lock(mLock);
mThumbnail.clear();
if (mRetriever == NULL) {
LOGE("retriever is not initialized");
return NULL;
}
- VideoFrame *frame = mRetriever->captureFrame();
+ VideoFrame *frame = mRetriever->getFrameAtTime(timeUs, option);
if (frame == NULL) {
LOGE("failed to capture a video frame");
return NULL;
diff --git a/media/libmediaplayerservice/MetadataRetrieverClient.h b/media/libmediaplayerservice/MetadataRetrieverClient.h
index 4aab94f..b834715 100644
--- a/media/libmediaplayerservice/MetadataRetrieverClient.h
+++ b/media/libmediaplayerservice/MetadataRetrieverClient.h
@@ -43,9 +43,7 @@ public:
virtual void disconnect();
virtual status_t setDataSource(const char *url);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual status_t setMode(int mode);
- virtual status_t getMode(int* mode) const;
- virtual sp<IMemory> captureFrame();
+ virtual sp<IMemory> getFrameAtTime(int64_t timeUs, int option);
virtual sp<IMemory> extractAlbumArt();
virtual const char* extractMetadata(int keyCode);
@@ -60,7 +58,6 @@ private:
mutable Mutex mLock;
sp<MediaMetadataRetrieverBase> mRetriever;
pid_t mPid;
- int mMode;
// Keep the shared memory copy of album art and capture frame (for thumbnail)
sp<IMemory> mAlbumArt;
diff --git a/media/libstagefright/StagefrightMediaScanner.cpp b/media/libstagefright/StagefrightMediaScanner.cpp
index d3aa2f6..10c6e41 100644
--- a/media/libstagefright/StagefrightMediaScanner.cpp
+++ b/media/libstagefright/StagefrightMediaScanner.cpp
@@ -130,9 +130,7 @@ status_t StagefrightMediaScanner::processFile(
return HandleMIDI(path, &client);
}
- if (mRetriever->setDataSource(path) == OK
- && mRetriever->setMode(
- METADATA_MODE_METADATA_RETRIEVAL_ONLY) == OK) {
+ if (mRetriever->setDataSource(path) == OK) {
const char *value;
if ((value = mRetriever->extractMetadata(
METADATA_KEY_MIMETYPE)) != NULL) {
@@ -181,9 +179,7 @@ char *StagefrightMediaScanner::extractAlbumArt(int fd) {
}
lseek(fd, 0, SEEK_SET);
- if (mRetriever->setDataSource(fd, 0, size) == OK
- && mRetriever->setMode(
- METADATA_MODE_FRAME_CAPTURE_ONLY) == OK) {
+ if (mRetriever->setDataSource(fd, 0, size) == OK) {
sp<IMemory> mem = mRetriever->extractAlbumArt();
if (mem != NULL) {
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index ac208cd..e8f4839 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -108,7 +108,10 @@ status_t StagefrightMetadataRetriever::setDataSource(
static VideoFrame *extractVideoFrameWithCodecFlags(
OMXClient *client,
const sp<MetaData> &trackMeta,
- const sp<MediaSource> &source, uint32_t flags) {
+ const sp<MediaSource> &source,
+ uint32_t flags,
+ int64_t frameTimeUs,
+ int seekMode) {
sp<MediaSource> decoder =
OMXCodec::Create(
client->interface(), source->getFormat(), false, source,
@@ -130,11 +133,22 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
// and spurious empty buffers.
MediaSource::ReadOptions options;
+ if (seekMode < MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC ||
+ seekMode > MediaSource::ReadOptions::SEEK_CLOSEST) {
+
+ LOGE("Unknown seek mode: %d", seekMode);
+ return NULL;
+ }
+
+ MediaSource::ReadOptions::SeekMode mode =
+ static_cast<MediaSource::ReadOptions::SeekMode>(seekMode);
+
int64_t thumbNailTime;
- if (trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
- options.setSeekTo(thumbNailTime);
+ if (frameTimeUs < 0 && trackMeta->findInt64(kKeyThumbnailTime, &thumbNailTime)) {
+ options.setSeekTo(thumbNailTime, mode);
} else {
thumbNailTime = -1;
+ options.setSeekTo(frameTimeUs, mode);
}
MediaBuffer *buffer = NULL;
@@ -226,14 +240,10 @@ static VideoFrame *extractVideoFrameWithCodecFlags(
return frame;
}
-VideoFrame *StagefrightMetadataRetriever::captureFrame() {
- LOGV("captureFrame");
-
- if (0 == (mMode & METADATA_MODE_FRAME_CAPTURE_ONLY)) {
- LOGV("captureFrame disabled by mode (0x%08x)", mMode);
+VideoFrame *StagefrightMetadataRetriever::getFrameAtTime(
+ int64_t timeUs, int option) {
- return NULL;
- }
+ LOGV("getFrameAtTime: %lld us option: %d", timeUs, option);
if (mExtractor.get() == NULL) {
LOGV("no extractor.");
@@ -270,13 +280,15 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
VideoFrame *frame =
extractVideoFrameWithCodecFlags(
- &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs);
+ &mClient, trackMeta, source, OMXCodec::kPreferSoftwareCodecs,
+ timeUs, option);
if (frame == NULL) {
LOGV("Software decoder failed to extract thumbnail, "
"trying hardware decoder.");
- frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0);
+ frame = extractVideoFrameWithCodecFlags(&mClient, trackMeta, source, 0,
+ timeUs, option);
}
return frame;
@@ -285,12 +297,6 @@ VideoFrame *StagefrightMetadataRetriever::captureFrame() {
MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
LOGV("extractAlbumArt (extractor: %s)", mExtractor.get() != NULL ? "YES" : "NO");
- if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) {
- LOGV("extractAlbumArt/metadata retrieval disabled by mode");
-
- return NULL;
- }
-
if (mExtractor == NULL) {
return NULL;
}
@@ -309,12 +315,6 @@ MediaAlbumArt *StagefrightMetadataRetriever::extractAlbumArt() {
}
const char *StagefrightMetadataRetriever::extractMetadata(int keyCode) {
- if (0 == (mMode & METADATA_MODE_METADATA_RETRIEVAL_ONLY)) {
- LOGV("extractAlbumArt/metadata retrieval disabled by mode");
-
- return NULL;
- }
-
if (mExtractor == NULL) {
return NULL;
}
diff --git a/media/libstagefright/include/StagefrightMetadataRetriever.h b/media/libstagefright/include/StagefrightMetadataRetriever.h
index b80387f..07b1ec8 100644
--- a/media/libstagefright/include/StagefrightMetadataRetriever.h
+++ b/media/libstagefright/include/StagefrightMetadataRetriever.h
@@ -35,7 +35,7 @@ struct StagefrightMetadataRetriever : public MediaMetadataRetrieverInterface {
virtual status_t setDataSource(const char *url);
virtual status_t setDataSource(int fd, int64_t offset, int64_t length);
- virtual VideoFrame *captureFrame();
+ virtual VideoFrame *getFrameAtTime(int64_t timeUs, int option);
virtual MediaAlbumArt *extractAlbumArt();
virtual const char *extractMetadata(int keyCode);
diff --git a/media/libstagefright/matroska/MatroskaExtractor.cpp b/media/libstagefright/matroska/MatroskaExtractor.cpp
index d16476d..1661130 100644
--- a/media/libstagefright/matroska/MatroskaExtractor.cpp
+++ b/media/libstagefright/matroska/MatroskaExtractor.cpp
@@ -22,13 +22,15 @@
#include "mkvparser.hpp"
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaBuffer.h>
-#include <media/stagefright/MediaDebug.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MediaSource.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
#include <utils/String8.h>
namespace android {
@@ -81,46 +83,6 @@ private:
////////////////////////////////////////////////////////////////////////////////
-#include <ctype.h>
-static void hexdump(const void *_data, size_t size) {
- const uint8_t *data = (const uint8_t *)_data;
- size_t offset = 0;
- while (offset < size) {
- printf("0x%04x ", offset);
-
- size_t n = size - offset;
- if (n > 16) {
- n = 16;
- }
-
- for (size_t i = 0; i < 16; ++i) {
- if (i == 8) {
- printf(" ");
- }
-
- if (offset + i < size) {
- printf("%02x ", data[offset + i]);
- } else {
- printf(" ");
- }
- }
-
- printf(" ");
-
- for (size_t i = 0; i < n; ++i) {
- if (isprint(data[offset + i])) {
- printf("%c", data[offset + i]);
- } else {
- printf(".");
- }
- }
-
- printf("\n");
-
- offset += 16;
- }
-}
-
struct BlockIterator {
BlockIterator(mkvparser::Segment *segment, unsigned long trackNum);
@@ -156,6 +118,9 @@ struct MatroskaSource : public MediaSource {
virtual status_t read(
MediaBuffer **buffer, const ReadOptions *options);
+protected:
+ virtual ~MatroskaSource();
+
private:
enum Type {
AVC,
@@ -167,9 +132,15 @@ private:
size_t mTrackIndex;
Type mType;
BlockIterator mBlockIter;
+ size_t mNALSizeLen; // for type AVC
+
+ List<MediaBuffer *> mPendingFrames;
status_t advance();
+ status_t readBlock();
+ void clearPendingFrames();
+
MatroskaSource(const MatroskaSource &);
MatroskaSource &operator=(const MatroskaSource &);
};
@@ -180,18 +151,35 @@ MatroskaSource::MatroskaSource(
mTrackIndex(index),
mType(OTHER),
mBlockIter(mExtractor->mSegment,
- mExtractor->mTracks.itemAt(index).mTrackNum) {
+ mExtractor->mTracks.itemAt(index).mTrackNum),
+ mNALSizeLen(0) {
+ sp<MetaData> meta = mExtractor->mTracks.itemAt(index).mMeta;
+
const char *mime;
- CHECK(mExtractor->mTracks.itemAt(index).mMeta->
- findCString(kKeyMIMEType, &mime));
+ CHECK(meta->findCString(kKeyMIMEType, &mime));
if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AVC)) {
mType = AVC;
+
+ uint32_t dummy;
+ const uint8_t *avcc;
+ size_t avccSize;
+ CHECK(meta->findData(
+ kKeyAVCC, &dummy, (const void **)&avcc, &avccSize));
+
+ CHECK_GE(avccSize, 5u);
+
+ mNALSizeLen = 1 + (avcc[4] & 3);
+ LOGV("mNALSizeLen = %d", mNALSizeLen);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) {
mType = AAC;
}
}
+MatroskaSource::~MatroskaSource() {
+ clearPendingFrames();
+}
+
status_t MatroskaSource::start(MetaData *params) {
mBlockIter.reset();
@@ -199,6 +187,8 @@ status_t MatroskaSource::start(MetaData *params) {
}
status_t MatroskaSource::stop() {
+ clearPendingFrames();
+
return OK;
}
@@ -276,66 +266,313 @@ int64_t BlockIterator::blockTimeUs() const {
////////////////////////////////////////////////////////////////////////////////
-status_t MatroskaSource::read(
- MediaBuffer **out, const ReadOptions *options) {
- *out = NULL;
+static unsigned U24_AT(const uint8_t *ptr) {
+ return ptr[0] << 16 | ptr[1] << 8 | ptr[2];
+}
- int64_t seekTimeUs;
- ReadOptions::SeekMode mode;
- if (options && options->getSeekTo(&seekTimeUs, &mode)) {
- mBlockIter.seek(seekTimeUs);
+static size_t clz(uint8_t x) {
+ size_t numLeadingZeroes = 0;
+
+ while (!(x & 0x80)) {
+ ++numLeadingZeroes;
+ x = x << 1;
}
+ return numLeadingZeroes;
+}
+
+void MatroskaSource::clearPendingFrames() {
+ while (!mPendingFrames.empty()) {
+ MediaBuffer *frame = *mPendingFrames.begin();
+ mPendingFrames.erase(mPendingFrames.begin());
+
+ frame->release();
+ frame = NULL;
+ }
+}
+
+#define BAIL(err) \
+ do { \
+ if (bigbuf) { \
+ bigbuf->release(); \
+ bigbuf = NULL; \
+ } \
+ \
+ return err; \
+ } while (0)
+
+status_t MatroskaSource::readBlock() {
+ CHECK(mPendingFrames.empty());
+
if (mBlockIter.eos()) {
return ERROR_END_OF_STREAM;
}
const mkvparser::Block *block = mBlockIter.block();
+
size_t size = block->GetSize();
int64_t timeUs = mBlockIter.blockTimeUs();
+ int32_t isSync = block->IsKey();
- MediaBuffer *buffer = new MediaBuffer(size + 2);
- buffer->meta_data()->setInt64(kKeyTime, timeUs);
- buffer->meta_data()->setInt32(kKeyIsSyncFrame, block->IsKey());
+ MediaBuffer *bigbuf = new MediaBuffer(size);
long res = block->Read(
- mExtractor->mReader, (unsigned char *)buffer->data() + 2);
+ mExtractor->mReader, (unsigned char *)bigbuf->data());
if (res != 0) {
+ bigbuf->release();
+ bigbuf = NULL;
+
return ERROR_END_OF_STREAM;
}
- buffer->set_range(2, size);
+ mBlockIter.advance();
+
+ bigbuf->meta_data()->setInt64(kKeyTime, timeUs);
+ bigbuf->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
- if (mType == AVC) {
- CHECK(size >= 2);
+ unsigned lacing = (block->Flags() >> 1) & 3;
- uint8_t *data = (uint8_t *)buffer->data();
+ if (lacing == 0) {
+ mPendingFrames.push_back(bigbuf);
+ return OK;
+ }
- unsigned NALsize = data[2] << 8 | data[3];
- CHECK_EQ(size, NALsize + 2);
+ LOGV("lacing = %u, size = %d", lacing, size);
- memcpy(data, "\x00\x00\x00\x01", 4);
- buffer->set_range(0, size + 2);
- } else if (mType == AAC) {
- // There's strange junk at the beginning...
+ const uint8_t *data = (const uint8_t *)bigbuf->data();
+ // hexdump(data, size);
- const uint8_t *data = (const uint8_t *)buffer->data() + 2;
- size_t offset = 0;
- while (offset < size && data[offset] != 0x21) {
- ++offset;
- }
- buffer->set_range(2 + offset, size - offset);
+ if (size == 0) {
+ BAIL(ERROR_MALFORMED);
}
- *out = buffer;
+ unsigned numFrames = (unsigned)data[0] + 1;
+ ++data;
+ --size;
+
+ Vector<uint64_t> frameSizes;
+
+ switch (lacing) {
+ case 1: // Xiph
+ {
+ for (size_t i = 0; i < numFrames - 1; ++i) {
+ size_t frameSize = 0;
+ uint8_t byte;
+ do {
+ if (size == 0) {
+ BAIL(ERROR_MALFORMED);
+ }
+ byte = data[0];
+ ++data;
+ --size;
+
+ frameSize += byte;
+ } while (byte == 0xff);
+
+ frameSizes.push(frameSize);
+ }
+
+ break;
+ }
+
+ case 2: // fixed-size
+ {
+ if ((size % numFrames) != 0) {
+ BAIL(ERROR_MALFORMED);
+ }
+
+ size_t frameSize = size / numFrames;
+ for (size_t i = 0; i < numFrames - 1; ++i) {
+ frameSizes.push(frameSize);
+ }
+
+ break;
+ }
+
+ case 3: // EBML
+ {
+ uint64_t lastFrameSize = 0;
+ for (size_t i = 0; i < numFrames - 1; ++i) {
+ uint8_t byte;
+
+ if (size == 0) {
+ BAIL(ERROR_MALFORMED);
+ }
+ byte = data[0];
+ ++data;
+ --size;
+
+ size_t numLeadingZeroes = clz(byte);
+
+ uint64_t frameSize = byte & ~(0x80 >> numLeadingZeroes);
+ for (size_t j = 0; j < numLeadingZeroes; ++j) {
+ if (size == 0) {
+ BAIL(ERROR_MALFORMED);
+ }
+
+ frameSize = frameSize << 8;
+ frameSize |= data[0];
+ ++data;
+ --size;
+ }
+
+ if (i == 0) {
+ frameSizes.push(frameSize);
+ } else {
+ size_t shift =
+ 7 - numLeadingZeroes + 8 * numLeadingZeroes;
+
+ int64_t delta =
+ (int64_t)frameSize - (1ll << (shift - 1)) + 1;
+
+ frameSize = lastFrameSize + delta;
+
+ frameSizes.push(frameSize);
+ }
+
+ lastFrameSize = frameSize;
+ }
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
#if 0
- hexdump((const uint8_t *)buffer->data() + buffer->range_offset(),
- buffer->range_length());
+ AString out;
+ for (size_t i = 0; i < frameSizes.size(); ++i) {
+ if (i > 0) {
+ out.append(", ");
+ }
+ out.append(StringPrintf("%llu", frameSizes.itemAt(i)));
+ }
+ LOGV("sizes = [%s]", out.c_str());
#endif
- mBlockIter.advance();
+ for (size_t i = 0; i < frameSizes.size(); ++i) {
+ uint64_t frameSize = frameSizes.itemAt(i);
+
+ if (size < frameSize) {
+ BAIL(ERROR_MALFORMED);
+ }
+
+ MediaBuffer *mbuf = new MediaBuffer(frameSize);
+ mbuf->meta_data()->setInt64(kKeyTime, timeUs);
+ mbuf->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
+ memcpy(mbuf->data(), data, frameSize);
+ mPendingFrames.push_back(mbuf);
+
+ data += frameSize;
+ size -= frameSize;
+ }
+
+ size_t offset = bigbuf->range_length() - size;
+ bigbuf->set_range(offset, size);
+
+ mPendingFrames.push_back(bigbuf);
+
+ return OK;
+}
+
+#undef BAIL
+
+status_t MatroskaSource::read(
+ MediaBuffer **out, const ReadOptions *options) {
+ *out = NULL;
+
+ int64_t seekTimeUs;
+ ReadOptions::SeekMode mode;
+ if (options && options->getSeekTo(&seekTimeUs, &mode)) {
+ clearPendingFrames();
+ mBlockIter.seek(seekTimeUs);
+ }
+
+again:
+ while (mPendingFrames.empty()) {
+ status_t err = readBlock();
+
+ if (err != OK) {
+ clearPendingFrames();
+
+ return err;
+ }
+ }
+
+ MediaBuffer *frame = *mPendingFrames.begin();
+ mPendingFrames.erase(mPendingFrames.begin());
+
+ size_t size = frame->range_length();
+
+ if (mType != AVC) {
+ *out = frame;
+
+ return OK;
+ }
+
+ if (size < mNALSizeLen) {
+ frame->release();
+ frame = NULL;
+
+ return ERROR_MALFORMED;
+ }
+
+ // In the case of AVC content, each NAL unit is prefixed by
+ // mNALSizeLen bytes of length. We want to prefix the data with
+ // a four-byte 0x00000001 startcode instead of the length prefix.
+ // mNALSizeLen ranges from 1 through 4 bytes, so add an extra
+ // 3 bytes of padding to the buffer start.
+ static const size_t kPadding = 3;
+
+ MediaBuffer *buffer = new MediaBuffer(size + kPadding);
+
+ int64_t timeUs;
+ CHECK(frame->meta_data()->findInt64(kKeyTime, &timeUs));
+ int32_t isSync;
+ CHECK(frame->meta_data()->findInt32(kKeyIsSyncFrame, &isSync));
+
+ buffer->meta_data()->setInt64(kKeyTime, timeUs);
+ buffer->meta_data()->setInt32(kKeyIsSyncFrame, isSync);
+
+ memcpy((uint8_t *)buffer->data() + kPadding,
+ (const uint8_t *)frame->data() + frame->range_offset(),
+ size);
+
+ buffer->set_range(kPadding, size);
+
+ frame->release();
+ frame = NULL;
+
+ uint8_t *data = (uint8_t *)buffer->data();
+
+ size_t NALsize;
+ switch (mNALSizeLen) {
+ case 1: NALsize = data[kPadding]; break;
+ case 2: NALsize = U16_AT(&data[kPadding]); break;
+ case 3: NALsize = U24_AT(&data[kPadding]); break;
+ case 4: NALsize = U32_AT(&data[kPadding]); break;
+ default:
+ TRESPASS();
+ }
+
+ if (size < NALsize + mNALSizeLen) {
+ buffer->release();
+ buffer = NULL;
+
+ return ERROR_MALFORMED;
+ }
+
+ if (size > NALsize + mNALSizeLen) {
+ LOGW("discarding %d bytes of data.", size - NALsize - mNALSizeLen);
+ }
+
+ // actual data starts at &data[kPadding + mNALSizeLen]
+
+ memcpy(&data[mNALSizeLen - 1], "\x00\x00\x00\x01", 4);
+ buffer->set_range(mNALSizeLen - 1, NALsize + 4);
+
+ *out = buffer;
return OK;
}
diff --git a/media/libstagefright/matroska/mkvparser.cpp b/media/libstagefright/matroska/mkvparser.cpp
index 455b1d6..7448d96 100644
--- a/media/libstagefright/matroska/mkvparser.cpp
+++ b/media/libstagefright/matroska/mkvparser.cpp
@@ -4474,6 +4474,9 @@ bool Block::IsKey() const
return ((m_flags & static_cast<unsigned char>(1 << 7)) != 0);
}
+unsigned char Block::Flags() const {
+ return m_flags;
+}
void Block::SetKey(bool bKey)
{
diff --git a/media/libstagefright/matroska/mkvparser.hpp b/media/libstagefright/matroska/mkvparser.hpp
index c46d349..f7d8948 100644
--- a/media/libstagefright/matroska/mkvparser.hpp
+++ b/media/libstagefright/matroska/mkvparser.hpp
@@ -80,6 +80,8 @@ public:
bool IsKey() const;
void SetKey(bool);
+ unsigned char Flags() const;
+
long long GetOffset() const;
long GetSize() const;
long Read(IMkvReader*, unsigned char*) const;
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
index b0d2c64..bbde516 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.cpp
@@ -18,18 +18,381 @@
#include "ARTPSource.h"
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/MediaErrors.h>
+
+#include <ctype.h>
namespace android {
-AMPEG4AudioAssembler::AMPEG4AudioAssembler(const sp<AMessage> &notify)
+static bool GetAttribute(const char *s, const char *key, AString *value) {
+ value->clear();
+
+ size_t keyLen = strlen(key);
+
+ for (;;) {
+ while (isspace(*s)) {
+ ++s;
+ }
+
+ const char *colonPos = strchr(s, ';');
+
+ size_t len =
+ (colonPos == NULL) ? strlen(s) : colonPos - s;
+
+ if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
+ value->setTo(&s[keyLen + 1], len - keyLen - 1);
+ return true;
+ }
+
+ if (colonPos == NULL) {
+ return false;
+ }
+
+ s = colonPos + 1;
+ }
+}
+
+static sp<ABuffer> decodeHex(const AString &s) {
+ if ((s.size() % 2) != 0) {
+ return NULL;
+ }
+
+ size_t outLen = s.size() / 2;
+ sp<ABuffer> buffer = new ABuffer(outLen);
+ uint8_t *out = buffer->data();
+
+ uint8_t accum = 0;
+ for (size_t i = 0; i < s.size(); ++i) {
+ char c = s.c_str()[i];
+ unsigned value;
+ if (c >= '0' && c <= '9') {
+ value = c - '0';
+ } else if (c >= 'a' && c <= 'f') {
+ value = c - 'a' + 10;
+ } else if (c >= 'A' && c <= 'F') {
+ value = c - 'A' + 10;
+ } else {
+ return NULL;
+ }
+
+ accum = (accum << 4) | value;
+
+ if (i & 1) {
+ *out++ = accum;
+
+ accum = 0;
+ }
+ }
+
+ return buffer;
+}
+
+static status_t parseAudioObjectType(
+ ABitReader *bits, unsigned *audioObjectType) {
+ *audioObjectType = bits->getBits(5);
+ if ((*audioObjectType) == 31) {
+ *audioObjectType = 32 + bits->getBits(6);
+ }
+
+ return OK;
+}
+
+static status_t parseGASpecificConfig(
+ ABitReader *bits,
+ unsigned audioObjectType, unsigned channelConfiguration) {
+ unsigned frameLengthFlag = bits->getBits(1);
+ unsigned dependsOnCoreCoder = bits->getBits(1);
+ if (dependsOnCoreCoder) {
+ /* unsigned coreCoderDelay = */bits->getBits(1);
+ }
+ unsigned extensionFlag = bits->getBits(1);
+
+ if (!channelConfiguration) {
+ // program_config_element
+ return ERROR_UNSUPPORTED; // XXX to be implemented
+ }
+
+ if (audioObjectType == 6 || audioObjectType == 20) {
+ /* unsigned layerNr = */bits->getBits(3);
+ }
+
+ if (extensionFlag) {
+ if (audioObjectType == 22) {
+ /* unsigned numOfSubFrame = */bits->getBits(5);
+ /* unsigned layerLength = */bits->getBits(11);
+ } else if (audioObjectType == 17 || audioObjectType == 19
+ || audioObjectType == 20 || audioObjectType == 23) {
+ /* unsigned aacSectionDataResilienceFlag = */bits->getBits(1);
+ /* unsigned aacScalefactorDataResilienceFlag = */bits->getBits(1);
+ /* unsigned aacSpectralDataResilienceFlag = */bits->getBits(1);
+ }
+
+ unsigned extensionFlag3 = bits->getBits(1);
+ CHECK_EQ(extensionFlag3, 0u); // TBD in version 3
+ }
+
+ return OK;
+}
+
+static status_t parseAudioSpecificConfig(ABitReader *bits) {
+ unsigned audioObjectType;
+ CHECK_EQ(parseAudioObjectType(bits, &audioObjectType), (status_t)OK);
+
+ unsigned samplingFreqIndex = bits->getBits(4);
+ if (samplingFreqIndex == 0x0f) {
+ /* unsigned samplingFrequency = */bits->getBits(24);
+ }
+
+ unsigned channelConfiguration = bits->getBits(4);
+
+ unsigned extensionAudioObjectType = 0;
+ unsigned sbrPresent = 0;
+
+ if (audioObjectType == 5) {
+ extensionAudioObjectType = audioObjectType;
+ sbrPresent = 1;
+ unsigned extensionSamplingFreqIndex = bits->getBits(4);
+ if (extensionSamplingFreqIndex == 0x0f) {
+ /* unsigned extensionSamplingFrequency = */bits->getBits(24);
+ }
+ CHECK_EQ(parseAudioObjectType(bits, &audioObjectType), (status_t)OK);
+ }
+
+ CHECK((audioObjectType >= 1 && audioObjectType <= 4)
+ || (audioObjectType >= 6 && audioObjectType <= 7)
+ || audioObjectType == 17
+ || (audioObjectType >= 19 && audioObjectType <= 23));
+
+ CHECK_EQ(parseGASpecificConfig(
+ bits, audioObjectType, channelConfiguration), (status_t)OK);
+
+ if (audioObjectType == 17
+ || (audioObjectType >= 19 && audioObjectType <= 27)) {
+ unsigned epConfig = bits->getBits(2);
+ if (epConfig == 2 || epConfig == 3) {
+ // ErrorProtectionSpecificConfig
+ return ERROR_UNSUPPORTED; // XXX to be implemented
+
+ if (epConfig == 3) {
+ unsigned directMapping = bits->getBits(1);
+ CHECK_EQ(directMapping, 1u);
+ }
+ }
+ }
+
+#if 0
+ // This is not supported here as the upper layers did not explicitly
+ // signal the length of AudioSpecificConfig.
+
+ if (extensionAudioObjectType != 5 && bits->numBitsLeft() >= 16) {
+ unsigned syncExtensionType = bits->getBits(11);
+ if (syncExtensionType == 0x2b7) {
+ CHECK_EQ(parseAudioObjectType(bits, &extensionAudioObjectType),
+ (status_t)OK);
+
+ sbrPresent = bits->getBits(1);
+
+ if (sbrPresent == 1) {
+ unsigned extensionSamplingFreqIndex = bits->getBits(4);
+ if (extensionSamplingFreqIndex == 0x0f) {
+ /* unsigned extensionSamplingFrequency = */bits->getBits(24);
+ }
+ }
+ }
+ }
+#endif
+
+ return OK;
+}
+
+static status_t parseStreamMuxConfig(
+ ABitReader *bits,
+ unsigned *numSubFrames,
+ unsigned *frameLengthType,
+ bool *otherDataPresent,
+ unsigned *otherDataLenBits) {
+ unsigned audioMuxVersion = bits->getBits(1);
+
+ unsigned audioMuxVersionA = 0;
+ if (audioMuxVersion == 1) {
+ audioMuxVersionA = bits->getBits(1);
+ }
+
+ CHECK_EQ(audioMuxVersionA, 0u); // otherwise future spec
+
+ if (audioMuxVersion != 0) {
+ return ERROR_UNSUPPORTED; // XXX to be implemented;
+ }
+ CHECK_EQ(audioMuxVersion, 0u); // XXX to be implemented
+
+ unsigned allStreamsSameTimeFraming = bits->getBits(1);
+ CHECK_EQ(allStreamsSameTimeFraming, 1u); // There's only one stream.
+
+ *numSubFrames = bits->getBits(6);
+ unsigned numProgram = bits->getBits(4);
+ CHECK_EQ(numProgram, 0u); // disabled in RTP LATM
+
+ unsigned numLayer = bits->getBits(3);
+ CHECK_EQ(numLayer, 0u); // disabled in RTP LATM
+
+ if (audioMuxVersion == 0) {
+ // AudioSpecificConfig
+ CHECK_EQ(parseAudioSpecificConfig(bits), (status_t)OK);
+ } else {
+ TRESPASS(); // XXX to be implemented
+ }
+
+ *frameLengthType = bits->getBits(3);
+ switch (*frameLengthType) {
+ case 0:
+ {
+ /* unsigned bufferFullness = */bits->getBits(8);
+
+ // The "coreFrameOffset" does not apply since there's only
+ // a single layer.
+ break;
+ }
+
+ case 1:
+ {
+ /* unsigned frameLength = */bits->getBits(9);
+ break;
+ }
+
+ case 3:
+ case 4:
+ case 5:
+ {
+ /* unsigned CELPframeLengthTableIndex = */bits->getBits(6);
+ break;
+ }
+
+ case 6:
+ case 7:
+ {
+ /* unsigned HVXCframeLengthTableIndex = */bits->getBits(1);
+ break;
+ }
+
+ default:
+ break;
+ }
+
+ *otherDataPresent = bits->getBits(1);
+ *otherDataLenBits = 0;
+ if (*otherDataPresent) {
+ if (audioMuxVersion == 1) {
+ TRESPASS(); // XXX to be implemented
+ } else {
+ *otherDataLenBits = 0;
+
+ unsigned otherDataLenEsc;
+ do {
+ (*otherDataLenBits) <<= 8;
+ otherDataLenEsc = bits->getBits(1);
+ unsigned otherDataLenTmp = bits->getBits(8);
+ (*otherDataLenBits) += otherDataLenTmp;
+ } while (otherDataLenEsc);
+ }
+ }
+
+ unsigned crcCheckPresent = bits->getBits(1);
+ if (crcCheckPresent) {
+ /* unsigned crcCheckSum = */bits->getBits(8);
+ }
+
+ return OK;
+}
+
+sp<ABuffer> AMPEG4AudioAssembler::removeLATMFraming(const sp<ABuffer> &buffer) {
+ CHECK(!mMuxConfigPresent); // XXX to be implemented
+
+ sp<ABuffer> out = new ABuffer(buffer->size());
+ out->setRange(0, 0);
+
+ size_t offset = 0;
+ uint8_t *ptr = buffer->data();
+
+ for (size_t i = 0; i <= mNumSubFrames; ++i) {
+ // parse PayloadLengthInfo
+
+ unsigned payloadLength = 0;
+
+ switch (mFrameLengthType) {
+ case 0:
+ {
+ unsigned muxSlotLengthBytes = 0;
+ unsigned tmp;
+ do {
+ CHECK_LT(offset, buffer->size());
+ tmp = ptr[offset++];
+ muxSlotLengthBytes += tmp;
+ } while (tmp == 0xff);
+
+ payloadLength = muxSlotLengthBytes;
+ break;
+ }
+
+ default:
+ TRESPASS(); // XXX to be implemented
+ break;
+ }
+
+ CHECK_LE(offset + payloadLength, buffer->size());
+
+ memcpy(out->data() + out->size(), &ptr[offset], payloadLength);
+ out->setRange(0, out->size() + payloadLength);
+
+ offset += payloadLength;
+
+ if (mOtherDataPresent) {
+ // We want to stay byte-aligned.
+
+ CHECK((mOtherDataLenBits % 8) == 0);
+ CHECK_LE(offset + (mOtherDataLenBits / 8), buffer->size());
+ offset += mOtherDataLenBits / 8;
+ }
+ }
+
+ CHECK_EQ(offset, buffer->size());
+
+ return out;
+}
+
+AMPEG4AudioAssembler::AMPEG4AudioAssembler(
+ const sp<AMessage> &notify, const AString &params)
: mNotifyMsg(notify),
+ mMuxConfigPresent(false),
mAccessUnitRTPTime(0),
mNextExpectedSeqNoValid(false),
mNextExpectedSeqNo(0),
mAccessUnitDamaged(false) {
+ AString val;
+ if (!GetAttribute(params.c_str(), "cpresent", &val)) {
+ mMuxConfigPresent = true;
+ } else if (val == "0") {
+ mMuxConfigPresent = false;
+ } else {
+ CHECK(val == "1");
+ mMuxConfigPresent = true;
+ }
+
+ CHECK(GetAttribute(params.c_str(), "config", &val));
+
+ sp<ABuffer> config = decodeHex(val);
+ CHECK(config != NULL);
+
+ ABitReader bits(config->data(), config->size());
+ status_t err = parseStreamMuxConfig(
+ &bits, &mNumSubFrames, &mFrameLengthType,
+ &mOtherDataPresent, &mOtherDataLenBits);
+
+ CHECK_EQ(err, (status_t)NO_ERROR);
}
AMPEG4AudioAssembler::~AMPEG4AudioAssembler() {
@@ -108,13 +471,7 @@ void AMPEG4AudioAssembler::submitAccessUnit() {
while (it != mPackets.end()) {
const sp<ABuffer> &unit = *it;
- size_t n = 0;
- while (unit->data()[n] == 0xff) {
- ++n;
- }
- ++n;
-
- totalSize += unit->size() - n;
+ totalSize += unit->size();
++it;
}
@@ -124,20 +481,13 @@ void AMPEG4AudioAssembler::submitAccessUnit() {
while (it != mPackets.end()) {
const sp<ABuffer> &unit = *it;
- size_t n = 0;
- while (unit->data()[n] == 0xff) {
- ++n;
- }
- ++n;
-
memcpy((uint8_t *)accessUnit->data() + offset,
- unit->data() + n, unit->size() - n);
-
- offset += unit->size() - n;
+ unit->data(), unit->size());
++it;
}
+ accessUnit = removeLATMFraming(accessUnit);
CopyTimes(accessUnit, *mPackets.begin());
#if 0
diff --git a/media/libstagefright/rtsp/AMPEG4AudioAssembler.h b/media/libstagefright/rtsp/AMPEG4AudioAssembler.h
index bf9f204..9cef94c 100644
--- a/media/libstagefright/rtsp/AMPEG4AudioAssembler.h
+++ b/media/libstagefright/rtsp/AMPEG4AudioAssembler.h
@@ -27,9 +27,11 @@
namespace android {
struct AMessage;
+struct AString;
struct AMPEG4AudioAssembler : public ARTPAssembler {
- AMPEG4AudioAssembler(const sp<AMessage> &notify);
+ AMPEG4AudioAssembler(
+ const sp<AMessage> &notify, const AString &params);
protected:
virtual ~AMPEG4AudioAssembler();
@@ -40,6 +42,13 @@ protected:
private:
sp<AMessage> mNotifyMsg;
+
+ bool mMuxConfigPresent;
+ unsigned mNumSubFrames;
+ unsigned mFrameLengthType;
+ bool mOtherDataPresent;
+ unsigned mOtherDataLenBits;
+
uint32_t mAccessUnitRTPTime;
bool mNextExpectedSeqNoValid;
uint32_t mNextExpectedSeqNo;
@@ -49,6 +58,8 @@ private:
AssemblyStatus addPacket(const sp<ARTPSource> &source);
void submitAccessUnit();
+ sp<ABuffer> removeLATMFraming(const sp<ABuffer> &buffer);
+
DISALLOW_EVIL_CONSTRUCTORS(AMPEG4AudioAssembler);
};
diff --git a/media/libstagefright/rtsp/ARTPSource.cpp b/media/libstagefright/rtsp/ARTPSource.cpp
index 2518264..5aae4e7 100644
--- a/media/libstagefright/rtsp/ARTPSource.cpp
+++ b/media/libstagefright/rtsp/ARTPSource.cpp
@@ -57,7 +57,7 @@ ARTPSource::ARTPSource(
mAssembler = new AAVCAssembler(notify);
mIssueFIRRequests = true;
} else if (!strncmp(desc.c_str(), "MP4A-LATM/", 10)) {
- mAssembler = new AMPEG4AudioAssembler(notify);
+ mAssembler = new AMPEG4AudioAssembler(notify, params);
} else if (!strncmp(desc.c_str(), "H263-1998/", 10)
|| !strncmp(desc.c_str(), "H263-2000/", 10)) {
mAssembler = new AH263Assembler(notify);
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 5ec03b2..e936923 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -23,11 +23,13 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/MediaErrors.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <netdb.h>
+#include <openssl/md5.h>
#include <sys/socket.h>
namespace android {
@@ -37,6 +39,7 @@ const int64_t ARTSPConnection::kSelectTimeoutUs = 1000ll;
ARTSPConnection::ARTSPConnection()
: mState(DISCONNECTED),
+ mAuthType(NONE),
mSocket(-1),
mConnectionID(0),
mNextCSeq(0),
@@ -114,10 +117,13 @@ void ARTSPConnection::onMessageReceived(const sp<AMessage> &msg) {
// static
bool ARTSPConnection::ParseURL(
- const char *url, AString *host, unsigned *port, AString *path) {
+ const char *url, AString *host, unsigned *port, AString *path,
+ AString *user, AString *pass) {
host->clear();
*port = 0;
path->clear();
+ user->clear();
+ pass->clear();
if (strncasecmp("rtsp://", url, 7)) {
return false;
@@ -133,7 +139,25 @@ bool ARTSPConnection::ParseURL(
path->setTo(slashPos);
}
- char *colonPos = strchr(host->c_str(), ':');
+ ssize_t atPos = host->find("@");
+
+ if (atPos >= 0) {
+ // Split of user:pass@ from hostname.
+
+ AString userPass(*host, 0, atPos);
+ host->erase(0, atPos + 1);
+
+ ssize_t colonPos = userPass.find(":");
+
+ if (colonPos < 0) {
+ *user = userPass;
+ } else {
+ user->setTo(userPass, 0, colonPos);
+ pass->setTo(userPass, colonPos + 1, userPass.size() - colonPos - 1);
+ }
+ }
+
+ const char *colonPos = strchr(host->c_str(), ':');
if (colonPos != NULL) {
unsigned long x;
@@ -187,7 +211,12 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
AString host, path;
unsigned port;
- if (!ParseURL(url.c_str(), &host, &port, &path)) {
+ if (!ParseURL(url.c_str(), &host, &port, &path, &mUser, &mPass)
+ || (mUser.size() > 0 && mPass.size() == 0)) {
+ // If we have a user name but no password we have to give up
+ // right here, since we currently have no way of asking the user
+ // for this information.
+
LOGE("Malformed rtsp url %s", url.c_str());
reply->setInt32("result", ERROR_MALFORMED);
@@ -197,6 +226,10 @@ void ARTSPConnection::onConnect(const sp<AMessage> &msg) {
return;
}
+ if (mUser.size() > 0) {
+ LOGV("user = '%s', pass = '%s'", mUser.c_str(), mPass.c_str());
+ }
+
struct hostent *ent = gethostbyname(host.c_str());
if (ent == NULL) {
LOGE("Unknown host %s", host.c_str());
@@ -262,6 +295,11 @@ void ARTSPConnection::onDisconnect(const sp<AMessage> &msg) {
reply->setInt32("result", OK);
mState = DISCONNECTED;
+ mUser.clear();
+ mPass.clear();
+ mAuthType = NONE;
+ mNonce.clear();
+
reply->post();
}
@@ -335,6 +373,12 @@ void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) {
AString request;
CHECK(msg->findString("request", &request));
+ // Just in case we need to re-issue the request with proper authentication
+ // later, stash it away.
+ reply->setString("original-request", request.c_str(), request.size());
+
+ addAuthentication(&request);
+
// Find the boundary between headers and the body.
ssize_t i = request.find("\r\n\r\n");
CHECK_GE(i, 0);
@@ -347,7 +391,7 @@ void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) {
request.insert(cseqHeader, i + 2);
- LOGV("%s", request.c_str());
+ LOGV("request: '%s'", request.c_str());
size_t numBytesSent = 0;
while (numBytesSent < request.size()) {
@@ -612,6 +656,30 @@ bool ARTSPConnection::receiveRTSPReponse() {
}
}
+ if (response->mStatusCode == 401) {
+ if (mAuthType == NONE && mUser.size() > 0
+ && parseAuthMethod(response)) {
+ ssize_t i;
+ CHECK_EQ((status_t)OK, findPendingRequest(response, &i));
+ CHECK_GE(i, 0);
+
+ sp<AMessage> reply = mPendingRequests.valueAt(i);
+ mPendingRequests.removeItemsAt(i);
+
+ AString request;
+ CHECK(reply->findString("original-request", &request));
+
+ sp<AMessage> msg = new AMessage(kWhatSendRequest, id());
+ msg->setMessage("reply", reply);
+ msg->setString("request", request.c_str(), request.size());
+
+ LOGI("re-sending request with authentication headers...");
+ onSendRequest(msg);
+
+ return true;
+ }
+ }
+
return notifyResponseListener(response);
}
@@ -628,26 +696,47 @@ bool ARTSPConnection::ParseSingleUnsignedLong(
return true;
}
-bool ARTSPConnection::notifyResponseListener(
- const sp<ARTSPResponse> &response) {
+status_t ARTSPConnection::findPendingRequest(
+ const sp<ARTSPResponse> &response, ssize_t *index) const {
+ *index = 0;
+
ssize_t i = response->mHeaders.indexOfKey("cseq");
if (i < 0) {
- return true;
+ // This is an unsolicited server->client message.
+ return OK;
}
AString value = response->mHeaders.valueAt(i);
unsigned long cseq;
if (!ParseSingleUnsignedLong(value.c_str(), &cseq)) {
- return false;
+ return ERROR_MALFORMED;
}
i = mPendingRequests.indexOfKey(cseq);
if (i < 0) {
- // Unsolicited response?
- TRESPASS();
+ return -ENOENT;
+ }
+
+ *index = i;
+
+ return OK;
+}
+
+bool ARTSPConnection::notifyResponseListener(
+ const sp<ARTSPResponse> &response) {
+ ssize_t i;
+ status_t err = findPendingRequest(response, &i);
+
+ if (err == OK && i < 0) {
+ // An unsolicited server response is not a problem.
+ return true;
+ }
+
+ if (err != OK) {
+ return false;
}
sp<AMessage> reply = mPendingRequests.valueAt(i);
@@ -660,4 +749,160 @@ bool ARTSPConnection::notifyResponseListener(
return true;
}
+bool ARTSPConnection::parseAuthMethod(const sp<ARTSPResponse> &response) {
+ ssize_t i = response->mHeaders.indexOfKey("www-authenticate");
+
+ if (i < 0) {
+ return false;
+ }
+
+ AString value = response->mHeaders.valueAt(i);
+
+ if (!strncmp(value.c_str(), "Basic", 5)) {
+ mAuthType = BASIC;
+ } else {
+#if !defined(HAVE_ANDROID_OS)
+ // We don't have access to the MD5 implementation on the simulator,
+ // so we won't support digest authentication.
+ return false;
+#endif
+
+ CHECK(!strncmp(value.c_str(), "Digest", 6));
+ mAuthType = DIGEST;
+
+ i = value.find("nonce=");
+ CHECK_GE(i, 0);
+ CHECK_EQ(value.c_str()[i + 6], '\"');
+ ssize_t j = value.find("\"", i + 7);
+ CHECK_GE(j, 0);
+
+ mNonce.setTo(value, i + 7, j - i - 7);
+ }
+
+ return true;
+}
+
+#if defined(HAVE_ANDROID_OS)
+static void H(const AString &s, AString *out) {
+ out->clear();
+
+ MD5_CTX m;
+ MD5_Init(&m);
+ MD5_Update(&m, s.c_str(), s.size());
+
+ uint8_t key[16];
+ MD5_Final(key, &m);
+
+ for (size_t i = 0; i < 16; ++i) {
+ char nibble = key[i] >> 4;
+ if (nibble <= 9) {
+ nibble += '0';
+ } else {
+ nibble += 'a' - 10;
+ }
+ out->append(&nibble, 1);
+
+ nibble = key[i] & 0x0f;
+ if (nibble <= 9) {
+ nibble += '0';
+ } else {
+ nibble += 'a' - 10;
+ }
+ out->append(&nibble, 1);
+ }
+}
+#endif
+
+static void GetMethodAndURL(
+ const AString &request, AString *method, AString *url) {
+ ssize_t space1 = request.find(" ");
+ CHECK_GE(space1, 0);
+
+ ssize_t space2 = request.find(" ", space1 + 1);
+ CHECK_GE(space2, 0);
+
+ method->setTo(request, 0, space1);
+ url->setTo(request, space1 + 1, space2 - space1);
+}
+
+void ARTSPConnection::addAuthentication(AString *request) {
+ if (mAuthType == NONE) {
+ return;
+ }
+
+ // Find the boundary between headers and the body.
+ ssize_t i = request->find("\r\n\r\n");
+ CHECK_GE(i, 0);
+
+ if (mAuthType == BASIC) {
+ AString tmp;
+ tmp.append(mUser);
+ tmp.append(":");
+ tmp.append(mPass);
+
+ AString out;
+ encodeBase64(tmp.c_str(), tmp.size(), &out);
+
+ AString fragment;
+ fragment.append("Authorization: Basic ");
+ fragment.append(out);
+ fragment.append("\r\n");
+
+ request->insert(fragment, i + 2);
+
+ return;
+ }
+
+#if defined(HAVE_ANDROID_OS)
+ CHECK_EQ((int)mAuthType, (int)DIGEST);
+
+ AString method, url;
+ GetMethodAndURL(*request, &method, &url);
+
+ AString A1;
+ A1.append(mUser);
+ A1.append(":");
+ A1.append("Streaming Server");
+ A1.append(":");
+ A1.append(mPass);
+
+ AString A2;
+ A2.append(method);
+ A2.append(":");
+ A2.append(url);
+
+ AString HA1, HA2;
+ H(A1, &HA1);
+ H(A2, &HA2);
+
+ AString tmp;
+ tmp.append(HA1);
+ tmp.append(":");
+ tmp.append(mNonce);
+ tmp.append(":");
+ tmp.append(HA2);
+
+ AString digest;
+ H(tmp, &digest);
+
+ AString fragment;
+ fragment.append("Authorization: Digest ");
+ fragment.append("nonce=\"");
+ fragment.append(mNonce);
+ fragment.append("\", ");
+ fragment.append("username=\"");
+ fragment.append(mUser);
+ fragment.append("\", ");
+ fragment.append("uri=\"");
+ fragment.append(url);
+ fragment.append("\", ");
+ fragment.append("response=\"");
+ fragment.append(digest);
+ fragment.append("\"");
+ fragment.append("\r\n");
+
+ request->insert(fragment, i + 2);
+#endif
+}
+
} // namespace android
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 96e0d5b..19be2a6 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -42,6 +42,10 @@ struct ARTSPConnection : public AHandler {
void observeBinaryData(const sp<AMessage> &reply);
+ static bool ParseURL(
+ const char *url, AString *host, unsigned *port, AString *path,
+ AString *user, AString *pass);
+
protected:
virtual ~ARTSPConnection();
virtual void onMessageReceived(const sp<AMessage> &msg);
@@ -62,9 +66,18 @@ private:
kWhatObserveBinaryData = 'obin',
};
+ enum AuthType {
+ NONE,
+ BASIC,
+ DIGEST
+ };
+
static const int64_t kSelectTimeoutUs;
State mState;
+ AString mUser, mPass;
+ AuthType mAuthType;
+ AString mNonce;
int mSocket;
int32_t mConnectionID;
int32_t mNextCSeq;
@@ -90,8 +103,11 @@ private:
sp<ABuffer> receiveBinaryData();
bool notifyResponseListener(const sp<ARTSPResponse> &response);
- static bool ParseURL(
- const char *url, AString *host, unsigned *port, AString *path);
+ bool parseAuthMethod(const sp<ARTSPResponse> &response);
+ void addAuthentication(AString *request);
+
+ status_t findPendingRequest(
+ const sp<ARTSPResponse> &response, ssize_t *index) const;
static bool ParseSingleUnsignedLong(
const char *from, unsigned long *x);
diff --git a/media/libstagefright/rtsp/ASessionDescription.cpp b/media/libstagefright/rtsp/ASessionDescription.cpp
index 0db3595..0d0234b 100644
--- a/media/libstagefright/rtsp/ASessionDescription.cpp
+++ b/media/libstagefright/rtsp/ASessionDescription.cpp
@@ -53,21 +53,30 @@ bool ASessionDescription::parse(const void *data, size_t size) {
mFormats.push(AString("[root]"));
AString desc((const char *)data, size);
- LOGI("%s", desc.c_str());
size_t i = 0;
for (;;) {
- ssize_t eolPos = desc.find("\r\n", i);
+ ssize_t eolPos = desc.find("\n", i);
+
if (eolPos < 0) {
break;
}
- AString line(desc, i, eolPos - i);
+ AString line;
+ if ((size_t)eolPos > i && desc.c_str()[eolPos - 1] == '\r') {
+ // We accept both '\n' and '\r\n' line endings, if it's
+ // the latter, strip the '\r' as well.
+ line.setTo(desc, i, eolPos - i - 1);
+ } else {
+ line.setTo(desc, i, eolPos - i);
+ }
if (line.size() < 2 || line.c_str()[1] != '=') {
return false;
}
+ LOGI("%s", line.c_str());
+
switch (line.c_str()[0]) {
case 'v':
{
@@ -141,7 +150,7 @@ bool ASessionDescription::parse(const void *data, size_t size) {
}
}
- i = eolPos + 2;
+ i = eolPos + 1;
}
return true;
@@ -245,7 +254,7 @@ bool ASessionDescription::getDurationUs(int64_t *durationUs) const {
return false;
}
- if (value == "npt=now-") {
+ if (value == "npt=now-" || value == "npt=0-") {
return false;
}
@@ -256,15 +265,17 @@ bool ASessionDescription::getDurationUs(int64_t *durationUs) const {
const char *s = value.c_str() + 4;
char *end;
double from = strtod(s, &end);
- CHECK_GT(end, s);
- CHECK_EQ(*end, '-');
+
+ if (end == s || *end != '-') {
+ return false;
+ }
s = end + 1;
double to = strtod(s, &end);
- CHECK_GT(end, s);
- CHECK_EQ(*end, '\0');
- CHECK_GE(to, from);
+ if (end == s || *end != '\0' || to < from) {
+ return false;
+ }
*durationUs = (int64_t)((to - from) * 1E6);
diff --git a/media/libstagefright/rtsp/Android.mk b/media/libstagefright/rtsp/Android.mk
index 081ae32..0bbadc1 100644
--- a/media/libstagefright/rtsp/Android.mk
+++ b/media/libstagefright/rtsp/Android.mk
@@ -23,6 +23,7 @@ LOCAL_C_INCLUDES:= \
$(JNI_H_INCLUDE) \
$(TOP)/frameworks/base/include/media/stagefright/openmax \
$(TOP)/frameworks/base/media/libstagefright/include \
+ $(TOP)/external/openssl/include
LOCAL_MODULE:= libstagefright_rtsp
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 1bc9925..8f8e10a 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -96,6 +96,7 @@ struct MyHandler : public AHandler {
mNetLooper(new ALooper),
mConn(new ARTSPConnection),
mRTPConn(new ARTPConnection),
+ mOriginalSessionURL(url),
mSessionURL(url),
mSetupTracksSuccessful(false),
mSeekPending(false),
@@ -113,6 +114,23 @@ struct MyHandler : public AHandler {
mNetLooper->start(false /* runOnCallingThread */,
false /* canCallJava */,
PRIORITY_HIGHEST);
+
+ // Strip any authentication info from the session url, we don't
+ // want to transmit user/pass in cleartext.
+ AString host, path, user, pass;
+ unsigned port;
+ if (ARTSPConnection::ParseURL(
+ mSessionURL.c_str(), &host, &port, &path, &user, &pass)
+ && user.size() > 0) {
+ mSessionURL.clear();
+ mSessionURL.append("rtsp://");
+ mSessionURL.append(host);
+ mSessionURL.append(":");
+ mSessionURL.append(StringPrintf("%u", port));
+ mSessionURL.append(path);
+
+ LOGI("rewritten session url: '%s'", mSessionURL.c_str());
+ }
}
void connect(const sp<AMessage> &doneMsg) {
@@ -126,7 +144,7 @@ struct MyHandler : public AHandler {
mConn->observeBinaryData(notify);
sp<AMessage> reply = new AMessage('conn', id());
- mConn->connect(mSessionURL.c_str(), reply);
+ mConn->connect(mOriginalSessionURL.c_str(), reply);
}
void disconnect(const sp<AMessage> &doneMsg) {
@@ -312,7 +330,7 @@ struct MyHandler : public AHandler {
int32_t reconnect;
if (msg->findInt32("reconnect", &reconnect) && reconnect) {
sp<AMessage> reply = new AMessage('conn', id());
- mConn->connect(mSessionURL.c_str(), reply);
+ mConn->connect(mOriginalSessionURL.c_str(), reply);
} else {
(new AMessage('quit', id()))->post();
}
@@ -922,7 +940,7 @@ struct MyHandler : public AHandler {
CHECK(GetAttribute(range.c_str(), "npt", &val));
float npt1, npt2;
- if (val == "now-") {
+ if (val == "now-" || val == "0-") {
// This is a live stream and therefore not seekable.
return;
} else {
@@ -992,6 +1010,7 @@ private:
sp<ARTSPConnection> mConn;
sp<ARTPConnection> mRTPConn;
sp<ASessionDescription> mSessionDesc;
+ AString mOriginalSessionURL; // This one still has user:pass@
AString mSessionURL;
AString mBaseURL;
AString mSessionID;
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
index 0c0974c..2eea206 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/CodecTest.java
@@ -532,7 +532,7 @@ public class CodecTest {
e.printStackTrace();
return false;
}
- Bitmap outThumbnail = mMediaMetadataRetriever.captureFrame();
+ Bitmap outThumbnail = mMediaMetadataRetriever.getFrameAtTime(-1);
//Verify the thumbnail
Bitmap goldenBitmap = mBitmapFactory.decodeFile(goldenPath);
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
index 95dbb97..6ded74d 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/functional/MediaMetadataTest.java
@@ -202,7 +202,6 @@ public class MediaMetadataTest extends AndroidTestCase {
}
String value = null;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
try {
retriever.setDataSource(meta_data_file[fileIndex][0]);
} catch(Exception e) {
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
index 7174e2b..dec21d7 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaMetadataRetrieverTest.java
@@ -36,13 +36,12 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
// Test album art extraction.
@MediumTest
- public static void testAlbumArt() throws Exception {
- Log.v(TAG, "testAlbumArt starts.");
+ public static void testGetEmbeddedPicture() throws Exception {
+ Log.v(TAG, "testGetEmbeddedPicture starts.");
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
boolean supportWMA = MediaProfileReader.getWMAEnable();
boolean hasFailed = false;
boolean supportWMV = MediaProfileReader.getWMVEnable();
- retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
for (int i = 0, n = MediaNames.ALBUMART_TEST_FILES.length; i < n; ++i) {
try {
Log.v(TAG, "File " + i + ": " + MediaNames.ALBUMART_TEST_FILES[i]);
@@ -53,13 +52,13 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
continue;
}
retriever.setDataSource(MediaNames.ALBUMART_TEST_FILES[i]);
- byte[] albumArt = retriever.extractAlbumArt();
+ byte[] albumArt = retriever.getEmbeddedPicture();
// TODO:
// A better test would be to compare the retrieved album art with the
// known result.
if (albumArt == null) { // Do we have expect in JUnit?
- Log.e(TAG, "Fails to extract album art for " + MediaNames.ALBUMART_TEST_FILES[i]);
+ Log.e(TAG, "Fails to get embedded picture for " + MediaNames.ALBUMART_TEST_FILES[i]);
hasFailed = true;
}
} catch(Exception e) {
@@ -69,7 +68,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
Thread.yield(); // Don't be evil
}
retriever.release();
- Log.v(TAG, "testAlbumArt completes.");
+ Log.v(TAG, "testGetEmbeddedPicture completes.");
assertTrue(!hasFailed);
}
@@ -92,7 +91,7 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
continue;
}
retriever.setDataSource(MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i]);
- Bitmap bitmap = retriever.captureFrame();
+ Bitmap bitmap = retriever.getFrameAtTime(-1);
assertTrue(bitmap != null);
try {
java.io.OutputStream stream = new FileOutputStream(MediaNames.THUMBNAIL_CAPTURE_TEST_FILES[i] + ".jpg");
@@ -120,7 +119,6 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
boolean supportWMV = MediaProfileReader.getWMVEnable();
boolean hasFailed = false;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
for(int i = 0, n = MediaNames.METADATA_RETRIEVAL_TEST_FILES.length; i < n; ++i) {
try {
Log.v(TAG, "File " + i + ": " + MediaNames.METADATA_RETRIEVAL_TEST_FILES[i]);
@@ -148,12 +146,9 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
public static void testBasicNormalMethodCallSequence() throws Exception {
boolean hasFailed = false;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
try {
retriever.setDataSource(MediaNames.TEST_PATH_1);
- /*
- * captureFrame() fails due to lack of permission to access hardware decoder devices
- Bitmap bitmap = retriever.captureFrame();
+ Bitmap bitmap = retriever.getFrameAtTime(-1);
assertTrue(bitmap != null);
try {
java.io.OutputStream stream = new FileOutputStream("/sdcard/thumbnailout.jpg");
@@ -162,7 +157,6 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
} catch (Exception e) {
throw new Exception("Fails to convert the bitmap to a JPEG file for " + MediaNames.TEST_PATH_1, e);
}
- */
extractAllSupportedMetadataValues(retriever);
} catch(Exception e) {
Log.e(TAG, "Fails to setDataSource for " + MediaNames.TEST_PATH_1, e);
@@ -172,18 +166,17 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
assertTrue(!hasFailed);
}
- // If setDataSource() has not been called, both captureFrame() and extractMetadata() must
+ // If setDataSource() has not been called, both getFrameAtTime() and extractMetadata() must
// return null.
@MediumTest
public static void testBasicAbnormalMethodCallSequence() {
boolean hasFailed = false;
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
if (retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM) != null) {
Log.e(TAG, "No album metadata expected, but is available");
hasFailed = true;
}
- if (retriever.captureFrame() != null) {
+ if (retriever.getFrameAtTime(-1) != null) {
Log.e(TAG, "No frame expected, but is available");
hasFailed = true;
}
@@ -194,7 +187,6 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
@MediumTest
public static void testSetDataSource() {
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
- retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
boolean hasFailed = false;
// Null pointer argument
@@ -259,14 +251,13 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
// By default, capture frame and retrieve metadata
MediaMetadataRetriever retriever = new MediaMetadataRetriever();
boolean hasFailed = false;
- // retriever.setDataSource(MediaNames.TEST_PATH_1);
- // assertTrue(retriever.captureFrame() != null);
- // assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
+ retriever.setDataSource(MediaNames.TEST_PATH_1);
+ assertTrue(retriever.getFrameAtTime(-1) != null);
+ assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
// Do not capture frame or retrieve metadata
- retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY & MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
retriever.setDataSource(MediaNames.TEST_PATH_1);
- if (retriever.captureFrame() != null) {
+ if (retriever.getFrameAtTime(-1) != null) {
Log.e(TAG, "No frame expected, but is available");
hasFailed = true;
}
@@ -276,23 +267,20 @@ public class MediaMetadataRetrieverTest extends AndroidTestCase {
}
// Capture frame only
- // retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY);
- // retriever.setDataSource(MediaNames.TEST_PATH_1);
- // assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) == null);
+ retriever.setDataSource(MediaNames.TEST_PATH_1);
+ assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) == null);
// Retriever metadata only
- retriever.setMode(MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
retriever.setDataSource(MediaNames.TEST_PATH_1);
- if (retriever.captureFrame() != null) {
+ if (retriever.getFrameAtTime(-1) != null) {
Log.e(TAG, "No frame expected, but is available");
hasFailed = true;
}
// Capture frame and retrieve metadata
- // retriever.setMode(MediaMetadataRetriever.MODE_CAPTURE_FRAME_ONLY | MediaMetadataRetriever.MODE_GET_METADATA_ONLY);
- // retriever.setDataSource(MediaNames.TEST_PATH_1);
- // assertTrue(retriever.captureFrame() != null);
- // assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
+ retriever.setDataSource(MediaNames.TEST_PATH_1);
+ assertTrue(retriever.getFrameAtTime(-1) != null);
+ assertTrue(retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_NUM_TRACKS) != null);
retriever.release();
assertTrue(!hasFailed);
}
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
index 01c7e2a..6bc6201 100644
--- a/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
index 4f0d1f1..aa2000e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_signal_flightmode.png
Binary files differ
diff --git a/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java b/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java
index 840c5e1..c4feefd 100644
--- a/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/AccountUnlockScreen.java
@@ -62,8 +62,8 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
*/
private static final int AWAKE_POKE_MILLIS = 30000;
- private final KeyguardScreenCallback mCallback;
- private final LockPatternUtils mLockPatternUtils;
+ private KeyguardScreenCallback mCallback;
+ private LockPatternUtils mLockPatternUtils;
private KeyguardUpdateMonitor mUpdateMonitor;
private TextView mTopHeader;
@@ -159,7 +159,10 @@ public class AccountUnlockScreen extends RelativeLayout implements KeyguardScree
if (mCheckingDialog != null) {
mCheckingDialog.hide();
}
- mUpdateMonitor.removeCallback(this);
+ mUpdateMonitor.removeCallback(this); // this must be first
+ mCallback = null;
+ mLockPatternUtils = null;
+ mUpdateMonitor = null;
}
/** {@inheritDoc} */
diff --git a/policy/src/com/android/internal/policy/impl/GlobalActions.java b/policy/src/com/android/internal/policy/impl/GlobalActions.java
index 1f06dcc..5e33f05 100644
--- a/policy/src/com/android/internal/policy/impl/GlobalActions.java
+++ b/policy/src/com/android/internal/policy/impl/GlobalActions.java
@@ -221,8 +221,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
final AlertDialog.Builder ab = new AlertDialog.Builder(mContext);
ab.setAdapter(mAdapter, this)
- .setInverseBackgroundForced(true)
- .setTitle(R.string.global_actions);
+ .setInverseBackgroundForced(true);
final AlertDialog dialog = ab.create();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
@@ -249,6 +248,7 @@ class GlobalActions implements DialogInterface.OnDismissListener, DialogInterfac
} else {
mDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG);
}
+ mDialog.setTitle(R.string.global_actions);
}
diff --git a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
index ba1d7f5..708e89d 100644
--- a/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
+++ b/policy/src/com/android/internal/policy/impl/KeyguardViewManager.java
@@ -223,8 +223,8 @@ public class KeyguardViewManager implements KeyguardWindowController {
mKeyguardHost.postDelayed(new Runnable() {
public void run() {
synchronized (KeyguardViewManager.this) {
- mKeyguardHost.removeView(lastView);
lastView.cleanUp();
+ mKeyguardHost.removeView(lastView);
}
}
}, 500);
diff --git a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
index 27706ef..f3d07ab 100644
--- a/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
+++ b/policy/src/com/android/internal/policy/impl/LockPatternKeyguardView.java
@@ -495,8 +495,10 @@ public class LockPatternKeyguardView extends KeyguardViewBase {
public void cleanUp() {
((KeyguardScreen) mLockScreen).onPause();
((KeyguardScreen) mLockScreen).cleanUp();
+ this.removeView(mLockScreen);
((KeyguardScreen) mUnlockScreen).onPause();
((KeyguardScreen) mUnlockScreen).cleanUp();
+ this.removeView(mUnlockScreen);
}
private boolean isSecure() {
diff --git a/policy/src/com/android/internal/policy/impl/LockScreen.java b/policy/src/com/android/internal/policy/impl/LockScreen.java
index 635b7d3..5a20b93 100644
--- a/policy/src/com/android/internal/policy/impl/LockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/LockScreen.java
@@ -55,9 +55,9 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
private Status mStatus = Status.Normal;
- private final LockPatternUtils mLockPatternUtils;
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final KeyguardScreenCallback mCallback;
+ private LockPatternUtils mLockPatternUtils;
+ private KeyguardUpdateMonitor mUpdateMonitor;
+ private KeyguardScreenCallback mCallback;
private TextView mCarrier;
private SlidingTab mSelector;
@@ -225,8 +225,8 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
setFocusableInTouchMode(true);
setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
- updateMonitor.registerInfoCallback(this);
- updateMonitor.registerSimStateCallback(this);
+ mUpdateMonitor.registerInfoCallback(this);
+ mUpdateMonitor.registerSimStateCallback(this);
mAudioManager = (AudioManager) getContext().getSystemService(Context.AUDIO_SERVICE);
mSilentMode = isSilentMode();
@@ -668,7 +668,10 @@ class LockScreen extends LinearLayout implements KeyguardScreen, KeyguardUpdateM
/** {@inheritDoc} */
public void cleanUp() {
- mUpdateMonitor.removeCallback(this);
+ mUpdateMonitor.removeCallback(this); // this must be first
+ mLockPatternUtils = null;
+ mUpdateMonitor = null;
+ mCallback = null;
}
/** {@inheritDoc} */
diff --git a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
index 418e243..ffd0a47 100644
--- a/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
+++ b/policy/src/com/android/internal/policy/impl/PatternUnlockScreen.java
@@ -66,9 +66,9 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient
private int mTotalFailedPatternAttempts = 0;
private CountDownTimer mCountdownTimer = null;
- private final LockPatternUtils mLockPatternUtils;
- private final KeyguardUpdateMonitor mUpdateMonitor;
- private final KeyguardScreenCallback mCallback;
+ private LockPatternUtils mLockPatternUtils;
+ private KeyguardUpdateMonitor mUpdateMonitor;
+ private KeyguardScreenCallback mCallback;
/**
* whether there is a fallback option available when the pattern is forgotten.
@@ -478,6 +478,9 @@ class PatternUnlockScreen extends LinearLayoutWithDefaultTouchRecepient
/** {@inheritDoc} */
public void cleanUp() {
mUpdateMonitor.removeCallback(this);
+ mLockPatternUtils = null;
+ mUpdateMonitor = null;
+ mCallback = null;
}
@Override
diff --git a/services/java/com/android/server/IntentResolver.java b/services/java/com/android/server/IntentResolver.java
index e47de13..a8b2840 100644
--- a/services/java/com/android/server/IntentResolver.java
+++ b/services/java/com/android/server/IntentResolver.java
@@ -346,7 +346,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
int num = 0;
while (i.hasNext()) {
- String name = (String)i.next();
+ String name = i.next();
num++;
if (localLOGV) Slog.v(TAG, prefix + name);
String baseName = name;
@@ -395,7 +395,7 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
int num = 0;
while (i.hasNext()) {
- String name = (String)i.next();
+ String name = i.next();
num++;
if (localLOGV) Slog.v(TAG, prefix + name);
String baseName = name;
@@ -534,8 +534,8 @@ public class IntentResolver<F extends IntentFilter, R extends Object> {
// Sorts a List of IntentFilter objects into descending priority order.
private static final Comparator mResolvePrioritySorter = new Comparator() {
public int compare(Object o1, Object o2) {
- float q1 = ((IntentFilter)o1).getPriority();
- float q2 = ((IntentFilter)o2).getPriority();
+ final int q1 = ((IntentFilter) o1).getPriority();
+ final int q2 = ((IntentFilter) o2).getPriority();
return (q1 > q2) ? -1 : ((q1 < q2) ? 1 : 0);
}
};
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index cb9dfc8..39c7540 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -102,6 +102,7 @@ import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
+import java.lang.reflect.Array;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
@@ -2881,13 +2882,13 @@ class PackageManagerService extends IPackageManager.Stub {
SharedUserSetting suid = null;
PackageSetting pkgSetting = null;
- if ((pkg.applicationInfo.flags&ApplicationInfo.FLAG_SYSTEM) == 0) {
+ if (!isSystemApp(pkg)) {
// Only system apps can use these features.
pkg.mOriginalPackages = null;
pkg.mRealPackage = null;
pkg.mAdoptPermissions = null;
}
-
+
synchronized (mPackages) {
// Check all shared libraries and map to their actual file path.
if (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null) {
@@ -4080,6 +4081,7 @@ class PackageManagerService extends IPackageManager.Stub {
}
public final void addActivity(PackageParser.Activity a, String type) {
+ final boolean systemApp = isSystemApp(a.info.applicationInfo);
mActivities.put(a.getComponentName(), a);
if (SHOW_INFO || Config.LOGV) Log.v(
TAG, " " + type + " " +
@@ -4088,6 +4090,11 @@ class PackageManagerService extends IPackageManager.Stub {
int NI = a.intents.size();
for (int j=0; j<NI; j++) {
PackageParser.ActivityIntentInfo intent = a.intents.get(j);
+ if (!systemApp && intent.getPriority() > 0 && "activity".equals(type)) {
+ intent.setPriority(0);
+ Log.w(TAG, "Package " + a.info.applicationInfo.packageName + " has activity "
+ + a.className + " with priority > 0, forcing to 0");
+ }
if (SHOW_INFO || Config.LOGV) {
Log.v(TAG, " IntentFilter:");
intent.dump(new LogPrinter(Log.VERBOSE, TAG), " ");
@@ -4566,16 +4573,52 @@ class PackageManagerService extends IPackageManager.Stub {
mHandler.sendMessage(msg);
}
- public void setPackageObbPath(String packageName, String path) {
+ public void setPackageObbPaths(String packageName, String[] paths) {
if (DEBUG_OBB)
- Log.v(TAG, "Setting .obb path for " + packageName + " to: " + path);
- PackageSetting pkgSetting;
+ Log.v(TAG, "Setting .obb paths for " + packageName + " to: " + Arrays.toString(paths));
final int uid = Binder.getCallingUid();
final int permission = mContext.checkCallingPermission(
android.Manifest.permission.INSTALL_PACKAGES);
final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+ if (!allowedByPermission) {
+ throw new SecurityException("Permission denial: attempt to set .obb file from pid="
+ + Binder.getCallingPid());
+ }
synchronized (mPackages) {
- pkgSetting = mSettings.mPackages.get(packageName);
+ final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+ if (pkgSetting == null) {
+ throw new IllegalArgumentException("Unknown package: " + packageName);
+ }
+
+ if (paths != null) {
+ if (paths.length == 0) {
+ // Don't bother storing an empty array.
+ paths = null;
+ } else {
+ // Don't allow the caller to manipulate our copy of the
+ // list.
+ paths = paths.clone();
+ }
+ }
+
+ // Only write settings file if the new and old settings are not the
+ // same.
+ if (!Arrays.equals(paths, pkgSetting.obbPathStrings)) {
+ pkgSetting.obbPathStrings = paths;
+ mSettings.writeLP();
+ }
+ }
+ }
+
+ public String[] getPackageObbPaths(String packageName) {
+ if (DEBUG_OBB)
+ Log.v(TAG, "Getting .obb paths for " + packageName);
+ final int uid = Binder.getCallingUid();
+ final int permission = mContext.checkCallingPermission(
+ android.Manifest.permission.INSTALL_PACKAGES);
+ final boolean allowedByPermission = (permission == PackageManager.PERMISSION_GRANTED);
+ synchronized (mPackages) {
+ final PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
if (pkgSetting == null) {
throw new IllegalArgumentException("Unknown package: " + packageName);
}
@@ -4584,8 +4627,7 @@ class PackageManagerService extends IPackageManager.Stub {
+ Binder.getCallingPid() + ", uid=" + uid + ", package uid="
+ pkgSetting.userId);
}
- pkgSetting.obbPathString = path;
- mSettings.writeLP();
+ return pkgSetting.obbPathStrings;
}
}
@@ -5952,6 +5994,10 @@ class PackageManagerService extends IPackageManager.Stub {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
}
+ private static boolean isSystemApp(ApplicationInfo info) {
+ return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
+ }
+
private static boolean isUpdatedSystemApp(PackageParser.Package pkg) {
return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;
}
@@ -7154,7 +7200,7 @@ class PackageManagerService extends IPackageManager.Stub {
pw.print(" codePath="); pw.println(ps.codePathString);
pw.print(" resourcePath="); pw.println(ps.resourcePathString);
pw.print(" nativeLibraryPath="); pw.println(ps.nativeLibraryPathString);
- pw.print(" obbPath="); pw.println(ps.obbPathString);
+ pw.print(" obbPaths="); pw.println(Arrays.toString(ps.obbPathStrings));
pw.print(" versionCode="); pw.println(ps.versionCode);
if (ps.pkg != null) {
pw.print(" versionName="); pw.println(ps.pkg.mVersionName);
@@ -7362,6 +7408,12 @@ class PackageManagerService extends IPackageManager.Stub {
static class PackageSignatures {
private Signature[] mSignatures;
+ PackageSignatures(PackageSignatures orig) {
+ if (orig != null && orig.mSignatures != null) {
+ mSignatures = orig.mSignatures.clone();
+ }
+ }
+
PackageSignatures(Signature[] sigs) {
assignSignatures(sigs);
}
@@ -7697,6 +7749,15 @@ class PackageManagerService extends IPackageManager.Stub {
setFlags(pkgFlags);
}
+ GrantedPermissions(GrantedPermissions base) {
+ pkgFlags = base.pkgFlags;
+ grantedPermissions = (HashSet<String>) base.grantedPermissions.clone();
+
+ if (base.gids != null) {
+ gids = base.gids.clone();
+ }
+ }
+
void setFlags(int pkgFlags) {
this.pkgFlags = pkgFlags & (
ApplicationInfo.FLAG_SYSTEM |
@@ -7717,14 +7778,14 @@ class PackageManagerService extends IPackageManager.Stub {
File resourcePath;
String resourcePathString;
String nativeLibraryPathString;
- String obbPathString;
+ String[] obbPathStrings;
long timeStamp;
long firstInstallTime;
long lastUpdateTime;
int versionCode;
boolean uidError;
-
+
PackageSignatures signatures = new PackageSignatures();
boolean permissionsFixed;
@@ -7750,6 +7811,48 @@ class PackageManagerService extends IPackageManager.Stub {
init(codePath, resourcePath, nativeLibraryPathString, pVersionCode);
}
+ /**
+ * New instance of PackageSetting with one-level-deep cloning.
+ */
+ PackageSettingBase(PackageSettingBase base) {
+ super(base);
+
+ name = base.name;
+ realName = base.realName;
+ codePath = base.codePath;
+ codePathString = base.codePathString;
+ resourcePath = base.resourcePath;
+ resourcePathString = base.resourcePathString;
+ nativeLibraryPathString = base.nativeLibraryPathString;
+
+ if (base.obbPathStrings != null) {
+ obbPathStrings = base.obbPathStrings.clone();
+ }
+
+ timeStamp = base.timeStamp;
+ firstInstallTime = base.firstInstallTime;
+ lastUpdateTime = base.lastUpdateTime;
+ versionCode = base.versionCode;
+
+ uidError = base.uidError;
+
+ signatures = new PackageSignatures(base.signatures);
+
+ permissionsFixed = base.permissionsFixed;
+ haveGids = base.haveGids;
+
+ disabledComponents = (HashSet<String>) base.disabledComponents.clone();
+
+ enabledComponents = (HashSet<String>) base.enabledComponents.clone();
+
+ enabled = base.enabled;
+ installStatus = base.installStatus;
+
+ origPackage = base.origPackage;
+
+ installerPackageName = base.installerPackageName;
+ }
+
void init(File codePath, File resourcePath, String nativeLibraryPathString,
int pVersionCode) {
this.codePath = codePath;
@@ -7780,6 +7883,9 @@ class PackageManagerService extends IPackageManager.Stub {
timeStamp = newStamp;
}
+ /**
+ * Make a shallow copy of this package settings.
+ */
public void copyFrom(PackageSettingBase base) {
grantedPermissions = base.grantedPermissions;
gids = base.gids;
@@ -7839,10 +7945,16 @@ class PackageManagerService extends IPackageManager.Stub {
pkgFlags);
}
+ /**
+ * New instance of PackageSetting replicating the original settings.
+ * Note that it keeps the same PackageParser.Package instance.
+ */
PackageSetting(PackageSetting orig) {
- super(orig.name, orig.realName, orig.codePath, orig.resourcePath,
- orig.nativeLibraryPathString, orig.versionCode, orig.pkgFlags);
- copyFrom(orig);
+ super(orig);
+
+ userId = orig.userId;
+ pkg = orig.pkg;
+ sharedUser = orig.sharedUser;
}
@Override
@@ -8074,7 +8186,7 @@ class PackageManagerService extends IPackageManager.Stub {
// a little trick... when we install the new package, we don't
// want to modify the existing PackageSetting for the built-in
// version. so at this point we need a new PackageSetting that
- // is okay to much with.
+ // is okay to muck with.
PackageSetting newp = new PackageSetting(p);
replacePackageLP(name, newp);
return true;
@@ -8775,8 +8887,15 @@ class PackageManagerService extends IPackageManager.Stub {
if (pkg.installerPackageName != null) {
serializer.attribute(null, "installer", pkg.installerPackageName);
}
- if (pkg.obbPathString != null) {
- serializer.attribute(null, "obbPath", pkg.obbPathString);
+ if (pkg.obbPathStrings != null && pkg.obbPathStrings.length > 0) {
+ int N = pkg.obbPathStrings.length;
+ serializer.startTag(null, "obbs");
+ for (int i = 0; i < N; i++) {
+ serializer.startTag(null, "obb");
+ serializer.attribute(null, "path", pkg.obbPathStrings[i]);
+ serializer.endTag(null, "obb");
+ }
+ serializer.endTag(null, "obbs");
}
pkg.signatures.writeXml(serializer, "sigs", mPastSignatures);
if ((pkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
@@ -9180,7 +9299,6 @@ class PackageManagerService extends IPackageManager.Stub {
String codePathStr = null;
String resourcePathStr = null;
String nativeLibraryPathStr = null;
- String obbPathStr = null;
String systemStr = null;
String installerPackageName = null;
String uidError = null;
@@ -9200,7 +9318,6 @@ class PackageManagerService extends IPackageManager.Stub {
codePathStr = parser.getAttributeValue(null, "codePath");
resourcePathStr = parser.getAttributeValue(null, "resourcePath");
nativeLibraryPathStr = parser.getAttributeValue(null, "nativeLibraryPath");
- obbPathStr = parser.getAttributeValue(null, "obbPath");
version = parser.getAttributeValue(null, "version");
if (version != null) {
try {
@@ -9325,7 +9442,6 @@ class PackageManagerService extends IPackageManager.Stub {
packageSetting.uidError = "true".equals(uidError);
packageSetting.installerPackageName = installerPackageName;
packageSetting.nativeLibraryPathString = nativeLibraryPathStr;
- packageSetting.obbPathString = obbPathStr;
final String enabledStr = parser.getAttributeValue(null, "enabled");
if (enabledStr != null) {
if (enabledStr.equalsIgnoreCase("true")) {
@@ -9373,6 +9489,8 @@ class PackageManagerService extends IPackageManager.Stub {
readGrantedPermissionsLP(parser,
packageSetting.grantedPermissions);
packageSetting.permissionsFixed = true;
+ } else if (tagName.equals("obbs")) {
+ readObbPathsLP(packageSetting, parser);
} else {
reportSettingsProblem(Log.WARN,
"Unknown element under <package>: "
@@ -9577,6 +9695,34 @@ class PackageManagerService extends IPackageManager.Stub {
}
}
+ private void readObbPathsLP(PackageSettingBase packageSetting, XmlPullParser parser)
+ throws XmlPullParserException, IOException {
+ final List<String> obbPaths = new ArrayList<String>();
+ final int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+
+ final String tagName = parser.getName();
+ if (tagName.equals("obb")) {
+ final String path = parser.getAttributeValue(null, "path");
+ obbPaths.add(path);
+ } else {
+ reportSettingsProblem(Log.WARN, "Unknown element under <obbs>: "
+ + parser.getName());
+ }
+ XmlUtils.skipCurrentTag(parser);
+ }
+ if (obbPaths.size() == 0) {
+ return;
+ } else {
+ packageSetting.obbPathStrings = obbPaths.toArray(new String[obbPaths.size()]);
+ }
+ }
+
// Returns -1 if we could not find an available UserId to assign
private int newUserIdLP(Object obj) {
// Let's be stupidly inefficient for now...
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index f0cbaa0..4a18b3e 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -490,8 +490,17 @@ public class MockPackageManager extends PackageManager {
throw new UnsupportedOperationException();
}
- @Override
public void setPackageObbPath(String packageName, String path) {
throw new UnsupportedOperationException();
}
+
+ @Override
+ public void setPackageObbPaths(String packageName, String[] paths) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public String[] getPackageObbPaths(String packageName) {
+ throw new UnsupportedOperationException();
+ }
}
diff --git a/voip/java/android/net/sip/SipProfile.java b/voip/java/android/net/sip/SipProfile.java
index f8fd2b7..c7e18df 100644
--- a/voip/java/android/net/sip/SipProfile.java
+++ b/voip/java/android/net/sip/SipProfile.java
@@ -49,6 +49,7 @@ public class SipProfile implements Parcelable, Serializable, Cloneable {
private String mDomain;
private String mProtocol = UDP;
private String mProfileName;
+ private String mAuthUserName;
private int mPort = DEFAULT_PORT;
private boolean mSendKeepAlive = false;
private boolean mAutoRegistration = true;
@@ -147,6 +148,18 @@ public class SipProfile implements Parcelable, Serializable, Cloneable {
}
/**
+ * Sets the username used for authentication.
+ *
+ * @param name auth. name of the profile
+ * @return this builder object
+ * @hide // TODO: remove when we make it public
+ */
+ public Builder setAuthUserName(String name) {
+ mProfile.mAuthUserName = name;
+ return this;
+ }
+
+ /**
* Sets the name of the profile. This name is given by user.
*
* @param name name of the profile
@@ -300,6 +313,7 @@ public class SipProfile implements Parcelable, Serializable, Cloneable {
mAutoRegistration = (in.readInt() == 0) ? false : true;
mCallingUid = in.readInt();
mPort = in.readInt();
+ mAuthUserName = in.readString();
}
@Override
@@ -314,6 +328,7 @@ public class SipProfile implements Parcelable, Serializable, Cloneable {
out.writeInt(mAutoRegistration ? 1 : 0);
out.writeInt(mCallingUid);
out.writeInt(mPort);
+ out.writeString(mAuthUserName);
}
@Override
@@ -375,6 +390,17 @@ public class SipProfile implements Parcelable, Serializable, Cloneable {
}
/**
+ * Gets the username for authentication. If it is null, then the username
+ * should be used in authentication instead.
+ *
+ * @return the auth. username
+ * @hide // TODO: remove when we make it public
+ */
+ public String getAuthUserName() {
+ return mAuthUserName;
+ }
+
+ /**
* Gets the password.
*
* @return the password
diff --git a/voip/java/com/android/server/sip/SipSessionGroup.java b/voip/java/com/android/server/sip/SipSessionGroup.java
index 3275317..aa616a9 100644
--- a/voip/java/com/android/server/sip/SipSessionGroup.java
+++ b/voip/java/com/android/server/sip/SipSessionGroup.java
@@ -895,7 +895,9 @@ class SipSessionGroup implements SipListener {
challengedTransaction, String realm) {
return new UserCredentials() {
public String getUserName() {
- return mLocalProfile.getUserName();
+ String username = mLocalProfile.getAuthUserName();
+ return (!TextUtils.isEmpty(username) ? username :
+ mLocalProfile.getUserName());
}
public String getPassword() {