am 00e08463: Doc change: clarifying nfc tech filter usage
* commit '00e08463cb8df0969e71fd731a4e078680c4f2b5':
Doc change: clarifying nfc tech filter usage
diff --git a/NOTICE b/NOTICE
index 462d5ae..152be20 100644
--- a/NOTICE
+++ b/NOTICE
@@ -56,16 +56,6 @@
=========================================================================
== 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.
-
- =========================================================================
- == NOTICE file corresponding to the section 4 d of ==
- == the Apache License, Version 2.0, ==
== in this case for the TagSoup code. ==
=========================================================================
@@ -82,6 +72,16 @@
OF ANY KIND, either express or implied; not even the implied warranty
of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ =========================================================================
+ == 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.
+
=========================================================================
== NOTICE file corresponding to the section 4 d of ==
== the Apache License, Version 2.0, ==
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index da518c2..2d03e7c 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -1579,9 +1579,11 @@
@Override
protected void finalize() throws Throwable {
+ // TODO: integrate CloseGuard support.
try {
if(!mCloseFlag) {
- ContentResolver.this.releaseProvider(mContentProvider);
+ Log.w(TAG, "Cursor finalized without prior close()");
+ close();
}
} finally {
super.finalize();
diff --git a/core/java/android/nfc/NfcAdapter.java b/core/java/android/nfc/NfcAdapter.java
index 622bcdb..8c56fda 100644
--- a/core/java/android/nfc/NfcAdapter.java
+++ b/core/java/android/nfc/NfcAdapter.java
@@ -702,4 +702,28 @@
return null;
}
}
+
+ /**
+ * To change the Secure Element Card Emulation state (ON/OFF)
+ * @hide
+ */
+ public void changeNfcSecureElementCardEmulationState(boolean state)
+ {
+ int seId = 11259375;
+ if(state){
+ /* Enable card emulation */
+ try {
+ sService.selectSecureElement(seId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Enable card emulation failed", e);
+ }
+ }else{
+ /* Disable card emulation */
+ try {
+ sService.deselectSecureElement();
+ } catch (RemoteException e) {
+ Log.e(TAG, " card emulation failed", e);
+ }
+ }
+ }
}
diff --git a/core/java/android/nfc/tech/MifareUltralight.java b/core/java/android/nfc/tech/MifareUltralight.java
index f7fee72..87c8d99 100644
--- a/core/java/android/nfc/tech/MifareUltralight.java
+++ b/core/java/android/nfc/tech/MifareUltralight.java
@@ -147,7 +147,7 @@
* @throws IOException if there is an I/O failure, or the operation is canceled
*/
public byte[] readPages(int pageOffset) throws IOException {
- validatePageOffset(pageOffset);
+ validatePageIndex(pageOffset);
checkConnected();
byte[] cmd = { 0x30, (byte) pageOffset};
@@ -172,7 +172,7 @@
* @throws IOException if there is an I/O failure, or the operation is canceled
*/
public void writePage(int pageOffset, byte[] data) throws IOException {
- validatePageOffset(pageOffset);
+ validatePageIndex(pageOffset);
checkConnected();
byte[] cmd = new byte[data.length + 2];
@@ -202,14 +202,14 @@
return transceive(data, true);
}
- private static void validatePageOffset(int pageOffset) {
+ private static void validatePageIndex(int pageIndex) {
// Do not be too strict on upper bounds checking, since some cards
// may have more addressable memory than they report.
// Note that issuing a command to an out-of-bounds block is safe - the
// tag will wrap the read to an addressable area. This validation is a
// helper to guard against obvious programming mistakes.
- if (pageOffset < 0 || pageOffset >= MAX_PAGE_COUNT) {
- throw new IndexOutOfBoundsException("page out of bounds: " + pageOffset);
+ if (pageIndex < 0 || pageIndex >= MAX_PAGE_COUNT) {
+ throw new IndexOutOfBoundsException("page out of bounds: " + pageIndex);
}
}
}
diff --git a/core/java/android/nfc/tech/package.html b/core/java/android/nfc/tech/package.html
new file mode 100644
index 0000000..a99828f
--- /dev/null
+++ b/core/java/android/nfc/tech/package.html
@@ -0,0 +1,13 @@
+<HTML>
+<BODY>
+<p>
+These classes provide access to a tag technology's features, which vary by the type
+of tag that is scanned. A scanned tag can support multiple technologies, and you can find
+out what they are by calling {@link android.nfc.Tag#getTechList getTechList()}.</p>
+
+<p>For more information on dealing with tag technologies and handling the ones that you care about, see
+<a href="{@docRoot}guide/topics/nfc/index.html#dispatch">The Tag Dispatch System</a>.
+The {@link android.nfc.tech.TagTechnology} interface provides an overview of the
+supported technologies.</p>
+</BODY>
+</HTML>
diff --git a/core/java/android/os/Message.java b/core/java/android/os/Message.java
index eb941e4..557e53f 100644
--- a/core/java/android/os/Message.java
+++ b/core/java/android/os/Message.java
@@ -96,9 +96,9 @@
// sometimes we store linked lists of these things
/*package*/ Message next;
- private static Object mPoolSync = new Object();
- private static Message mPool;
- private static int mPoolSize = 0;
+ private static final Object sPoolSync = new Object();
+ private static Message sPool;
+ private static int sPoolSize = 0;
private static final int MAX_POOL_SIZE = 10;
@@ -107,11 +107,12 @@
* avoid allocating new objects in many cases.
*/
public static Message obtain() {
- synchronized (mPoolSync) {
- if (mPool != null) {
- Message m = mPool;
- mPool = m.next;
+ synchronized (sPoolSync) {
+ if (sPool != null) {
+ Message m = sPool;
+ sPool = m.next;
m.next = null;
+ sPoolSize--;
return m;
}
}
@@ -248,12 +249,12 @@
* freed.
*/
public void recycle() {
- synchronized (mPoolSync) {
- if (mPoolSize < MAX_POOL_SIZE) {
+ synchronized (sPoolSync) {
+ if (sPoolSize < MAX_POOL_SIZE) {
clearForRecycle();
-
- next = mPool;
- mPool = this;
+ next = sPool;
+ sPool = this;
+ sPoolSize++;
}
}
}
diff --git a/core/java/android/pim/ICalendar.java b/core/java/android/pim/ICalendar.java
index cc0f45e..9c4eaf4 100644
--- a/core/java/android/pim/ICalendar.java
+++ b/core/java/android/pim/ICalendar.java
@@ -578,6 +578,23 @@
+ text);
}
parameter.name = text.substring(startIndex + 1, equalIndex);
+ } else if (c == '"') {
+ if (parameter == null) {
+ throw new FormatException("Expected parameter before '\"' in " + text);
+ }
+ if (equalIndex == -1) {
+ throw new FormatException("Expected '=' within parameter in " + text);
+ }
+ if (state.index > equalIndex + 1) {
+ throw new FormatException("Parameter value cannot contain a '\"' in " + text);
+ }
+ final int endQuote = text.indexOf('"', state.index + 1);
+ if (endQuote < 0) {
+ throw new FormatException("Expected closing '\"' in " + text);
+ }
+ parameter.value = text.substring(state.index + 1, endQuote);
+ state.index = endQuote + 1;
+ return parameter;
}
++state.index;
}
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
old mode 100644
new mode 100755
index 803446f..1a35112
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -115,8 +115,8 @@
public static final int STATUS_NONE = -1;
public static final int STATUS_COMPLETE = 0;
- public static final int STATUS_PENDING = 64;
- public static final int STATUS_FAILED = 128;
+ public static final int STATUS_PENDING = 32;
+ public static final int STATUS_FAILED = 64;
/**
* The subject of the message, if present
diff --git a/core/java/android/service/wallpaper/WallpaperService.java b/core/java/android/service/wallpaper/WallpaperService.java
index 912a88d..dd39714 100644
--- a/core/java/android/service/wallpaper/WallpaperService.java
+++ b/core/java/android/service/wallpaper/WallpaperService.java
@@ -524,8 +524,11 @@
mLayout.windowAnimations =
com.android.internal.R.style.Animation_Wallpaper;
mInputChannel = new InputChannel();
- mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets,
- mInputChannel);
+ if (mSession.add(mWindow, mLayout, View.VISIBLE, mContentInsets,
+ mInputChannel) < 0) {
+ Log.w(TAG, "Failed to add window while updating wallpaper surface.");
+ return;
+ }
mCreated = true;
InputQueue.registerInputChannel(mInputChannel, mInputHandler,
diff --git a/core/java/android/text/InputFilter.java b/core/java/android/text/InputFilter.java
index 2f55677..8d4b08e 100644
--- a/core/java/android/text/InputFilter.java
+++ b/core/java/android/text/InputFilter.java
@@ -88,7 +88,14 @@
} else if (keep >= end - start) {
return null; // keep original
} else {
- return source.subSequence(start, start + keep);
+ keep += start;
+ if (Character.isHighSurrogate(source.charAt(keep - 1))) {
+ --keep;
+ if (keep == start) {
+ return "";
+ }
+ }
+ return source.subSequence(start, keep);
}
}
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index a17ed9d..81346b4 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -38,7 +38,7 @@
* for the device you are running on. For example:
*
* <pre>LayoutInflater inflater = (LayoutInflater)context.getSystemService
- * Context.LAYOUT_INFLATER_SERVICE);</pre>
+ * (Context.LAYOUT_INFLATER_SERVICE);</pre>
*
* <p>
* To create a new LayoutInflater with an additional {@link Factory} for your
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index c26fa93..02e5b63 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1171,14 +1171,6 @@
gravity = o.gravity;
changes |= LAYOUT_CHANGED;
}
- if (horizontalMargin != o.horizontalMargin) {
- horizontalMargin = o.horizontalMargin;
- changes |= LAYOUT_CHANGED;
- }
- if (verticalMargin != o.verticalMargin) {
- verticalMargin = o.verticalMargin;
- changes |= LAYOUT_CHANGED;
- }
if (format != o.format) {
format = o.format;
changes |= FORMAT_CHANGED;
diff --git a/core/java/android/webkit/WebViewCore.java b/core/java/android/webkit/WebViewCore.java
index 5bdf408..b410699 100644
--- a/core/java/android/webkit/WebViewCore.java
+++ b/core/java/android/webkit/WebViewCore.java
@@ -56,7 +56,11 @@
// Load libwebcore during static initialization. This happens in the
// zygote process so it will be shared read-only across all app
// processes.
- System.loadLibrary("webcore");
+ try {
+ System.loadLibrary("webcore");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(LOGTAG, "Unable to load webcore library");
+ }
}
/*
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index ef4e4e0..cf72ec4 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -701,8 +701,8 @@
if (mProgress > max) {
mProgress = max;
- refreshProgress(R.id.progress, mProgress, false);
}
+ refreshProgress(R.id.progress, mProgress, false);
}
}
diff --git a/core/res/res/values-mcc219/config.xml b/core/res/res/values-mcc219/config.xml
new file mode 100644
index 0000000..7ae82fa
--- /dev/null
+++ b/core/res/res/values-mcc219/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+ <string-array name="config_twoDigitNumberPattern">
+ <item>"92"</item>
+ <item>"93"</item>
+ <item>"94"</item>
+ <item>"95"</item>
+ <item>"96"</item>
+ </string-array>
+
+</resources>
diff --git a/core/res/res/values-mcc220/config.xml b/core/res/res/values-mcc220/config.xml
new file mode 100644
index 0000000..7ae82fa
--- /dev/null
+++ b/core/res/res/values-mcc220/config.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2009, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+-->
+
+<!-- These resources are around just to allow their values to be customized
+ for different hardware and product builds. -->
+<resources>
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+ <string-array name="config_twoDigitNumberPattern">
+ <item>"92"</item>
+ <item>"93"</item>
+ <item>"94"</item>
+ <item>"95"</item>
+ <item>"96"</item>
+ </string-array>
+
+</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index aa3f722..c4b2ade 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -551,4 +551,8 @@
<!-- Sets whether menu shortcuts should be displayed on panel menus when
a keyboard is present. -->
<bool name="config_showMenuShortcutsWhenKeyboardPresent">false</bool>
+
+ <!-- Do not translate. Defines the slots is Two Digit Number for dialing normally not USSD -->
+ <string-array name="config_twoDigitNumberPattern">
+ </string-array>
</resources>
diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java
new file mode 100644
index 0000000..2b6dee8b
--- /dev/null
+++ b/core/tests/coretests/src/android/content/ContentResolverTest.java
@@ -0,0 +1,41 @@
+/*
+ * 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.content;
+
+import android.content.ContentResolver;
+import android.provider.ContactsContract;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.LargeTest;
+
+public class ContentResolverTest extends AndroidTestCase {
+ private ContentResolver mContentResolver;
+
+ @Override
+ protected void setUp() throws Exception {
+ super.setUp();
+ mContentResolver = mContext.getContentResolver();
+ }
+
+ @LargeTest
+ public void testCursorFinalizer() throws Exception {
+ // TODO: Want a test case that more predictably reproduce this issue. Selected
+ // 600 as this causes the problem 100% of the runs on current hw, it might not
+ // do so on some other configuration though.
+ for (int i = 0; i < 600; i++) {
+ mContentResolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
+ }
+ }
+}
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 5d00db1..60030f0 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -494,6 +494,7 @@
<td>Keyboard availability</td>
<td>
<code>keysexposed</code><br/>
+ <code>keyshidden</code><br/>
<code>keyssoft</code>
</td>
<td>
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index 9a6f787..b6e0c30 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -117,7 +117,11 @@
status_t DrmManager::setDrmServiceListener(
int uniqueId, const sp<IDrmServiceListener>& drmServiceListener) {
Mutex::Autolock _l(mLock);
- mServiceListeners.add(uniqueId, drmServiceListener);
+ if (NULL != drmServiceListener.get()) {
+ mServiceListeners.add(uniqueId, drmServiceListener);
+ } else {
+ mServiceListeners.removeItem(uniqueId);
+ }
return DRM_NO_ERROR;
}
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index 2f54b33..6caf678 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -738,26 +738,34 @@
*/
private String convertUriToPath(Uri uri) {
String path = null;
- String scheme = uri.getScheme();
- if (null == scheme || scheme.equals("") || scheme.equals(ContentResolver.SCHEME_FILE)) {
- path = uri.getPath();
- } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
- String[] projection = new String[] {MediaStore.MediaColumns.DATA};
- Cursor cursor = null;
- try {
- cursor = mContext.getContentResolver().query(uri, projection, null, null, null);
- } catch (SQLiteException e) {
- throw new IllegalArgumentException("Given Uri is not formatted in a way " +
- "so that it can be found in media store.");
+ if (null != uri) {
+ String scheme = uri.getScheme();
+ if (null == scheme || scheme.equals("") ||
+ scheme.equals(ContentResolver.SCHEME_FILE)) {
+ path = uri.getPath();
+ } else if (scheme.equals(ContentResolver.SCHEME_CONTENT)) {
+ String[] projection = new String[] {MediaStore.MediaColumns.DATA};
+ Cursor cursor = null;
+ try {
+ cursor = mContext.getContentResolver().query(uri, projection, null,
+ null, null);
+ if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) {
+ throw new IllegalArgumentException("Given Uri could not be found" +
+ " in media store");
+ }
+ int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
+ path = cursor.getString(pathIndex);
+ } catch (SQLiteException e) {
+ throw new IllegalArgumentException("Given Uri is not formatted in a way " +
+ "so that it can be found in media store.");
+ } finally {
+ if (null != cursor) {
+ cursor.close();
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("Given Uri scheme is not supported");
}
- if (null == cursor || 0 == cursor.getCount() || !cursor.moveToFirst()) {
- throw new IllegalArgumentException("Given Uri could not be found in media store");
- }
- int pathIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
- path = cursor.getString(pathIndex);
- cursor.close();
- } else {
- throw new IllegalArgumentException("Given Uri scheme is not supported");
}
return path;
}
diff --git a/drm/libdrmframework/DrmManagerClient.cpp b/drm/libdrmframework/DrmManagerClient.cpp
index 578e135..7b51822 100644
--- a/drm/libdrmframework/DrmManagerClient.cpp
+++ b/drm/libdrmframework/DrmManagerClient.cpp
@@ -31,6 +31,7 @@
DrmManagerClient::~DrmManagerClient() {
DrmManagerClientImpl::remove(mUniqueId);
mDrmManagerClientImpl->removeClient(mUniqueId);
+ mDrmManagerClientImpl->setOnInfoListener(mUniqueId, NULL);
delete mDrmManagerClientImpl; mDrmManagerClientImpl = NULL;
}
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
index f39131d..d20de92 100644
--- a/drm/libdrmframework/DrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -81,7 +81,8 @@
int uniqueId, const sp<DrmManagerClient::OnInfoListener>& infoListener) {
Mutex::Autolock _l(mLock);
mOnInfoListener = infoListener;
- return getDrmManagerService()->setDrmServiceListener(uniqueId, this);
+ return getDrmManagerService()->setDrmServiceListener(uniqueId,
+ (NULL != infoListener.get()) ? this : NULL);
}
status_t DrmManagerClientImpl::installDrmEngine(int uniqueId, const String8& drmEngineFile) {
diff --git a/drm/libdrmframework/plugins/common/Android.mk b/drm/libdrmframework/plugins/common/Android.mk
new file mode 100644
index 0000000..9ee7961
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/Android.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+include $(call all-subdir-makefiles)
diff --git a/drm/libdrmframework/plugins/common/util/Android.mk b/drm/libdrmframework/plugins/common/util/Android.mk
new file mode 100644
index 0000000..15dda80
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/util/Android.mk
@@ -0,0 +1,52 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ src/MimeTypeUtil.cpp
+
+LOCAL_MODULE := libdrmutility
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ libdl \
+ libdvm \
+ libandroid_runtime \
+ libnativehelper \
+ liblog
+
+
+base := frameworks/base
+
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE) \
+ $(base)/include \
+ $(base)/include/drm \
+ $(base)/include/drm/plugins \
+ $(LOCAL_PATH)/include
+
+
+ifneq ($(TARGET_BUILD_VARIANT),user)
+LOCAL_C_INCLUDES += \
+ $(LOCAL_PATH)/tools
+
+endif
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/libdrmframework/plugins/common/util/include/MimeTypeUtil.h b/drm/libdrmframework/plugins/common/util/include/MimeTypeUtil.h
new file mode 100644
index 0000000..4d12a61
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/util/include/MimeTypeUtil.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __MIMETYPEUTIL_H__
+#define __MIMETYPEUTIL_H__
+
+#include <utils/String8.h>
+
+namespace android {
+
+class MimeTypeUtil {
+
+public:
+
+ MimeTypeUtil() {}
+
+ virtual ~MimeTypeUtil() {}
+
+/**
+ * May convert the mimetype if there is a well known
+ * replacement mimetype otherwise the original mimetype
+ * is returned.
+ *
+ * @param mimeType - mimetype in lower case to convert.
+ *
+ * @return mimetype or null.
+ */
+static String8 convertMimeType(String8& mimeType);
+
+};
+};
+
+#endif /* __MIMETYPEUTIL_H__ */
diff --git a/drm/libdrmframework/plugins/common/util/include/SessionMap.h b/drm/libdrmframework/plugins/common/util/include/SessionMap.h
new file mode 100644
index 0000000..3dff58c
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/util/include/SessionMap.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __SESSIONMAP_H__
+#define __SESSIONMAP_H__
+
+#include <utils/KeyedVector.h>
+
+namespace android {
+
+/**
+ * A wrapper template class for handling DRM Engine sessions.
+ */
+template <typename NODE>
+class SessionMap {
+
+public:
+ KeyedVector<int, NODE> map;
+
+ SessionMap() {}
+
+ virtual ~SessionMap() {
+ destroyMap();
+ }
+
+/**
+ * Adds a new value in the session map table. It expects memory to be allocated already
+ * for the session object
+ *
+ * @param key - key or Session ID
+ * @param value - session object to add
+ *
+ * @return boolean result of adding value. returns false if key is already exist.
+ */
+bool addValue(int key, NODE value) {
+ bool result = false;
+
+ if (!isCreated(key)) {
+ map.add(key, value);
+ result = true;
+ }
+
+ return result;
+}
+
+
+/**
+ * returns the session object by the key
+ *
+ * @param key - key or Session ID
+ *
+ * @return session object as per the key
+ */
+NODE getValue(int key) {
+ NODE value = NULL;
+
+ if (isCreated(key)) {
+ value = (NODE) map.valueFor(key);
+ }
+
+ return value;
+}
+
+/**
+ * returns the number of objects in the session map table
+ *
+ * @return count of number of session objects.
+ */
+int getSize() {
+ return map.size();
+}
+
+/**
+ * returns the session object by the index in the session map table
+ *
+ * @param index - index of the value required
+ *
+ * @return session object as per the index
+ */
+NODE getValueAt(unsigned int index) {
+ NODE value = NULL;
+
+ if (map.size() > index) {
+ value = map.valueAt(index);
+ }
+
+ return value;
+}
+
+/**
+ * deletes the object from session map. It also frees up memory for the session object.
+ *
+ * @param key - key of the value to be deleted
+ *
+ */
+void removeValue(int key) {
+ deleteValue(getValue(key));
+ map.removeItem(key);
+}
+
+/**
+ * decides if session is already created.
+ *
+ * @param key - key of the value for the session
+ *
+ * @return boolean result of whether session is created
+ */
+bool isCreated(int key) {
+ return (0 <= map.indexOfKey(key));
+}
+
+/**
+ * empty the entire session table. It releases all the memory for session objects.
+ */
+void destroyMap() {
+ int size = map.size();
+ int i = 0;
+
+ for (i = 0; i < size; i++) {
+ deleteValue(map.valueAt(i));
+ }
+
+ map.clear();
+}
+
+/**
+ * free up the memory for the session object.
+ * Make sure if any reference to the session object anywhere, otherwise it will be a
+ * dangle pointer after this call.
+ *
+ * @param value - session object to free
+ *
+ */
+void deleteValue(NODE value) {
+ delete value;
+}
+
+};
+
+};
+
+#endif /* __SESSIONMAP_H__ */
diff --git a/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
new file mode 100644
index 0000000..4ee903e
--- /dev/null
+++ b/drm/libdrmframework/plugins/common/util/src/MimeTypeUtil.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <MimeTypeUtil.h>
+#include <utils/Log.h>
+
+namespace android {
+
+#undef LOG_TAG
+#define LOG_TAG "MimeTypeUtil"
+
+enum {
+ MIMETYPE_AUDIO = 0,
+ MIMETYPE_APPLICATION = 1,
+ MIMETYPE_IMAGE = 2,
+ MIMETYPE_VIDEO = 3,
+ MIMETYPE_LAST = -1,
+};
+
+struct MimeGroup{
+ int type; // Audio, video,.. use the enum values
+ const char* pGroup; // "audio/", "video/",.. should contain the last "/"
+ int size; // Number of bytes. e.g. "audio/" = 6 bytes
+};
+
+struct MimeTypeList{
+ int type;
+ const char* pMimeExt; // Everything after the '/' e.g. audio/x-mpeg -> "x-mpeg"
+ int size; // Number of bytes. e.g. "x-mpeg" = 6 bytes
+ const char* pMimeType; // Mimetype that should be returned
+};
+
+
+// Known mimetypes by android
+static const char mime_type_audio_mpeg[] = "audio/mpeg";
+static const char mime_type_audio_3gpp[] = "audio/3gpp";
+static const char mime_type_audio_amr[] = "audio/amr-wb";
+static const char mime_type_audio_aac[] = "audio/mp4a-latm";
+static const char mime_type_audio_wav[] = "audio/wav";
+
+static const char mime_type_video_mpeg4[] = "video/mpeg4";
+static const char mime_type_video_3gpp[] = "video/3gpp";
+
+// Known mimetype groups
+static const char mime_group_audio[] = "audio/";
+static const char mime_group_application[] = "application/";
+static const char mime_group_image[] = "image/";
+static const char mime_group_video[] = "video/";
+
+static struct MimeGroup mimeGroup[] = {
+ {MIMETYPE_AUDIO, mime_group_audio, sizeof(mime_group_audio)-1},
+ {MIMETYPE_APPLICATION, mime_group_application, sizeof(mime_group_application)-1},
+ {MIMETYPE_IMAGE, mime_group_image, sizeof(mime_group_image)-1},
+ {MIMETYPE_VIDEO, mime_group_video, sizeof(mime_group_video)-1},
+ {MIMETYPE_LAST, NULL, 0} // Must be last entry
+};
+
+// List of all mimetypes that should be converted.
+static struct MimeTypeList mimeTypeList[] = {
+ // Mp3 mime types
+ {MIMETYPE_AUDIO, "mp3", sizeof("mp3")-1, mime_type_audio_mpeg},
+ {MIMETYPE_AUDIO, "x-mpeg", sizeof("x-mpeg")-1, mime_type_audio_mpeg},
+ {MIMETYPE_AUDIO, "x-mp3", sizeof("x-mp3")-1, mime_type_audio_mpeg},
+ {MIMETYPE_AUDIO, "mpg", sizeof("mpg")-1, mime_type_audio_mpeg},
+ {MIMETYPE_AUDIO, "mpg3", sizeof("mpg")-1, mime_type_audio_mpeg},
+ {MIMETYPE_AUDIO, "x-mpg", sizeof("x-mpg")-1, mime_type_audio_mpeg},
+ {MIMETYPE_AUDIO, "x-mpegaudio", sizeof("x-mpegaudio")-1, mime_type_audio_mpeg},
+
+ // 3gpp audio mime types
+ {MIMETYPE_AUDIO, "3gp", sizeof("3gp")-1, mime_type_audio_3gpp},
+
+ // Amr audio mime types
+ {MIMETYPE_AUDIO, "amr", sizeof("amr")-1, mime_type_audio_amr},
+
+ // Aac audio mime types
+ {MIMETYPE_AUDIO, "aac", sizeof("aac")-1, mime_type_audio_aac},
+
+ // Wav audio mime types
+ {MIMETYPE_AUDIO, "x-wav", sizeof("x-wav")-1, mime_type_audio_wav},
+
+ // Mpeg4 video mime types
+ {MIMETYPE_VIDEO, "mpg4", sizeof("mpg4")-1, mime_type_video_mpeg4},
+ {MIMETYPE_VIDEO, "mp4v-es", sizeof("mp4v-es")-1, mime_type_video_mpeg4},
+
+ // 3gpp video mime types
+ {MIMETYPE_VIDEO, "3gp", sizeof("3gp")-1, mime_type_video_3gpp},
+
+ // Must be last entry
+ {MIMETYPE_LAST, NULL, 0, NULL}
+};
+
+/**
+ * May convert the mimetype if there is a well known
+ * replacement mimetype otherwise the original mimetype
+ * is returned.
+ *
+ * @param mimeType - mimetype in lower case to convert.
+ *
+ * @return mimetype or null.
+ */
+String8 MimeTypeUtil::convertMimeType(String8& mimeType) {
+ String8 result = mimeType;
+ const char* pTmp;
+ const char* pMimeType;
+ struct MimeGroup* pGroup;
+ struct MimeTypeList* pMimeItem;
+ int len;
+
+ pMimeType = mimeType.string();
+ if (NULL != pMimeType) {
+ /* Check which group the mimetype is */
+ pGroup = mimeGroup;
+
+ while (MIMETYPE_LAST != pGroup->type) {
+ if (0 == strncmp(pMimeType, pGroup->pGroup, pGroup->size)) {
+ break;
+ }
+ pGroup++;
+ }
+
+ /* Go through the mimetype list. Only check items of the correct group */
+ if (MIMETYPE_LAST != pGroup->type) {
+ pMimeItem = mimeTypeList;
+ len = strlen (pMimeType+pGroup->size);
+
+ while (MIMETYPE_LAST != pMimeItem->type) {
+ if ((len == pMimeItem->size) &&
+ (0 == strcmp(pMimeType+pGroup->size, pMimeItem->pMimeExt))) {
+ result = String8(pMimeItem->pMimeType);
+ break;
+ }
+ pMimeItem++;
+ }
+ }
+ LOGI("convertMimeType got mimetype %s, converted into mimetype %s",
+ pMimeType, result.string());
+ }
+
+ return result;
+}
+};
diff --git a/drm/libdrmframework/plugins/forward-lock/Android.mk b/drm/libdrmframework/plugins/forward-lock/Android.mk
new file mode 100644
index 0000000..9ee7961
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/Android.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+include $(call all-subdir-makefiles)
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
new file mode 100644
index 0000000..d4a6f18
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/Android.mk
@@ -0,0 +1,67 @@
+#
+# 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.
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+base := frameworks/base
+
+# Determine whether the DRM framework uses 64-bit data types for file offsets and do the same.
+ifneq ($(shell grep -c 'off64_t offset' $(base)/drm/libdrmframework/plugins/common/include/IDrmEngine.h), 0)
+LOCAL_CFLAGS += -DUSE_64BIT_DRM_API
+endif
+
+LOCAL_SRC_FILES:= \
+ src/FwdLockEngine.cpp
+
+LOCAL_MODULE := libfwdlockengine
+
+LOCAL_SHARED_LIBRARIES := \
+ libicui18n \
+ libicuuc \
+ libutils \
+ libdl \
+ libandroid_runtime \
+ libnativehelper \
+ libcrypto \
+ libssl \
+ libdrmframework
+
+LOCAL_STATIC_LIBRARIES := \
+ libdrmutility \
+ libdrmframeworkcommon \
+ libfwdlock-common \
+ libfwdlock-converter \
+ libfwdlock-decoder
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_C_INCLUDES += \
+ $(JNI_H_INCLUDE) \
+ $(base)/include/drm \
+ $(base)/drm/libdrmframework/plugins/common/include \
+ $(base)/drm/libdrmframework/plugins/common/util/include \
+ $(base)/drm/libdrmframework/plugins/forward-lock/internal-format/common \
+ $(base)/drm/libdrmframework/plugins/forward-lock/internal-format/converter \
+ $(base)/drm/libdrmframework/plugins/forward-lock/internal-format/decoder \
+ $(LOCAL_PATH)/include \
+ external/openssl/include
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/drm/plugins/native
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
new file mode 100644
index 0000000..34804cf
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
@@ -0,0 +1,559 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FWDLOCKENGINE_H__
+#define __FWDLOCKENGINE_H__
+
+#include <DrmEngineBase.h>
+#include <DrmConstraints.h>
+#include <DrmRights.h>
+#include <DrmInfo.h>
+#include <DrmInfoStatus.h>
+#include <DrmConvertedStatus.h>
+#include <DrmInfoRequest.h>
+#include <DrmSupportInfo.h>
+#include <DrmInfoEvent.h>
+
+#include "SessionMap.h"
+#include "FwdLockConv.h"
+
+namespace android {
+
+/**
+ * Forward Lock Engine class.
+ */
+class FwdLockEngine : public android::DrmEngineBase {
+
+public:
+ FwdLockEngine();
+ virtual ~FwdLockEngine();
+
+protected:
+/**
+ * Get constraint information associated with input content.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param path Path of the protected content
+ * @param action Actions defined such as,
+ * Action::DEFAULT, Action::PLAY, etc
+ * @return DrmConstraints
+ * key-value pairs of constraint are embedded in it
+ * @note
+ * In case of error, return NULL
+ */
+DrmConstraints* onGetConstraints(int uniqueId, const String8* path, int action);
+
+/**
+ * Get metadata information associated with input content.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param path Path of the protected content
+ * @return DrmMetadata
+ * For Forward Lock engine, it returns an empty object
+ * @note
+ * In case of error, returns NULL
+ */
+DrmMetadata* onGetMetadata(int uniqueId, const String8* path);
+
+/**
+ * Initialize plug-in.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+ */
+status_t onInitialize(int uniqueId);
+
+/**
+ * Register a callback to be invoked when the caller required to
+ * receive necessary information.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param infoListener Listener
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+ */
+status_t onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener);
+
+/**
+ * Terminate the plug-in and release resources bound to it.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+ */
+status_t onTerminate(int uniqueId);
+
+/**
+ * Get whether the given content can be handled by this plugin or not.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param path Path to the protected object
+ * @return bool
+ * Returns true if this plugin can handle , false in case of not able to handle
+ */
+bool onCanHandle(int uniqueId, const String8& path);
+
+/**
+ * Processes the given DRM information as appropriate for its type.
+ * Not used for Forward Lock Engine.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param drmInfo Information that needs to be processed
+ * @return DrmInfoStatus
+ * instance as a result of processing given input
+ */
+DrmInfoStatus* onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo);
+
+/**
+ * Save DRM rights to specified rights path
+ * and make association with content path.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param drmRights DrmRights to be saved
+ * @param rightsPath File path where rights to be saved
+ * @param contentPath File path where content was saved
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+ */
+status_t onSaveRights(int uniqueId,
+ const DrmRights& drmRights,
+ const String8& rightsPath,
+ const String8& contentPath);
+
+/**
+ * Retrieves necessary information for registration, unregistration or rights
+ * acquisition information.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param drmInfoRequest Request information to retrieve drmInfo
+ * @return DrmInfo
+ * instance as a result of processing given input
+ */
+DrmInfo* onAcquireDrmInfo(int uniqueId,
+ const DrmInfoRequest* drmInfoRequest);
+
+/**
+ * Retrieves the mime type embedded inside the original content.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param path Path of the protected content
+ * @return String8
+ * Returns mime-type of the original content, such as "video/mpeg"
+ */
+String8 onGetOriginalMimeType(int uniqueId, const String8& path);
+
+/**
+ * Retrieves the type of the protected object (content, rights, etc..)
+ * using specified path or mimetype. At least one parameter should be non null
+ * to retrieve DRM object type.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param path Path of the content or null.
+ * @param mimeType Mime type of the content or null.
+ * @return type of the DRM content,
+ * such as DrmObjectType::CONTENT, DrmObjectType::RIGHTS_OBJECT
+ */
+int onGetDrmObjectType(int uniqueId,
+ const String8& path,
+ const String8& mimeType);
+
+/**
+ * Check whether the given content has valid rights or not.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param path Path of the protected content
+ * @param action Action to perform (Action::DEFAULT, Action::PLAY, etc)
+ * @return the status of the rights for the protected content,
+ * such as RightsStatus::RIGHTS_VALID, RightsStatus::RIGHTS_EXPIRED, etc.
+ */
+int onCheckRightsStatus(int uniqueId,
+ const String8& path,
+ int action);
+
+/**
+ * Consumes the rights for a content.
+ * If the reserve parameter is true the rights are reserved until the same
+ * application calls this api again with the reserve parameter set to false.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the decryption session
+ * @param action Action to perform. (Action::DEFAULT, Action::PLAY, etc)
+ * @param reserve True if the rights should be reserved.
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+ */
+status_t onConsumeRights(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int action,
+ bool reserve);
+
+/**
+ * Informs the DRM Engine about the playback actions performed on the DRM files.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the decryption session
+ * @param playbackStatus Playback action (Playback::START, Playback::STOP, Playback::PAUSE)
+ * @param position Position in the file (in milliseconds) where the start occurs.
+ * Only valid together with Playback::START.
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+ */
+#ifdef USE_64BIT_DRM_API
+status_t onSetPlaybackStatus(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int playbackStatus,
+ int64_t position);
+#else
+status_t onSetPlaybackStatus(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int playbackStatus,
+ int position);
+#endif
+
+/**
+ * Validates whether an action on the DRM content is allowed or not.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param path Path of the protected content
+ * @param action Action to validate (Action::PLAY, Action::TRANSFER, etc)
+ * @param description Detailed description of the action
+ * @return true if the action is allowed.
+ */
+bool onValidateAction(int uniqueId,
+ const String8& path,
+ int action,
+ const ActionDescription& description);
+
+/**
+ * Removes the rights associated with the given protected content.
+ * Not used for Forward Lock Engine.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param path Path of the protected content
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+ */
+status_t onRemoveRights(int uniqueId, const String8& path);
+
+/**
+ * Removes all the rights information of each plug-in associated with
+ * DRM framework. Will be used in master reset but does nothing for
+ * Forward Lock Engine.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+ */
+status_t onRemoveAllRights(int uniqueId);
+
+/**
+ * Starts the Forward Lock file conversion session.
+ * Each time the application tries to download a new DRM file
+ * which needs to be converted, then the application has to
+ * begin with calling this API. The convertId is used as the conversion session key
+ * and must not be the same for different convert sessions.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param convertId Handle for the convert session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+ */
+status_t onOpenConvertSession(int uniqueId, int convertId);
+
+/**
+ * Accepts and converts the input data which is part of DRM file.
+ * The resultant converted data and the status is returned in the DrmConvertedInfo
+ * object. This method will be called each time there is a new block
+ * of data received by the application.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param convertId Handle for the convert session
+ * @param inputData Input Data which need to be converted
+ * @return Return object contains the status of the data conversion,
+ * the output converted data and offset. In this case the
+ * application will ignore the offset information.
+ */
+DrmConvertedStatus* onConvertData(int uniqueId,
+ int convertId,
+ const DrmBuffer* inputData);
+
+/**
+ * Closes the convert session in case of data supply completed or error occurred.
+ * Upon successful conversion of the complete data, it returns signature calculated over
+ * the entire data used over a conversion session. This signature must be copied to the offset
+ * mentioned in the DrmConvertedStatus. Signature is used for data integrity protection.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param convertId Handle for the convert session
+ * @return Return object contains the status of the data conversion,
+ * the header and body signature data. It also informs
+ * the application about the file offset at which this
+ * signature data should be written.
+ */
+DrmConvertedStatus* onCloseConvertSession(int uniqueId, int convertId);
+
+/**
+ * Returns the information about the Drm Engine capabilities which includes
+ * supported MimeTypes and file suffixes.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @return DrmSupportInfo
+ * instance which holds the capabilities of a plug-in
+ */
+DrmSupportInfo* onGetSupportInfo(int uniqueId);
+
+/**
+ * Open the decrypt session to decrypt the given protected content.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the current decryption session
+ * @param fd File descriptor of the protected content to be decrypted
+ * @param offset Start position of the content
+ * @param length The length of the protected content
+ * @return
+ * DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
+ */
+#ifdef USE_64BIT_DRM_API
+status_t onOpenDecryptSession(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int fd, off64_t offset, off64_t length);
+#else
+status_t onOpenDecryptSession(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int fd, int offset, int length);
+#endif
+
+/**
+ * Open the decrypt session to decrypt the given protected content.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the current decryption session
+ * @param uri Path of the protected content to be decrypted
+ * @return
+ * DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
+ */
+status_t onOpenDecryptSession(int uniqueId,
+ DecryptHandle* decryptHandle,
+ const char* uri);
+
+/**
+ * Close the decrypt session for the given handle.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the decryption session
+ * @return status_t
+ * Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
+ */
+status_t onCloseDecryptSession(int uniqueId,
+ DecryptHandle* decryptHandle);
+
+/**
+ * Initialize decryption for the given unit of the protected content.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the decryption session
+ * @param decryptUnitId ID which specifies decryption unit, such as track ID
+ * @param headerInfo Information for initializing decryption of this decrypUnit
+ * @return
+ * DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
+ */
+status_t onInitializeDecryptUnit(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int decryptUnitId,
+ const DrmBuffer* headerInfo);
+
+/**
+ * Decrypt the protected content buffers for the given unit.
+ * This method will be called any number of times, based on number of
+ * encrypted streams received from application.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the decryption session
+ * @param decryptUnitId ID which specifies decryption unit, such as track ID
+ * @param encBuffer Encrypted data block
+ * @param decBuffer Decrypted data block
+ * @return status_t
+ * Returns the error code for this API
+ * DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
+ * DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
+ * DRM_ERROR_DECRYPT for failure.
+ */
+status_t onDecrypt(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int decryptUnitId,
+ const DrmBuffer* encBuffer,
+ DrmBuffer** decBuffer);
+
+/**
+ * Decrypt the protected content buffers for the given unit.
+ * This method will be called any number of times, based on number of
+ * encrypted streams received from application.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptId Handle for the decryption session
+ * @param decryptUnitId ID Specifies decryption unit, such as track ID
+ * @param encBuffer Encrypted data block
+ * @param decBuffer Decrypted data block
+ * @param IV Optional buffer
+ * @return status_t
+ * Returns the error code for this API
+ * DRM_NO_ERROR for success, and one of DRM_ERROR_UNKNOWN, DRM_ERROR_LICENSE_EXPIRED
+ * DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
+ * DRM_ERROR_DECRYPT for failure.
+ */
+status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
+ int decryptUnitId, const DrmBuffer* encBuffer,
+ DrmBuffer** decBuffer, DrmBuffer* IV);
+
+/**
+ * Finalize decryption for the given unit of the protected content.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the decryption session
+ * @param decryptUnitId ID Specifies decryption unit, such as track ID
+ * @return
+ * DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
+ */
+status_t onFinalizeDecryptUnit(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int decryptUnitId);
+
+/**
+ * Reads the specified number of bytes from an open DRM file.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the decryption session
+ * @param buffer Reference to the buffer that should receive the read data.
+ * @param numBytes Number of bytes to read.
+ *
+ * @return Number of bytes read.
+ * @retval -1 Failure.
+ */
+ssize_t onRead(int uniqueId,
+ DecryptHandle* decryptHandle,
+ void* pBuffer,
+ int numBytes);
+
+/**
+ * Updates the file position within an open DRM file.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the decryption session
+ * @param offset Offset with which to update the file position.
+ * @param whence One of SEEK_SET, SEEK_CUR, and SEEK_END.
+ * These constants are defined in unistd.h.
+ *
+ * @return New file position.
+ * @retval ((off_t)-1) Failure.
+ */
+#ifdef USE_64BIT_DRM_API
+off64_t onLseek(int uniqueId,
+ DecryptHandle* decryptHandle,
+ off64_t offset,
+ int whence);
+#else
+off_t onLseek(int uniqueId,
+ DecryptHandle* decryptHandle,
+ off_t offset,
+ int whence);
+#endif
+
+/**
+ * Reads the specified number of bytes from an open DRM file.
+ *
+ * @param uniqueId Unique identifier for a session
+ * @param decryptHandle Handle for the decryption session
+ * @param buffer Reference to the buffer that should receive the read data.
+ * @param numBytes Number of bytes to read.
+ * @param offset Offset with which to update the file position.
+ *
+ * @return Number of bytes read. Returns -1 for Failure.
+ */
+#ifdef USE_64BIT_DRM_API
+ssize_t onPread(int uniqueId,
+ DecryptHandle* decryptHandle,
+ void* buffer,
+ ssize_t numBytes,
+ off64_t offset);
+#else
+ssize_t onPread(int uniqueId,
+ DecryptHandle* decryptHandle,
+ void* buffer,
+ ssize_t numBytes,
+ off_t offset);
+#endif
+
+private:
+
+/**
+ * Session Class for Forward Lock Conversion. An object of this class is created
+ * for every conversion.
+ */
+class ConvertSession {
+ public :
+ int uniqueId;
+ FwdLockConv_Output_t output;
+
+ ConvertSession() {
+ uniqueId = 0;
+ memset(&output, 0, sizeof(FwdLockConv_Output_t));
+ }
+
+ virtual ~ConvertSession() {}
+};
+
+/**
+ * Session Class for Forward Lock decoder. An object of this class is created
+ * for every decoding session.
+ */
+class DecodeSession {
+ public :
+ int fileDesc;
+ off_t offset;
+
+ DecodeSession() {
+ fileDesc = -1;
+ offset = 0;
+ }
+
+ DecodeSession(int fd) {
+ fileDesc = fd;
+ offset = 0;
+ }
+
+ virtual ~DecodeSession() {}
+};
+
+/**
+ * Session Map Tables for Conversion and Decoding of forward lock files.
+ */
+SessionMap<ConvertSession*> convertSessionMap;
+SessionMap<DecodeSession*> decodeSessionMap;
+
+/**
+ * Converts the error code from Forward Lock Converter to DrmConvertStatus error code.
+ *
+ * @param Forward Lock Converter error code
+ *
+ * @return Status code from DrmConvertStatus.
+ */
+static int getConvertedStatus(FwdLockConv_Status_t status);
+};
+
+};
+
+#endif /* __FWDLOCKENGINE_H__ */
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngineConst.h b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngineConst.h
new file mode 100644
index 0000000..da95d60
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngineConst.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FWDLOCKENGINECONST_H__
+#define __FWDLOCKENGINECONST_H__
+
+namespace android {
+
+/**
+ * Constants for forward Lock Engine used for exposing engine's capabilities.
+ */
+#define FWDLOCK_EXTENSION_FL ("FL")
+#define FWDLOCK_DOTEXTENSION_FL (".fl")
+#define FWDLOCK_MIMETYPE_FL ("application/x-android-drm-fl")
+
+#define FWDLOCK_EXTENSION_DM ("DM")
+#define FWDLOCK_DOTEXTENSION_DM (".dm")
+#define FWDLOCK_MIMETYPE_DM ("application/vnd.oma.drm.message")
+
+#define FWDLOCK_DESCRIPTION ("OMA V1 Forward Lock")
+
+};
+
+#endif /* __FWDLOCKENGINECONST_H__ */
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
new file mode 100644
index 0000000..d430f72
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -0,0 +1,628 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "SessionMap.h"
+#include "FwdLockEngine.h"
+#include <utils/Log.h>
+#include <errno.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "drm_framework_common.h"
+#include <fcntl.h>
+#include <limits.h>
+#include <DrmRights.h>
+#include <DrmConstraints.h>
+#include <DrmMetadata.h>
+#include <DrmInfo.h>
+#include <DrmInfoStatus.h>
+#include <DrmInfoRequest.h>
+#include <DrmSupportInfo.h>
+#include <DrmConvertedStatus.h>
+#include <utils/String8.h>
+#include "FwdLockConv.h"
+#include "FwdLockFile.h"
+#include "FwdLockGlue.h"
+#include "FwdLockEngineConst.h"
+#include "MimeTypeUtil.h"
+
+#undef LOG_TAG
+#define LOG_TAG "FwdLockEngine"
+
+using namespace android;
+// This extern "C" is mandatory to be managed by TPlugInManager
+extern "C" IDrmEngine* create() {
+ return new FwdLockEngine();
+}
+
+// This extern "C" is mandatory to be managed by TPlugInManager
+extern "C" void destroy(IDrmEngine* plugIn) {
+ delete plugIn;
+}
+
+FwdLockEngine::FwdLockEngine() {
+ LOGD("FwdLockEngine Construction");
+}
+
+FwdLockEngine::~FwdLockEngine() {
+ LOGD("FwdLockEngine Destruction");
+
+ convertSessionMap.destroyMap();
+ decodeSessionMap.destroyMap();
+}
+
+int FwdLockEngine::getConvertedStatus(FwdLockConv_Status_t status) {
+ int retStatus = DrmConvertedStatus::STATUS_ERROR;
+
+ switch(status) {
+ case FwdLockConv_Status_OK:
+ retStatus = DrmConvertedStatus::STATUS_OK;
+ break;
+ case FwdLockConv_Status_SyntaxError:
+ case FwdLockConv_Status_InvalidArgument:
+ case FwdLockConv_Status_UnsupportedFileFormat:
+ case FwdLockConv_Status_UnsupportedContentTransferEncoding:
+ LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
+ "Returning STATUS_INPUTDATA_ERROR", status);
+ retStatus = DrmConvertedStatus::STATUS_INPUTDATA_ERROR;
+ break;
+ default:
+ LOGD("FwdLockEngine getConvertedStatus: file conversion Error %d. " \
+ "Returning STATUS_ERROR", status);
+ retStatus = DrmConvertedStatus::STATUS_ERROR;
+ break;
+ }
+
+ return retStatus;
+}
+
+DrmConstraints* FwdLockEngine::onGetConstraints(int uniqueId, const String8* path, int action) {
+ DrmConstraints* drmConstraints = NULL;
+
+ LOGD("FwdLockEngine::onGetConstraints");
+
+ if (NULL != path &&
+ (RightsStatus::RIGHTS_VALID == onCheckRightsStatus(uniqueId, *path, action))) {
+ // Return the empty constraints to show no error condition.
+ drmConstraints = new DrmConstraints();
+ }
+
+ return drmConstraints;
+}
+
+DrmMetadata* FwdLockEngine::onGetMetadata(int uniqueId, const String8* path) {
+ DrmMetadata* drmMetadata = NULL;
+
+ LOGD("FwdLockEngine::onGetMetadata");
+
+ if (NULL != path) {
+ // Returns empty metadata to show no error condition.
+ drmMetadata = new DrmMetadata();
+ }
+
+ return drmMetadata;
+}
+
+android::status_t FwdLockEngine::onInitialize(int uniqueId) {
+ LOGD("FwdLockEngine::onInitialize");
+
+
+ if (FwdLockGlue_InitializeKeyEncryption()) {
+ LOGD("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption succeeded");
+ } else {
+ LOGD("FwdLockEngine::onInitialize -- FwdLockGlue_InitializeKeyEncryption failed:"
+ "errno = %d", errno);
+ }
+
+ return DRM_NO_ERROR;
+}
+
+android::status_t
+FwdLockEngine::onSetOnInfoListener(int uniqueId, const IDrmEngine::OnInfoListener* infoListener) {
+ // Not used
+ LOGD("FwdLockEngine::onSetOnInfoListener");
+
+ return DRM_NO_ERROR;
+}
+
+android::status_t FwdLockEngine::onTerminate(int uniqueId) {
+ LOGD("FwdLockEngine::onTerminate");
+
+ return DRM_NO_ERROR;
+}
+
+DrmSupportInfo* FwdLockEngine::onGetSupportInfo(int uniqueId) {
+ DrmSupportInfo* pSupportInfo = new DrmSupportInfo();
+
+ LOGD("FwdLockEngine::onGetSupportInfo");
+
+ // fill all Forward Lock mimetypes and extensions
+ if (NULL != pSupportInfo) {
+ pSupportInfo->addMimeType(String8(FWDLOCK_MIMETYPE_FL));
+ pSupportInfo->addFileSuffix(String8(FWDLOCK_DOTEXTENSION_FL));
+ pSupportInfo->addMimeType(String8(FWDLOCK_MIMETYPE_DM));
+ pSupportInfo->addFileSuffix(String8(FWDLOCK_DOTEXTENSION_DM));
+
+ pSupportInfo->setDescription(String8(FWDLOCK_DESCRIPTION));
+ }
+
+ return pSupportInfo;
+}
+
+bool FwdLockEngine::onCanHandle(int uniqueId, const String8& path) {
+ bool result = false;
+
+ String8 extString = path.getPathExtension();
+
+ extString.toLower();
+
+ if ((extString == String8(FWDLOCK_DOTEXTENSION_FL)) ||
+ (extString == String8(FWDLOCK_DOTEXTENSION_DM))) {
+ result = true;
+ }
+ return result;
+}
+
+DrmInfoStatus* FwdLockEngine::onProcessDrmInfo(int uniqueId, const DrmInfo* drmInfo) {
+ DrmInfoStatus *drmInfoStatus = NULL;
+
+ // Nothing to process
+
+ drmInfoStatus = new DrmInfoStatus((int)DrmInfoStatus::STATUS_OK, 0, NULL, String8(""));
+
+ LOGD("FwdLockEngine::onProcessDrmInfo");
+
+ return drmInfoStatus;
+}
+
+status_t FwdLockEngine::onSaveRights(
+ int uniqueId,
+ const DrmRights& drmRights,
+ const String8& rightsPath,
+ const String8& contentPath) {
+ // No rights to save. Return
+ LOGD("FwdLockEngine::onSaveRights");
+ return DRM_ERROR_UNKNOWN;
+}
+
+DrmInfo* FwdLockEngine::onAcquireDrmInfo(int uniqueId, const DrmInfoRequest* drmInfoRequest) {
+ DrmInfo* drmInfo = NULL;
+
+ // Nothing to be done for Forward Lock file
+ LOGD("FwdLockEngine::onAcquireDrmInfo");
+
+ return drmInfo;
+}
+
+int FwdLockEngine::onCheckRightsStatus(int uniqueId,
+ const String8& path,
+ int action) {
+ int result = RightsStatus::RIGHTS_INVALID;
+
+ LOGD("FwdLockEngine::onCheckRightsStatus");
+
+ // Only Transfer action is not allowed for forward Lock files.
+ if (onCanHandle(uniqueId, path)) {
+ switch(action) {
+ case Action::DEFAULT:
+ case Action::PLAY:
+ case Action::RINGTONE:
+ case Action::OUTPUT:
+ case Action::PREVIEW:
+ case Action::EXECUTE:
+ case Action::DISPLAY:
+ result = RightsStatus::RIGHTS_VALID;
+ break;
+
+ case Action::TRANSFER:
+ default:
+ result = RightsStatus::RIGHTS_INVALID;
+ break;
+ }
+ }
+
+ return result;
+}
+
+status_t FwdLockEngine::onConsumeRights(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int action,
+ bool reserve) {
+ // No rights consumption
+ LOGD("FwdLockEngine::onConsumeRights");
+ return DRM_NO_ERROR;
+}
+
+bool FwdLockEngine::onValidateAction(int uniqueId,
+ const String8& path,
+ int action,
+ const ActionDescription& description) {
+ LOGD("FwdLockEngine::onValidateAction");
+
+ // For the forwardlock engine checkRights and ValidateAction are the same.
+ return (onCheckRightsStatus(uniqueId, path, action) == RightsStatus::RIGHTS_VALID);
+}
+
+String8 FwdLockEngine::onGetOriginalMimeType(int uniqueId, const String8& path) {
+ LOGD("FwdLockEngine::onGetOriginalMimeType");
+ String8 mimeString = String8("");
+ int fileDesc = FwdLockFile_open(path.string());
+
+ if (-1 < fileDesc) {
+ const char* pMimeType = FwdLockFile_GetContentType(fileDesc);
+
+ if (NULL != pMimeType) {
+ String8 contentType = String8(pMimeType);
+ contentType.toLower();
+ mimeString = MimeTypeUtil::convertMimeType(contentType);
+ }
+
+ FwdLockFile_close(fileDesc);
+ }
+
+ return mimeString;
+}
+
+int FwdLockEngine::onGetDrmObjectType(int uniqueId,
+ const String8& path,
+ const String8& mimeType) {
+ String8 mimeStr = String8(mimeType);
+
+ LOGD("FwdLockEngine::onGetDrmObjectType");
+
+ mimeStr.toLower();
+
+ /* Checks whether
+ * 1. path and mime type both are not empty strings (meaning unavailable) else content is unknown
+ * 2. if one of them is empty string and if other is known then its a DRM Content Object.
+ * 3. if both of them are available, then both may be of known type
+ * (regardless of the relation between them to make it compatible with other DRM Engines)
+ */
+ if (((0 == path.length()) || onCanHandle(uniqueId, path)) &&
+ ((0 == mimeType.length()) || ((mimeStr == String8(FWDLOCK_MIMETYPE_FL)) ||
+ (mimeStr == String8(FWDLOCK_MIMETYPE_DM)))) && (mimeType != path) ) {
+ return DrmObjectType::CONTENT;
+ }
+
+ return DrmObjectType::UNKNOWN;
+}
+
+status_t FwdLockEngine::onRemoveRights(int uniqueId, const String8& path) {
+ // No Rights to remove
+ LOGD("FwdLockEngine::onRemoveRights");
+ return DRM_NO_ERROR;
+}
+
+status_t FwdLockEngine::onRemoveAllRights(int uniqueId) {
+ // No rights to remove
+ LOGD("FwdLockEngine::onRemoveAllRights");
+ return DRM_NO_ERROR;
+}
+
+#ifdef USE_64BIT_DRM_API
+status_t FwdLockEngine::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+ int playbackStatus, int64_t position) {
+#else
+status_t FwdLockEngine::onSetPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+ int playbackStatus, int position) {
+#endif
+ // Not used
+ LOGD("FwdLockEngine::onSetPlaybackStatus");
+ return DRM_NO_ERROR;
+}
+
+status_t FwdLockEngine::onOpenConvertSession(int uniqueId,
+ int convertId) {
+ status_t result = DRM_ERROR_UNKNOWN;
+ LOGD("FwdLockEngine::onOpenConvertSession");
+ if (!convertSessionMap.isCreated(convertId)) {
+ ConvertSession *newSession = new ConvertSession();
+ if (FwdLockConv_Status_OK ==
+ FwdLockConv_OpenSession(&(newSession->uniqueId), &(newSession->output))) {
+ convertSessionMap.addValue(convertId, newSession);
+ result = DRM_NO_ERROR;
+ } else {
+ LOGD("FwdLockEngine::onOpenConvertSession -- FwdLockConv_OpenSession failed.");
+ delete newSession;
+ }
+ }
+ return result;
+}
+
+DrmConvertedStatus* FwdLockEngine::onConvertData(int uniqueId,
+ int convertId,
+ const DrmBuffer* inputData) {
+ FwdLockConv_Status_t retStatus = FwdLockConv_Status_InvalidArgument;
+ DrmBuffer *convResult = new DrmBuffer(NULL, 0);
+ int offset = -1;
+
+ if (NULL != inputData && convertSessionMap.isCreated(convertId)) {
+ ConvertSession *convSession = convertSessionMap.getValue(convertId);
+
+ if (NULL != convSession) {
+ retStatus = FwdLockConv_ConvertData(convSession->uniqueId,
+ inputData->data,
+ inputData->length,
+ &(convSession->output));
+
+ if (FwdLockConv_Status_OK == retStatus) {
+ // return bytes from conversion if available
+ if (convSession->output.fromConvertData.numBytes > 0) {
+ convResult->data = new char[convSession->output.fromConvertData.numBytes];
+
+ if (NULL != convResult->data) {
+ convResult->length = convSession->output.fromConvertData.numBytes;
+ memcpy(convResult->data,
+ (char *)convSession->output.fromConvertData.pBuffer,
+ convResult->length);
+ }
+ }
+ } else {
+ offset = convSession->output.fromConvertData.errorPos;
+ }
+ }
+ }
+ return new DrmConvertedStatus(getConvertedStatus(retStatus), convResult, offset);
+}
+
+DrmConvertedStatus* FwdLockEngine::onCloseConvertSession(int uniqueId,
+ int convertId) {
+ FwdLockConv_Status_t retStatus = FwdLockConv_Status_InvalidArgument;
+ DrmBuffer *convResult = new DrmBuffer(NULL, 0);
+ int offset = -1;
+
+ LOGD("FwdLockEngine::onCloseConvertSession");
+
+ if (convertSessionMap.isCreated(convertId)) {
+ ConvertSession *convSession = convertSessionMap.getValue(convertId);
+
+ if (NULL != convSession) {
+ retStatus = FwdLockConv_CloseSession(convSession->uniqueId, &(convSession->output));
+
+ if (FwdLockConv_Status_OK == retStatus) {
+ offset = convSession->output.fromCloseSession.fileOffset;
+ convResult->data = new char[FWD_LOCK_SIGNATURES_SIZE];
+
+ if (NULL != convResult->data) {
+ convResult->length = FWD_LOCK_SIGNATURES_SIZE;
+ memcpy(convResult->data,
+ (char *)convSession->output.fromCloseSession.signatures,
+ convResult->length);
+ }
+ }
+ }
+ convertSessionMap.removeValue(convertId);
+ }
+ return new DrmConvertedStatus(getConvertedStatus(retStatus), convResult, offset);
+}
+
+#ifdef USE_64BIT_DRM_API
+status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int fd,
+ off64_t offset,
+ off64_t length) {
+#else
+status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int fd,
+ int offset,
+ int length) {
+#endif
+ status_t result = DRM_ERROR_CANNOT_HANDLE;
+ int fileDesc = -1;
+
+ LOGD("FwdLockEngine::onOpenDecryptSession");
+
+ if ((-1 < fd) &&
+ (NULL != decryptHandle) &&
+ (!decodeSessionMap.isCreated(decryptHandle->decryptId))) {
+ fileDesc = dup(fd);
+ } else {
+ LOGD("FwdLockEngine::onOpenDecryptSession parameter error");
+ return result;
+ }
+
+ if (-1 < fileDesc &&
+ -1 < ::lseek(fileDesc, offset, SEEK_SET) &&
+ -1 < FwdLockFile_attach(fileDesc)) {
+ // check for file integrity. This must be done to protect the content mangling.
+ int retVal = FwdLockFile_CheckHeaderIntegrity(fileDesc);
+ DecodeSession* decodeSession = new DecodeSession(fileDesc);
+
+ if (retVal && NULL != decodeSession) {
+ decodeSessionMap.addValue(decryptHandle->decryptId, decodeSession);
+ const char *pmime= FwdLockFile_GetContentType(fileDesc);
+ String8 contentType = String8(pmime == NULL ? "" : pmime);
+ contentType.toLower();
+ decryptHandle->mimeType = MimeTypeUtil::convertMimeType(contentType);
+ decryptHandle->decryptApiType = DecryptApiType::CONTAINER_BASED;
+ decryptHandle->status = RightsStatus::RIGHTS_VALID;
+ decryptHandle->decryptInfo = NULL;
+ result = DRM_NO_ERROR;
+ } else {
+ LOGD("FwdLockEngine::onOpenDecryptSession Integrity Check failed for the fd");
+ FwdLockFile_detach(fileDesc);
+ ::close(fileDesc);
+ delete decodeSession;
+ }
+ }
+
+ LOGD("FwdLockEngine::onOpenDecryptSession Exit. result = %d", result);
+
+ return result;
+}
+
+status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
+ DecryptHandle* decryptHandle,
+ const char* uri) {
+ status_t result = DRM_ERROR_CANNOT_HANDLE;
+ const char fileTag [] = "file://";
+
+ if (NULL != decryptHandle && NULL != uri && strlen(uri) > sizeof(fileTag)) {
+ String8 uriTag = String8(uri);
+ uriTag.toLower();
+
+ if (0 == strncmp(uriTag.string(), fileTag, sizeof(fileTag) - 1)) {
+ const char *filePath = strchr(uri + sizeof(fileTag) - 1, '/');
+ if (NULL != filePath && onCanHandle(uniqueId, String8(filePath))) {
+ int fd = open(filePath, O_RDONLY);
+
+ if (-1 < fd) {
+ // offset is always 0 and length is not used. so any positive size.
+ result = onOpenDecryptSession(uniqueId, decryptHandle, fd, 0, 1);
+
+ // fd is duplicated already if success. closing the file
+ close(fd);
+ }
+ }
+ }
+ }
+
+ return result;
+}
+
+status_t FwdLockEngine::onCloseDecryptSession(int uniqueId,
+ DecryptHandle* decryptHandle) {
+ status_t result = DRM_ERROR_UNKNOWN;
+ LOGD("FwdLockEngine::onCloseDecryptSession");
+
+ if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
+ DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
+ if (NULL != session && session->fileDesc > -1) {
+ FwdLockFile_detach(session->fileDesc);
+ ::close(session->fileDesc);
+ decodeSessionMap.removeValue(decryptHandle->decryptId);
+ result = DRM_NO_ERROR;
+ }
+ }
+
+ LOGD("FwdLockEngine::onCloseDecryptSession Exit");
+ return result;
+}
+
+status_t FwdLockEngine::onInitializeDecryptUnit(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int decryptUnitId,
+ const DrmBuffer* headerInfo) {
+ LOGD("FwdLockEngine::onInitializeDecryptUnit");
+ return DRM_ERROR_UNKNOWN;
+}
+
+status_t FwdLockEngine::onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
+ LOGD("FwdLockEngine::onDecrypt");
+ return DRM_ERROR_UNKNOWN;
+}
+
+status_t FwdLockEngine::onDecrypt(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int decryptUnitId,
+ const DrmBuffer* encBuffer,
+ DrmBuffer** decBuffer) {
+ LOGD("FwdLockEngine::onDecrypt");
+ return DRM_ERROR_UNKNOWN;
+}
+
+status_t FwdLockEngine::onFinalizeDecryptUnit(int uniqueId,
+ DecryptHandle* decryptHandle,
+ int decryptUnitId) {
+ LOGD("FwdLockEngine::onFinalizeDecryptUnit");
+ return DRM_ERROR_UNKNOWN;
+}
+
+ssize_t FwdLockEngine::onRead(int uniqueId,
+ DecryptHandle* decryptHandle,
+ void* buffer,
+ int numBytes) {
+ ssize_t size = -1;
+
+ if (NULL != decryptHandle &&
+ decodeSessionMap.isCreated(decryptHandle->decryptId) &&
+ NULL != buffer &&
+ numBytes > -1) {
+ DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
+ if (NULL != session && session->fileDesc > -1) {
+ size = FwdLockFile_read(session->fileDesc, buffer, numBytes);
+
+ if (0 > size) {
+ session->offset = ((off_t)-1);
+ } else {
+ session->offset += size;
+ }
+ }
+ }
+
+ return size;
+}
+
+#ifdef USE_64BIT_DRM_API
+off64_t FwdLockEngine::onLseek(int uniqueId, DecryptHandle* decryptHandle,
+ off64_t offset, int whence) {
+#else
+off_t FwdLockEngine::onLseek(int uniqueId, DecryptHandle* decryptHandle,
+ off_t offset, int whence) {
+#endif
+ off_t offval = -1;
+
+ if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
+ DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
+ if (NULL != session && session->fileDesc > -1) {
+ offval = FwdLockFile_lseek(session->fileDesc, offset, whence);
+ session->offset = offval;
+ }
+ }
+
+ return offval;
+}
+
+#ifdef USE_64BIT_DRM_API
+ssize_t FwdLockEngine::onPread(int uniqueId,
+ DecryptHandle* decryptHandle,
+ void* buffer,
+ ssize_t numBytes,
+ off64_t offset) {
+#else
+ssize_t FwdLockEngine::onPread(int uniqueId,
+ DecryptHandle* decryptHandle,
+ void* buffer,
+ ssize_t numBytes,
+ off_t offset) {
+#endif
+ ssize_t bytesRead = -1;
+
+ DecodeSession* decoderSession = NULL;
+
+ if ((NULL != decryptHandle) &&
+ (NULL != (decoderSession = decodeSessionMap.getValue(decryptHandle->decryptId))) &&
+ (NULL != buffer) &&
+ (numBytes > -1) &&
+ (offset > -1)) {
+ if (offset != decoderSession->offset) {
+ decoderSession->offset = onLseek(uniqueId, decryptHandle, offset, SEEK_SET);
+ }
+
+ if (((off_t)-1) != decoderSession->offset) {
+ bytesRead = onRead(uniqueId, decryptHandle, buffer, numBytes);
+ if (bytesRead < 0) {
+ LOGD("FwdLockEngine::onPread error reading");
+ }
+ }
+ } else {
+ LOGD("FwdLockEngine::onPread decryptId not found");
+ }
+
+ return bytesRead;
+}
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/Android.mk
new file mode 100644
index 0000000..9ee7961
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/Android.mk
@@ -0,0 +1,16 @@
+#
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+include $(call all-subdir-makefiles)
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk
new file mode 100644
index 0000000..6c5d3cf
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/common/Android.mk
@@ -0,0 +1,32 @@
+#
+# 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.
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ FwdLockGlue.c
+
+LOCAL_C_INCLUDES := \
+ external/openssl/include
+
+LOCAL_SHARED_LIBRARIES := libcrypto
+
+LOCAL_MODULE := libfwdlock-common
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/FwdLockGlue.c b/drm/libdrmframework/plugins/forward-lock/internal-format/common/FwdLockGlue.c
new file mode 100644
index 0000000..92bda8ff
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/common/FwdLockGlue.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <openssl/aes.h>
+
+#include "FwdLockGlue.h"
+
+#define TRUE 1
+#define FALSE 0
+
+#define KEY_SIZE 16
+#define KEY_SIZE_IN_BITS (KEY_SIZE * 8)
+
+static int isInitialized = FALSE;
+
+static const char strKeyFilename[] = "/data/drm/fwdlock/kek.dat";
+
+static AES_KEY encryptionRoundKeys;
+static AES_KEY decryptionRoundKeys;
+
+/**
+ * Creates all directories along the fully qualified path of the given file.
+ *
+ * @param[in] path A reference to the fully qualified path of a file.
+ * @param[in] mode The access mode to use for the directories being created.
+ *
+ * @return A Boolean value indicating whether the operation was successful.
+ */
+static int FwdLockGlue_CreateDirectories(const char *path, mode_t mode) {
+ int result = TRUE;
+ size_t partialPathLength = strlen(path);
+ char *partialPath = malloc(partialPathLength + 1);
+ if (partialPath == NULL) {
+ result = FALSE;
+ } else {
+ size_t i;
+ for (i = 0; i < partialPathLength; ++i) {
+ if (path[i] == '/' && i > 0) {
+ partialPath[i] = '\0';
+ if (mkdir(partialPath, mode) != 0 && errno != EEXIST) {
+ result = FALSE;
+ break;
+ }
+ }
+ partialPath[i] = path[i];
+ }
+ free(partialPath);
+ }
+ return result;
+}
+
+/**
+ * Initializes the round keys used for encryption and decryption of session keys. First creates a
+ * device-unique key-encryption key if none exists yet.
+ */
+static void FwdLockGlue_InitializeRoundKeys() {
+ unsigned char keyEncryptionKey[KEY_SIZE];
+ int fileDesc = open(strKeyFilename, O_RDONLY);
+ if (fileDesc >= 0) {
+ if (read(fileDesc, keyEncryptionKey, KEY_SIZE) == KEY_SIZE) {
+ isInitialized = TRUE;
+ }
+ (void)close(fileDesc);
+ } else if (errno == ENOENT &&
+ FwdLockGlue_GetRandomNumber(keyEncryptionKey, KEY_SIZE) &&
+ FwdLockGlue_CreateDirectories(strKeyFilename, S_IRWXU)) {
+ fileDesc = open(strKeyFilename, O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR);
+ if (fileDesc >= 0) {
+ if (write(fileDesc, keyEncryptionKey, KEY_SIZE) == KEY_SIZE) {
+ isInitialized = TRUE;
+ }
+ (void)close(fileDesc);
+ }
+ }
+ if (isInitialized) {
+ if (AES_set_encrypt_key(keyEncryptionKey, KEY_SIZE_IN_BITS, &encryptionRoundKeys) != 0 ||
+ AES_set_decrypt_key(keyEncryptionKey, KEY_SIZE_IN_BITS, &decryptionRoundKeys) != 0) {
+ isInitialized = FALSE;
+ }
+ }
+ memset(keyEncryptionKey, 0, KEY_SIZE); // Zero out key data.
+}
+
+/**
+ * Validates the padding of a decrypted key.
+ *
+ * @param[in] pData A reference to the buffer containing the decrypted key and padding.
+ * @param[in] decryptedKeyLength The length in bytes of the decrypted key.
+ *
+ * @return A Boolean value indicating whether the padding was valid.
+ */
+static int FwdLockGlue_ValidatePadding(const unsigned char *pData, size_t decryptedKeyLength) {
+ size_t i;
+ size_t padding = AES_BLOCK_SIZE - (decryptedKeyLength % AES_BLOCK_SIZE);
+ pData += decryptedKeyLength;
+ for (i = 0; i < padding; ++i) {
+ if ((size_t)*pData != padding) {
+ return FALSE;
+ }
+ ++pData;
+ }
+ return TRUE;
+}
+
+int FwdLockGlue_GetRandomNumber(void *pBuffer, size_t numBytes) {
+ // Generate 'cryptographically secure' random bytes by reading them from "/dev/urandom" (the
+ // non-blocking version of "/dev/random").
+ ssize_t numBytesRead = 0;
+ int fileDesc = open("/dev/urandom", O_RDONLY);
+ if (fileDesc >= 0) {
+ numBytesRead = read(fileDesc, pBuffer, numBytes);
+ (void)close(fileDesc);
+ }
+ return numBytesRead >= 0 && (size_t)numBytesRead == numBytes;
+}
+
+int FwdLockGlue_InitializeKeyEncryption() {
+ static pthread_once_t once = PTHREAD_ONCE_INIT;
+ pthread_once(&once, FwdLockGlue_InitializeRoundKeys);
+ return isInitialized;
+}
+
+size_t FwdLockGlue_GetEncryptedKeyLength(size_t plaintextKeyLength) {
+ return ((plaintextKeyLength / AES_BLOCK_SIZE) + 2) * AES_BLOCK_SIZE;
+}
+
+int FwdLockGlue_EncryptKey(const void *pPlaintextKey,
+ size_t plaintextKeyLength,
+ void *pEncryptedKey,
+ size_t encryptedKeyLength) {
+ int result = FALSE;
+ assert(encryptedKeyLength == FwdLockGlue_GetEncryptedKeyLength(plaintextKeyLength));
+ if (FwdLockGlue_InitializeKeyEncryption()) {
+ unsigned char initVector[AES_BLOCK_SIZE];
+ if (FwdLockGlue_GetRandomNumber(initVector, AES_BLOCK_SIZE)) {
+ size_t padding = AES_BLOCK_SIZE - (plaintextKeyLength % AES_BLOCK_SIZE);
+ size_t dataLength = encryptedKeyLength - AES_BLOCK_SIZE;
+ memcpy(pEncryptedKey, pPlaintextKey, plaintextKeyLength);
+ memset((unsigned char *)pEncryptedKey + plaintextKeyLength, (int)padding, padding);
+ memcpy((unsigned char *)pEncryptedKey + dataLength, initVector, AES_BLOCK_SIZE);
+ AES_cbc_encrypt(pEncryptedKey, pEncryptedKey, dataLength, &encryptionRoundKeys,
+ initVector, AES_ENCRYPT);
+ result = TRUE;
+ }
+ }
+ return result;
+}
+
+int FwdLockGlue_DecryptKey(const void *pEncryptedKey,
+ size_t encryptedKeyLength,
+ void *pDecryptedKey,
+ size_t decryptedKeyLength) {
+ int result = FALSE;
+ assert(encryptedKeyLength == FwdLockGlue_GetEncryptedKeyLength(decryptedKeyLength));
+ if (FwdLockGlue_InitializeKeyEncryption()) {
+ size_t dataLength = encryptedKeyLength - AES_BLOCK_SIZE;
+ unsigned char *pData = malloc(dataLength);
+ if (pData != NULL) {
+ unsigned char initVector[AES_BLOCK_SIZE];
+ memcpy(pData, pEncryptedKey, dataLength);
+ memcpy(initVector, (const unsigned char *)pEncryptedKey + dataLength, AES_BLOCK_SIZE);
+ AES_cbc_encrypt(pData, pData, dataLength, &decryptionRoundKeys, initVector,
+ AES_DECRYPT);
+ memcpy(pDecryptedKey, pData, decryptedKeyLength);
+ result = FwdLockGlue_ValidatePadding(pData, decryptedKeyLength);
+ free(pData);
+ }
+ }
+ return result;
+}
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/common/FwdLockGlue.h b/drm/libdrmframework/plugins/forward-lock/internal-format/common/FwdLockGlue.h
new file mode 100644
index 0000000..f36f6ea
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/common/FwdLockGlue.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FWDLOCKGLUE_H__
+#define __FWDLOCKGLUE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * Generates the specified number of cryptographically secure random bytes.
+ *
+ * @param[out] pBuffer A reference to the buffer that should receive the random data.
+ * @param[in] numBytes The number of random bytes to generate.
+ *
+ * @return A Boolean value indicating whether the operation was successful.
+ */
+int FwdLockGlue_GetRandomNumber(void *pBuffer, size_t numBytes);
+
+/**
+ * Performs initialization of the key-encryption key. Should be called once during startup to
+ * facilitate encryption and decryption of session keys.
+ *
+ * @return A Boolean value indicating whether the operation was successful.
+ */
+int FwdLockGlue_InitializeKeyEncryption();
+
+/**
+ * Returns the length of the encrypted key, given the length of the plaintext key.
+ *
+ * @param[in] plaintextKeyLength The length in bytes of the plaintext key.
+ *
+ * @return The length in bytes of the encrypted key.
+ */
+size_t FwdLockGlue_GetEncryptedKeyLength(size_t plaintextKeyLength);
+
+/**
+ * Encrypts the given session key using a key-encryption key unique to this device.
+ *
+ * @param[in] pPlaintextKey A reference to the buffer containing the plaintext key.
+ * @param[in] plaintextKeyLength The length in bytes of the plaintext key.
+ * @param[out] pEncryptedKey A reference to the buffer containing the encrypted key.
+ * @param[in] encryptedKeyLength The length in bytes of the encrypted key.
+ *
+ * @return A Boolean value indicating whether the operation was successful.
+ */
+int FwdLockGlue_EncryptKey(const void *pPlaintextKey,
+ size_t plaintextKeyLength,
+ void *pEncryptedKey,
+ size_t encryptedKeyLength);
+
+/**
+ * Decrypts the given session key using a key-encryption key unique to this device.
+ *
+ * @param[in] pEncryptedKey A reference to the buffer containing the encrypted key.
+ * @param[in] encryptedKeyLength The length in bytes of the encrypted key.
+ * @param[out] pDecryptedKey A reference to the buffer containing the decrypted key.
+ * @param[in] decryptedKeyLength The length in bytes of the decrypted key.
+ *
+ * @return A Boolean value indicating whether the operation was successful.
+ */
+int FwdLockGlue_DecryptKey(const void *pEncryptedKey,
+ size_t encryptedKeyLength,
+ void *pDecryptedKey,
+ size_t decryptedKeyLength);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __FWDLOCKGLUE_H__
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk
new file mode 100644
index 0000000..00bb788
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/Android.mk
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ FwdLockConv.c
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/drm/libdrmframework/plugins/forward-lock/internal-format/common \
+ external/openssl/include
+
+LOCAL_SHARED_LIBRARIES := libcrypto
+
+LOCAL_WHOLE_STATIC_LIBRARIES := libfwdlock-common
+
+LOCAL_STATIC_LIBRARIES := libfwdlock-common
+
+LOCAL_MODULE := libfwdlock-converter
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
new file mode 100644
index 0000000..14ea9e9
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.c
@@ -0,0 +1,1339 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <openssl/aes.h>
+#include <openssl/hmac.h>
+
+#include "FwdLockConv.h"
+#include "FwdLockGlue.h"
+
+#define TRUE 1
+#define FALSE 0
+
+#define INVALID_OFFSET ((off64_t)-1)
+
+#define MAX_NUM_SESSIONS 32
+
+#define OUTPUT_BUFFER_SIZE_INCREMENT 1024
+#define READ_BUFFER_SIZE 1024
+
+#define MAX_BOUNDARY_LENGTH 70
+#define MAX_DELIMITER_LENGTH (MAX_BOUNDARY_LENGTH + 4)
+
+#define STRING_LENGTH_INCREMENT 25
+
+#define KEY_SIZE AES_BLOCK_SIZE
+#define KEY_SIZE_IN_BITS (KEY_SIZE * 8)
+
+#define SHA1_HASH_SIZE 20
+
+#define FWD_LOCK_VERSION 0
+#define FWD_LOCK_SUBFORMAT 0
+#define USAGE_RESTRICTION_FLAGS 0
+#define CONTENT_TYPE_LENGTH_POS 7
+#define TOP_HEADER_SIZE 8
+
+/**
+ * Data type for the parser states of the converter.
+ */
+typedef enum FwdLockConv_ParserState {
+ FwdLockConv_ParserState_WantsOpenDelimiter,
+ FwdLockConv_ParserState_WantsMimeHeaders,
+ FwdLockConv_ParserState_WantsBinaryEncodedData,
+ FwdLockConv_ParserState_WantsBase64EncodedData,
+ FwdLockConv_ParserState_Done
+} FwdLockConv_ParserState_t;
+
+/**
+ * Data type for the scanner states of the converter.
+ */
+typedef enum FwdLockConv_ScannerState {
+ FwdLockConv_ScannerState_WantsFirstDash,
+ FwdLockConv_ScannerState_WantsSecondDash,
+ FwdLockConv_ScannerState_WantsCR,
+ FwdLockConv_ScannerState_WantsLF,
+ FwdLockConv_ScannerState_WantsBoundary,
+ FwdLockConv_ScannerState_WantsBoundaryEnd,
+ FwdLockConv_ScannerState_WantsMimeHeaderNameStart,
+ FwdLockConv_ScannerState_WantsMimeHeaderName,
+ FwdLockConv_ScannerState_WantsMimeHeaderNameEnd,
+ FwdLockConv_ScannerState_WantsContentTypeStart,
+ FwdLockConv_ScannerState_WantsContentType,
+ FwdLockConv_ScannerState_WantsContentTransferEncodingStart,
+ FwdLockConv_ScannerState_Wants_A_OR_I,
+ FwdLockConv_ScannerState_Wants_N,
+ FwdLockConv_ScannerState_Wants_A,
+ FwdLockConv_ScannerState_Wants_R,
+ FwdLockConv_ScannerState_Wants_Y,
+ FwdLockConv_ScannerState_Wants_S,
+ FwdLockConv_ScannerState_Wants_E,
+ FwdLockConv_ScannerState_Wants_6,
+ FwdLockConv_ScannerState_Wants_4,
+ FwdLockConv_ScannerState_Wants_B,
+ FwdLockConv_ScannerState_Wants_I,
+ FwdLockConv_ScannerState_Wants_T,
+ FwdLockConv_ScannerState_WantsContentTransferEncodingEnd,
+ FwdLockConv_ScannerState_WantsMimeHeaderValueEnd,
+ FwdLockConv_ScannerState_WantsMimeHeadersEnd,
+ FwdLockConv_ScannerState_WantsByte1,
+ FwdLockConv_ScannerState_WantsByte1_AfterCRLF,
+ FwdLockConv_ScannerState_WantsByte2,
+ FwdLockConv_ScannerState_WantsByte3,
+ FwdLockConv_ScannerState_WantsByte4,
+ FwdLockConv_ScannerState_WantsPadding,
+ FwdLockConv_ScannerState_WantsWhitespace,
+ FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF,
+ FwdLockConv_ScannerState_WantsDelimiter
+} FwdLockConv_ScannerState_t;
+
+/**
+ * Data type for the content transfer encoding.
+ */
+typedef enum FwdLockConv_ContentTransferEncoding {
+ FwdLockConv_ContentTransferEncoding_Undefined,
+ FwdLockConv_ContentTransferEncoding_Binary,
+ FwdLockConv_ContentTransferEncoding_Base64
+} FwdLockConv_ContentTransferEncoding_t;
+
+/**
+ * Data type for a dynamically growing string.
+ */
+typedef struct FwdLockConv_String {
+ char *ptr;
+ size_t length;
+ size_t maxLength;
+ size_t lengthIncrement;
+} FwdLockConv_String_t;
+
+/**
+ * Data type for the per-file state information needed by the converter.
+ */
+typedef struct FwdLockConv_Session {
+ FwdLockConv_ParserState_t parserState;
+ FwdLockConv_ScannerState_t scannerState;
+ FwdLockConv_ScannerState_t savedScannerState;
+ off64_t numCharsConsumed;
+ char delimiter[MAX_DELIMITER_LENGTH];
+ size_t delimiterLength;
+ size_t delimiterMatchPos;
+ FwdLockConv_String_t mimeHeaderName;
+ FwdLockConv_String_t contentType;
+ FwdLockConv_ContentTransferEncoding_t contentTransferEncoding;
+ unsigned char sessionKey[KEY_SIZE];
+ void *pEncryptedSessionKey;
+ size_t encryptedSessionKeyLength;
+ AES_KEY encryptionRoundKeys;
+ HMAC_CTX signingContext;
+ unsigned char topHeader[TOP_HEADER_SIZE];
+ unsigned char counter[AES_BLOCK_SIZE];
+ unsigned char keyStream[AES_BLOCK_SIZE];
+ int keyStreamIndex;
+ unsigned char ch;
+ size_t outputBufferSize;
+ size_t dataOffset;
+ size_t numDataBytes;
+} FwdLockConv_Session_t;
+
+static FwdLockConv_Session_t *sessionPtrs[MAX_NUM_SESSIONS] = { NULL };
+
+static pthread_mutex_t sessionAcquisitionMutex = PTHREAD_MUTEX_INITIALIZER;
+
+static const FwdLockConv_String_t nullString = { NULL, 0, 0, STRING_LENGTH_INCREMENT };
+
+static const unsigned char topHeaderTemplate[] =
+ { 'F', 'W', 'L', 'K', FWD_LOCK_VERSION, FWD_LOCK_SUBFORMAT, USAGE_RESTRICTION_FLAGS };
+
+static const char strContent[] = "content-";
+static const char strType[] = "type";
+static const char strTransferEncoding[] = "transfer-encoding";
+static const char strTextPlain[] = "text/plain";
+static const char strApplicationVndOmaDrmRightsXml[] = "application/vnd.oma.drm.rights+xml";
+static const char strApplicationVndOmaDrmContent[] = "application/vnd.oma.drm.content";
+
+static const size_t strlenContent = sizeof strContent - 1;
+static const size_t strlenTextPlain = sizeof strTextPlain - 1;
+
+static const signed char base64Values[] = {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
+ 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -2, -1, -1,
+ -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
+ -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51
+};
+
+/**
+ * Acquires an unused converter session.
+ *
+ * @return A session ID.
+ */
+static int FwdLockConv_AcquireSession() {
+ int sessionId = -1;
+ int i;
+ pthread_mutex_lock(&sessionAcquisitionMutex);
+ for (i = 0; i < MAX_NUM_SESSIONS; ++i) {
+ if (sessionPtrs[i] == NULL) {
+ sessionPtrs[i] = malloc(sizeof *sessionPtrs[i]);
+ if (sessionPtrs[i] != NULL) {
+ sessionId = i;
+ }
+ break;
+ }
+ }
+ pthread_mutex_unlock(&sessionAcquisitionMutex);
+ return sessionId;
+}
+
+/**
+ * Checks whether a session ID is in range and currently in use.
+ *
+ * @param[in] sessionID A session ID.
+ *
+ * @return A Boolean value indicating whether the session ID is in range and currently in use.
+ */
+static int FwdLockConv_IsValidSession(int sessionId) {
+ return 0 <= sessionId && sessionId < MAX_NUM_SESSIONS && sessionPtrs[sessionId] != NULL;
+}
+
+/**
+ * Releases a converter session.
+ *
+ * @param[in] sessionID A session ID.
+ */
+static void FwdLockConv_ReleaseSession(int sessionId) {
+ pthread_mutex_lock(&sessionAcquisitionMutex);
+ assert(FwdLockConv_IsValidSession(sessionId));
+ memset(sessionPtrs[sessionId], 0, sizeof *sessionPtrs[sessionId]); // Zero out key data.
+ free(sessionPtrs[sessionId]);
+ sessionPtrs[sessionId] = NULL;
+ pthread_mutex_unlock(&sessionAcquisitionMutex);
+}
+
+/**
+ * Derives cryptographically independent keys for encryption and signing from the session key.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ *
+ * @return A status code.
+ */
+static int FwdLockConv_DeriveKeys(FwdLockConv_Session_t *pSession) {
+ FwdLockConv_Status_t status;
+ struct FwdLockConv_DeriveKeys_Data {
+ AES_KEY sessionRoundKeys;
+ unsigned char value[KEY_SIZE];
+ unsigned char key[KEY_SIZE];
+ } *pData = malloc(sizeof *pData);
+ if (pData == NULL) {
+ status = FwdLockConv_Status_OutOfMemory;
+ } else {
+ if (AES_set_encrypt_key(pSession->sessionKey, KEY_SIZE_IN_BITS,
+ &pData->sessionRoundKeys) != 0) {
+ status = FwdLockConv_Status_ProgramError;
+ } else {
+ // Encrypt the 16-byte value {0, 0, ..., 0} to produce the encryption key.
+ memset(pData->value, 0, KEY_SIZE);
+ AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys);
+ if (AES_set_encrypt_key(pData->key, KEY_SIZE_IN_BITS,
+ &pSession->encryptionRoundKeys) != 0) {
+ status = FwdLockConv_Status_ProgramError;
+ } else {
+ // Encrypt the 16-byte value {1, 0, ..., 0} to produce the signing key.
+ ++pData->value[0];
+ AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys);
+ HMAC_CTX_init(&pSession->signingContext);
+ HMAC_Init_ex(&pSession->signingContext, pData->key, KEY_SIZE, EVP_sha1(), NULL);
+ status = FwdLockConv_Status_OK;
+ }
+ }
+ memset(pData, 0, sizeof pData); // Zero out key data.
+ free(pData);
+ }
+ return status;
+}
+
+/**
+ * Checks whether a given character is valid in a boundary. Note that the boundary may contain
+ * leading and internal spaces.
+ *
+ * @param[in] ch The character to check.
+ *
+ * @return A Boolean value indicating whether the given character is valid in a boundary.
+ */
+static int FwdLockConv_IsBoundaryChar(int ch) {
+ return isalnum(ch) || ch == '\'' ||
+ ch == '(' || ch == ')' || ch == '+' || ch == '_' || ch == ',' || ch == '-' ||
+ ch == '.' || ch == '/' || ch == ':' || ch == '=' || ch == '?' || ch == ' ';
+}
+
+/**
+ * Checks whether a given character should be considered whitespace, using a narrower definition
+ * than the standard-library isspace() function.
+ *
+ * @param[in] ch The character to check.
+ *
+ * @return A Boolean value indicating whether the given character should be considered whitespace.
+ */
+static int FwdLockConv_IsWhitespace(int ch) {
+ return ch == ' ' || ch == '\t';
+}
+
+/**
+ * Removes trailing spaces from the delimiter.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_RightTrimDelimiter(FwdLockConv_Session_t *pSession) {
+ while (pSession->delimiterLength > 4 &&
+ pSession->delimiter[pSession->delimiterLength - 1] == ' ') {
+ --pSession->delimiterLength;
+ }
+ if (pSession->delimiterLength > 4) {
+ return FwdLockConv_Status_OK;
+ }
+ return FwdLockConv_Status_SyntaxError;
+}
+
+/**
+ * Matches the open delimiter.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ * @param[in] ch A character.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_MatchOpenDelimiter(FwdLockConv_Session_t *pSession,
+ int ch) {
+ FwdLockConv_Status_t status = FwdLockConv_Status_OK;
+ switch (pSession->scannerState) {
+ case FwdLockConv_ScannerState_WantsFirstDash:
+ if (ch == '-') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsSecondDash;
+ } else if (ch == '\r') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ } else {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsSecondDash:
+ if (ch == '-') {
+ // The delimiter starts with "\r\n--" (the open delimiter may omit the initial "\r\n").
+ // The rest is the user-defined boundary that should come next.
+ pSession->delimiter[0] = '\r';
+ pSession->delimiter[1] = '\n';
+ pSession->delimiter[2] = '-';
+ pSession->delimiter[3] = '-';
+ pSession->delimiterLength = 4;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsBoundary;
+ } else if (ch == '\r') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ } else {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsCR:
+ if (ch == '\r') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsLF:
+ if (ch == '\n') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash;
+ } else if (ch != '\r') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsBoundary:
+ if (FwdLockConv_IsBoundaryChar(ch)) {
+ // The boundary may contain leading and internal spaces, so trailing spaces will also be
+ // matched here. These will be removed later.
+ if (pSession->delimiterLength < MAX_DELIMITER_LENGTH) {
+ pSession->delimiter[pSession->delimiterLength++] = ch;
+ } else if (ch != ' ') {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ } else if (ch == '\r') {
+ status = FwdLockConv_RightTrimDelimiter(pSession);
+ if (status == FwdLockConv_Status_OK) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsBoundaryEnd;
+ }
+ } else if (ch == '\t') {
+ status = FwdLockConv_RightTrimDelimiter(pSession);
+ if (status == FwdLockConv_Status_OK) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace;
+ }
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsWhitespace:
+ if (ch == '\r') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsBoundaryEnd;
+ } else if (!FwdLockConv_IsWhitespace(ch)) {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsBoundaryEnd:
+ if (ch == '\n') {
+ pSession->parserState = FwdLockConv_ParserState_WantsMimeHeaders;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderNameStart;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ default:
+ status = FwdLockConv_Status_ProgramError;
+ break;
+ }
+ return status;
+}
+
+/**
+ * Checks whether a given character is valid in a MIME header name.
+ *
+ * @param[in] ch The character to check.
+ *
+ * @return A Boolean value indicating whether the given character is valid in a MIME header name.
+ */
+static int FwdLockConv_IsMimeHeaderNameChar(int ch) {
+ return isgraph(ch) && ch != ':';
+}
+
+/**
+ * Checks whether a given character is valid in a MIME header value.
+ *
+ * @param[in] ch The character to check.
+ *
+ * @return A Boolean value indicating whether the given character is valid in a MIME header value.
+ */
+static int FwdLockConv_IsMimeHeaderValueChar(int ch) {
+ return isgraph(ch) && ch != ';';
+}
+
+/**
+ * Appends a character to the specified dynamically growing string.
+ *
+ * @param[in,out] pString A reference to a dynamically growing string.
+ * @param[in] ch The character to append.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_StringAppend(FwdLockConv_String_t *pString, int ch) {
+ if (pString->length == pString->maxLength) {
+ size_t newMaxLength = pString->maxLength + pString->lengthIncrement;
+ char *newPtr = realloc(pString->ptr, newMaxLength + 1);
+ if (newPtr == NULL) {
+ return FwdLockConv_Status_OutOfMemory;
+ }
+ pString->ptr = newPtr;
+ pString->maxLength = newMaxLength;
+ }
+ pString->ptr[pString->length++] = ch;
+ pString->ptr[pString->length] = '\0';
+ return FwdLockConv_Status_OK;
+}
+
+/**
+ * Attempts to recognize the MIME header name and changes the scanner state accordingly.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_RecognizeMimeHeaderName(FwdLockConv_Session_t *pSession) {
+ FwdLockConv_Status_t status = FwdLockConv_Status_OK;
+ if (strncmp(pSession->mimeHeaderName.ptr, strContent, strlenContent) == 0) {
+ if (strcmp(pSession->mimeHeaderName.ptr + strlenContent, strType) == 0) {
+ if (pSession->contentType.ptr == NULL) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsContentTypeStart;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ } else if (strcmp(pSession->mimeHeaderName.ptr + strlenContent, strTransferEncoding) == 0) {
+ if (pSession->contentTransferEncoding ==
+ FwdLockConv_ContentTransferEncoding_Undefined) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingStart;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ } else {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
+ }
+ } else {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
+ }
+ return status;
+}
+
+/**
+ * Applies defaults to missing MIME header values.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_ApplyDefaults(FwdLockConv_Session_t *pSession) {
+ if (pSession->contentType.ptr == NULL) {
+ // Content type is missing: default to "text/plain".
+ pSession->contentType.ptr = malloc(sizeof strTextPlain);
+ if (pSession->contentType.ptr == NULL) {
+ return FwdLockConv_Status_OutOfMemory;
+ }
+ memcpy(pSession->contentType.ptr, strTextPlain, sizeof strTextPlain);
+ pSession->contentType.length = strlenTextPlain;
+ pSession->contentType.maxLength = strlenTextPlain;
+ }
+ if (pSession->contentTransferEncoding == FwdLockConv_ContentTransferEncoding_Undefined) {
+ // Content transfer encoding is missing: default to binary.
+ pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Binary;
+ }
+ return FwdLockConv_Status_OK;
+}
+
+/**
+ * Verifies that the content type is supported.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_VerifyContentType(FwdLockConv_Session_t *pSession) {
+ FwdLockConv_Status_t status;
+ if (pSession->contentType.ptr == NULL) {
+ status = FwdLockConv_Status_ProgramError;
+ } else if (strcmp(pSession->contentType.ptr, strApplicationVndOmaDrmRightsXml) == 0 ||
+ strcmp(pSession->contentType.ptr, strApplicationVndOmaDrmContent) == 0) {
+ status = FwdLockConv_Status_UnsupportedFileFormat;
+ } else {
+ status = FwdLockConv_Status_OK;
+ }
+ return status;
+}
+
+/**
+ * Writes the header of the output file.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ * @param[out] pOutput The output from the conversion process.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_WriteHeader(FwdLockConv_Session_t *pSession,
+ FwdLockConv_Output_t *pOutput) {
+ FwdLockConv_Status_t status;
+ if (pSession->contentType.length > UCHAR_MAX) {
+ status = FwdLockConv_Status_SyntaxError;
+ } else {
+ pSession->outputBufferSize = OUTPUT_BUFFER_SIZE_INCREMENT;
+ pOutput->fromConvertData.pBuffer = malloc(pSession->outputBufferSize);
+ if (pOutput->fromConvertData.pBuffer == NULL) {
+ status = FwdLockConv_Status_OutOfMemory;
+ } else {
+ size_t encryptedSessionKeyPos = TOP_HEADER_SIZE + pSession->contentType.length;
+ size_t dataSignaturePos = encryptedSessionKeyPos + pSession->encryptedSessionKeyLength;
+ size_t headerSignaturePos = dataSignaturePos + SHA1_HASH_SIZE;
+ pSession->dataOffset = headerSignaturePos + SHA1_HASH_SIZE;
+ memcpy(pSession->topHeader, topHeaderTemplate, sizeof topHeaderTemplate);
+ pSession->topHeader[CONTENT_TYPE_LENGTH_POS] =
+ (unsigned char)pSession->contentType.length;
+ memcpy(pOutput->fromConvertData.pBuffer, pSession->topHeader, TOP_HEADER_SIZE);
+ memcpy((char *)pOutput->fromConvertData.pBuffer + TOP_HEADER_SIZE,
+ pSession->contentType.ptr, pSession->contentType.length);
+ memcpy((char *)pOutput->fromConvertData.pBuffer + encryptedSessionKeyPos,
+ pSession->pEncryptedSessionKey, pSession->encryptedSessionKeyLength);
+
+ // Set the signatures to all zeros for now; they will have to be updated later.
+ memset((char *)pOutput->fromConvertData.pBuffer + dataSignaturePos, 0,
+ SHA1_HASH_SIZE);
+ memset((char *)pOutput->fromConvertData.pBuffer + headerSignaturePos, 0,
+ SHA1_HASH_SIZE);
+
+ pOutput->fromConvertData.numBytes = pSession->dataOffset;
+ status = FwdLockConv_Status_OK;
+ }
+ }
+ return status;
+}
+
+/**
+ * Matches the MIME headers.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ * @param[in] ch A character.
+ * @param[out] pOutput The output from the conversion process.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_MatchMimeHeaders(FwdLockConv_Session_t *pSession,
+ int ch,
+ FwdLockConv_Output_t *pOutput) {
+ FwdLockConv_Status_t status = FwdLockConv_Status_OK;
+ switch (pSession->scannerState) {
+ case FwdLockConv_ScannerState_WantsMimeHeaderNameStart:
+ if (FwdLockConv_IsMimeHeaderNameChar(ch)) {
+ pSession->mimeHeaderName.length = 0;
+ status = FwdLockConv_StringAppend(&pSession->mimeHeaderName, tolower(ch));
+ if (status == FwdLockConv_Status_OK) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderName;
+ }
+ } else if (ch == '\r') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeadersEnd;
+ } else if (!FwdLockConv_IsWhitespace(ch)) {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsMimeHeaderName:
+ if (FwdLockConv_IsMimeHeaderNameChar(ch)) {
+ status = FwdLockConv_StringAppend(&pSession->mimeHeaderName, tolower(ch));
+ } else if (ch == ':') {
+ status = FwdLockConv_RecognizeMimeHeaderName(pSession);
+ } else if (FwdLockConv_IsWhitespace(ch)) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderNameEnd;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsMimeHeaderNameEnd:
+ if (ch == ':') {
+ status = FwdLockConv_RecognizeMimeHeaderName(pSession);
+ } else if (!FwdLockConv_IsWhitespace(ch)) {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsContentTypeStart:
+ if (FwdLockConv_IsMimeHeaderValueChar(ch)) {
+ status = FwdLockConv_StringAppend(&pSession->contentType, tolower(ch));
+ if (status == FwdLockConv_Status_OK) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsContentType;
+ }
+ } else if (!FwdLockConv_IsWhitespace(ch)) {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsContentType:
+ if (FwdLockConv_IsMimeHeaderValueChar(ch)) {
+ status = FwdLockConv_StringAppend(&pSession->contentType, tolower(ch));
+ } else if (ch == ';') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
+ } else if (ch == '\r') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ } else if (FwdLockConv_IsWhitespace(ch)) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderValueEnd;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsContentTransferEncodingStart:
+ if (ch == 'b' || ch == 'B') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_A_OR_I;
+ } else if (ch == '7' || ch == '8') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_B;
+ } else if (!FwdLockConv_IsWhitespace(ch)) {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_A_OR_I:
+ if (ch == 'i' || ch == 'I') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_N;
+ } else if (ch == 'a' || ch == 'A') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_S;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_N:
+ if (ch == 'n' || ch == 'N') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_A;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_A:
+ if (ch == 'a' || ch == 'A') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_R;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_R:
+ if (ch == 'r' || ch == 'R') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_Y;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_Y:
+ if (ch == 'y' || ch == 'Y') {
+ pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Binary;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingEnd;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_S:
+ if (ch == 's' || ch == 'S') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_E;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_E:
+ if (ch == 'e' || ch == 'E') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_6;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_6:
+ if (ch == '6') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_4;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_4:
+ if (ch == '4') {
+ pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Base64;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingEnd;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_B:
+ if (ch == 'b' || ch == 'B') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_I;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_I:
+ if (ch == 'i' || ch == 'I') {
+ pSession->scannerState = FwdLockConv_ScannerState_Wants_T;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_Wants_T:
+ if (ch == 't' || ch == 'T') {
+ pSession->contentTransferEncoding = FwdLockConv_ContentTransferEncoding_Binary;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsContentTransferEncodingEnd;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsContentTransferEncodingEnd:
+ if (ch == ';') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
+ } else if (ch == '\r') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ } else if (FwdLockConv_IsWhitespace(ch)) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderValueEnd;
+ } else {
+ status = FwdLockConv_Status_UnsupportedContentTransferEncoding;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsMimeHeaderValueEnd:
+ if (ch == ';') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsCR;
+ } else if (ch == '\r') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ } else if (!FwdLockConv_IsWhitespace(ch)) {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsCR:
+ if (ch == '\r') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsLF:
+ if (ch == '\n') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsMimeHeaderNameStart;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsMimeHeadersEnd:
+ if (ch == '\n') {
+ status = FwdLockConv_ApplyDefaults(pSession);
+ if (status == FwdLockConv_Status_OK) {
+ status = FwdLockConv_VerifyContentType(pSession);
+ }
+ if (status == FwdLockConv_Status_OK) {
+ status = FwdLockConv_WriteHeader(pSession, pOutput);
+ }
+ if (status == FwdLockConv_Status_OK) {
+ if (pSession->contentTransferEncoding ==
+ FwdLockConv_ContentTransferEncoding_Binary) {
+ pSession->parserState = FwdLockConv_ParserState_WantsBinaryEncodedData;
+ } else {
+ pSession->parserState = FwdLockConv_ParserState_WantsBase64EncodedData;
+ }
+ pSession->scannerState = FwdLockConv_ScannerState_WantsByte1;
+ }
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ default:
+ status = FwdLockConv_Status_ProgramError;
+ break;
+ }
+ return status;
+}
+
+/**
+ * Increments the counter, treated as a 16-byte little-endian number, by one.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ */
+static void FwdLockConv_IncrementCounter(FwdLockConv_Session_t *pSession) {
+ size_t i = 0;
+ while ((++pSession->counter[i] == 0) && (++i < AES_BLOCK_SIZE))
+ ;
+}
+
+/**
+ * Encrypts the given character and writes it to the output buffer.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ * @param[in] ch The character to encrypt and write.
+ * @param[in,out] pOutput The output from the conversion process.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_WriteEncryptedChar(FwdLockConv_Session_t *pSession,
+ unsigned char ch,
+ FwdLockConv_Output_t *pOutput) {
+ if (pOutput->fromConvertData.numBytes == pSession->outputBufferSize) {
+ void *pBuffer;
+ pSession->outputBufferSize += OUTPUT_BUFFER_SIZE_INCREMENT;
+ pBuffer = realloc(pOutput->fromConvertData.pBuffer, pSession->outputBufferSize);
+ if (pBuffer == NULL) {
+ return FwdLockConv_Status_OutOfMemory;
+ }
+ pOutput->fromConvertData.pBuffer = pBuffer;
+ }
+ if (++pSession->keyStreamIndex == AES_BLOCK_SIZE) {
+ FwdLockConv_IncrementCounter(pSession);
+ pSession->keyStreamIndex = 0;
+ }
+ if (pSession->keyStreamIndex == 0) {
+ AES_encrypt(pSession->counter, pSession->keyStream, &pSession->encryptionRoundKeys);
+ }
+ ch ^= pSession->keyStream[pSession->keyStreamIndex];
+ ((unsigned char *)pOutput->fromConvertData.pBuffer)[pOutput->fromConvertData.numBytes++] = ch;
+ ++pSession->numDataBytes;
+ return FwdLockConv_Status_OK;
+}
+
+/**
+ * Matches binary-encoded content data and encrypts it, while looking out for the close delimiter.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ * @param[in] ch A character.
+ * @param[in,out] pOutput The output from the conversion process.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_MatchBinaryEncodedData(FwdLockConv_Session_t *pSession,
+ int ch,
+ FwdLockConv_Output_t *pOutput) {
+ FwdLockConv_Status_t status = FwdLockConv_Status_OK;
+ switch (pSession->scannerState) {
+ case FwdLockConv_ScannerState_WantsByte1:
+ if (ch != pSession->delimiter[pSession->delimiterMatchPos]) {
+ // The partial match of the delimiter turned out to be spurious. Flush the matched bytes
+ // to the output buffer and start over.
+ size_t i;
+ for (i = 0; i < pSession->delimiterMatchPos; ++i) {
+ status = FwdLockConv_WriteEncryptedChar(pSession, pSession->delimiter[i], pOutput);
+ if (status != FwdLockConv_Status_OK) {
+ return status;
+ }
+ }
+ pSession->delimiterMatchPos = 0;
+ }
+ if (ch != pSession->delimiter[pSession->delimiterMatchPos]) {
+ // The current character isn't part of the delimiter. Write it to the output buffer.
+ status = FwdLockConv_WriteEncryptedChar(pSession, ch, pOutput);
+ } else if (++pSession->delimiterMatchPos == pSession->delimiterLength) {
+ // The entire delimiter has been matched. The only valid characters now are the "--"
+ // that complete the close delimiter (no more message parts are expected).
+ pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsFirstDash:
+ if (ch == '-') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsSecondDash;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsSecondDash:
+ if (ch == '-') {
+ pSession->parserState = FwdLockConv_ParserState_Done;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ default:
+ status = FwdLockConv_Status_ProgramError;
+ break;
+ }
+ return status;
+}
+
+/**
+ * Checks whether a given character is valid in base64-encoded data.
+ *
+ * @param[in] ch The character to check.
+ *
+ * @return A Boolean value indicating whether the given character is valid in base64-encoded data.
+ */
+static int FwdLockConv_IsBase64Char(int ch) {
+ return 0 <= ch && ch <= 'z' && base64Values[ch] >= 0;
+}
+
+/**
+ * Matches base64-encoded content data and encrypts it, while looking out for the close delimiter.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ * @param[in] ch A character.
+ * @param[in,out] pOutput The output from the conversion process.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_MatchBase64EncodedData(FwdLockConv_Session_t *pSession,
+ int ch,
+ FwdLockConv_Output_t *pOutput) {
+ FwdLockConv_Status_t status = FwdLockConv_Status_OK;
+ switch (pSession->scannerState) {
+ case FwdLockConv_ScannerState_WantsByte1:
+ case FwdLockConv_ScannerState_WantsByte1_AfterCRLF:
+ if (FwdLockConv_IsBase64Char(ch)) {
+ pSession->ch = base64Values[ch] << 2;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsByte2;
+ } else if (ch == '\r') {
+ pSession->savedScannerState = FwdLockConv_ScannerState_WantsByte1_AfterCRLF;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ } else if (ch == '-') {
+ if (pSession->scannerState == FwdLockConv_ScannerState_WantsByte1_AfterCRLF) {
+ pSession->delimiterMatchPos = 3;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsDelimiter;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ } else if (!FwdLockConv_IsWhitespace(ch)) {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsByte2:
+ if (FwdLockConv_IsBase64Char(ch)) {
+ pSession->ch |= base64Values[ch] >> 4;
+ status = FwdLockConv_WriteEncryptedChar(pSession, pSession->ch, pOutput);
+ if (status == FwdLockConv_Status_OK) {
+ pSession->ch = base64Values[ch] << 4;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsByte3;
+ }
+ } else if (ch == '\r') {
+ pSession->savedScannerState = pSession->scannerState;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ } else if (!FwdLockConv_IsWhitespace(ch)) {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsByte3:
+ if (FwdLockConv_IsBase64Char(ch)) {
+ pSession->ch |= base64Values[ch] >> 2;
+ status = FwdLockConv_WriteEncryptedChar(pSession, pSession->ch, pOutput);
+ if (status == FwdLockConv_Status_OK) {
+ pSession->ch = base64Values[ch] << 6;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsByte4;
+ }
+ } else if (ch == '\r') {
+ pSession->savedScannerState = pSession->scannerState;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ } else if (ch == '=') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsPadding;
+ } else if (!FwdLockConv_IsWhitespace(ch)) {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsByte4:
+ if (FwdLockConv_IsBase64Char(ch)) {
+ pSession->ch |= base64Values[ch];
+ status = FwdLockConv_WriteEncryptedChar(pSession, pSession->ch, pOutput);
+ if (status == FwdLockConv_Status_OK) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsByte1;
+ }
+ } else if (ch == '\r') {
+ pSession->savedScannerState = pSession->scannerState;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ } else if (ch == '=') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace;
+ } else if (!FwdLockConv_IsWhitespace(ch)) {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsLF:
+ if (ch == '\n') {
+ pSession->scannerState = pSession->savedScannerState;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsPadding:
+ if (ch == '=') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsWhitespace:
+ case FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF:
+ if (ch == '\r') {
+ pSession->savedScannerState = FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsLF;
+ } else if (ch == '-') {
+ if (pSession->scannerState == FwdLockConv_ScannerState_WantsWhitespace_AfterCRLF) {
+ pSession->delimiterMatchPos = 3;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsDelimiter;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ } else if (FwdLockConv_IsWhitespace(ch)) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsWhitespace;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsDelimiter:
+ if (ch != pSession->delimiter[pSession->delimiterMatchPos]) {
+ status = FwdLockConv_Status_SyntaxError;
+ } else if (++pSession->delimiterMatchPos == pSession->delimiterLength) {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsFirstDash:
+ if (ch == '-') {
+ pSession->scannerState = FwdLockConv_ScannerState_WantsSecondDash;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ case FwdLockConv_ScannerState_WantsSecondDash:
+ if (ch == '-') {
+ pSession->parserState = FwdLockConv_ParserState_Done;
+ } else {
+ status = FwdLockConv_Status_SyntaxError;
+ }
+ break;
+ default:
+ status = FwdLockConv_Status_ProgramError;
+ break;
+ }
+ return status;
+}
+
+/**
+ * Pushes a single character into the converter's state machine.
+ *
+ * @param[in,out] pSession A reference to a converter session.
+ * @param[in] ch A character.
+ * @param[in,out] pOutput The output from the conversion process.
+ *
+ * @return A status code.
+ */
+static FwdLockConv_Status_t FwdLockConv_PushChar(FwdLockConv_Session_t *pSession,
+ int ch,
+ FwdLockConv_Output_t *pOutput) {
+ FwdLockConv_Status_t status;
+ ++pSession->numCharsConsumed;
+ switch (pSession->parserState) {
+ case FwdLockConv_ParserState_WantsOpenDelimiter:
+ status = FwdLockConv_MatchOpenDelimiter(pSession, ch);
+ break;
+ case FwdLockConv_ParserState_WantsMimeHeaders:
+ status = FwdLockConv_MatchMimeHeaders(pSession, ch, pOutput);
+ break;
+ case FwdLockConv_ParserState_WantsBinaryEncodedData:
+ status = FwdLockConv_MatchBinaryEncodedData(pSession, ch, pOutput);
+ break;
+ case FwdLockConv_ParserState_WantsBase64EncodedData:
+ status = FwdLockConv_MatchBase64EncodedData(pSession, ch, pOutput);
+ break;
+ case FwdLockConv_ParserState_Done:
+ status = FwdLockConv_Status_OK;
+ break;
+ default:
+ status = FwdLockConv_Status_ProgramError;
+ break;
+ }
+ return status;
+}
+
+FwdLockConv_Status_t FwdLockConv_OpenSession(int *pSessionId, FwdLockConv_Output_t *pOutput) {
+ FwdLockConv_Status_t status;
+ if (pSessionId == NULL || pOutput == NULL) {
+ status = FwdLockConv_Status_InvalidArgument;
+ } else {
+ *pSessionId = FwdLockConv_AcquireSession();
+ if (*pSessionId < 0) {
+ status = FwdLockConv_Status_TooManySessions;
+ } else {
+ FwdLockConv_Session_t *pSession = sessionPtrs[*pSessionId];
+ pSession->encryptedSessionKeyLength = FwdLockGlue_GetEncryptedKeyLength(KEY_SIZE);
+ if (pSession->encryptedSessionKeyLength < AES_BLOCK_SIZE) {
+ // The encrypted session key is used as the CTR-mode nonce, so it must be at least
+ // the size of a single AES block.
+ status = FwdLockConv_Status_ProgramError;
+ } else {
+ pSession->pEncryptedSessionKey = malloc(pSession->encryptedSessionKeyLength);
+ if (pSession->pEncryptedSessionKey == NULL) {
+ status = FwdLockConv_Status_OutOfMemory;
+ } else {
+ if (!FwdLockGlue_GetRandomNumber(pSession->sessionKey, KEY_SIZE)) {
+ status = FwdLockConv_Status_RandomNumberGenerationFailed;
+ } else if (!FwdLockGlue_EncryptKey(pSession->sessionKey, KEY_SIZE,
+ pSession->pEncryptedSessionKey,
+ pSession->encryptedSessionKeyLength)) {
+ status = FwdLockConv_Status_KeyEncryptionFailed;
+ } else {
+ status = FwdLockConv_DeriveKeys(pSession);
+ }
+ if (status == FwdLockConv_Status_OK) {
+ memset(pSession->sessionKey, 0, KEY_SIZE); // Zero out key data.
+ memcpy(pSession->counter, pSession->pEncryptedSessionKey, AES_BLOCK_SIZE);
+ pSession->parserState = FwdLockConv_ParserState_WantsOpenDelimiter;
+ pSession->scannerState = FwdLockConv_ScannerState_WantsFirstDash;
+ pSession->numCharsConsumed = 0;
+ pSession->delimiterMatchPos = 0;
+ pSession->mimeHeaderName = nullString;
+ pSession->contentType = nullString;
+ pSession->contentTransferEncoding =
+ FwdLockConv_ContentTransferEncoding_Undefined;
+ pSession->keyStreamIndex = -1;
+ pOutput->fromConvertData.pBuffer = NULL;
+ pOutput->fromConvertData.errorPos = INVALID_OFFSET;
+ } else {
+ free(pSession->pEncryptedSessionKey);
+ }
+ }
+ }
+ if (status != FwdLockConv_Status_OK) {
+ FwdLockConv_ReleaseSession(*pSessionId);
+ *pSessionId = -1;
+ }
+ }
+ }
+ return status;
+}
+
+FwdLockConv_Status_t FwdLockConv_ConvertData(int sessionId,
+ const void *pBuffer,
+ size_t numBytes,
+ FwdLockConv_Output_t *pOutput) {
+ FwdLockConv_Status_t status;
+ if (!FwdLockConv_IsValidSession(sessionId) || pBuffer == NULL || pOutput == NULL) {
+ status = FwdLockConv_Status_InvalidArgument;
+ } else {
+ size_t i;
+ FwdLockConv_Session_t *pSession = sessionPtrs[sessionId];
+ pSession->dataOffset = 0;
+ pSession->numDataBytes = 0;
+ pOutput->fromConvertData.numBytes = 0;
+ status = FwdLockConv_Status_OK;
+
+ for (i = 0; i < numBytes; ++i) {
+ status = FwdLockConv_PushChar(pSession, ((char *)pBuffer)[i], pOutput);
+ if (status != FwdLockConv_Status_OK) {
+ break;
+ }
+ }
+ if (status == FwdLockConv_Status_OK) {
+ // Update the data signature.
+ HMAC_Update(&pSession->signingContext,
+ &((unsigned char *)pOutput->fromConvertData.pBuffer)[pSession->dataOffset],
+ pSession->numDataBytes);
+ } else if (status == FwdLockConv_Status_SyntaxError) {
+ pOutput->fromConvertData.errorPos = pSession->numCharsConsumed;
+ }
+ }
+ return status;
+}
+
+FwdLockConv_Status_t FwdLockConv_CloseSession(int sessionId, FwdLockConv_Output_t *pOutput) {
+ FwdLockConv_Status_t status;
+ if (!FwdLockConv_IsValidSession(sessionId) || pOutput == NULL) {
+ status = FwdLockConv_Status_InvalidArgument;
+ } else {
+ FwdLockConv_Session_t *pSession = sessionPtrs[sessionId];
+ free(pOutput->fromConvertData.pBuffer);
+ if (pSession->parserState != FwdLockConv_ParserState_Done) {
+ pOutput->fromCloseSession.errorPos = pSession->numCharsConsumed;
+ status = FwdLockConv_Status_SyntaxError;
+ } else {
+ // Finalize the data signature.
+ size_t signatureSize;
+ HMAC_Final(&pSession->signingContext, pOutput->fromCloseSession.signatures,
+ &signatureSize);
+ if (signatureSize != SHA1_HASH_SIZE) {
+ status = FwdLockConv_Status_ProgramError;
+ } else {
+ // Calculate the header signature, which is a signature of the rest of the header
+ // including the data signature.
+ HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
+ HMAC_Update(&pSession->signingContext, pSession->topHeader, TOP_HEADER_SIZE);
+ HMAC_Update(&pSession->signingContext, (unsigned char *)pSession->contentType.ptr,
+ pSession->contentType.length);
+ HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey,
+ pSession->encryptedSessionKeyLength);
+ HMAC_Update(&pSession->signingContext, pOutput->fromCloseSession.signatures,
+ signatureSize);
+ HMAC_Final(&pSession->signingContext, &pOutput->fromCloseSession.
+ signatures[signatureSize], &signatureSize);
+ if (signatureSize != SHA1_HASH_SIZE) {
+ status = FwdLockConv_Status_ProgramError;
+ } else {
+ pOutput->fromCloseSession.fileOffset = TOP_HEADER_SIZE +
+ pSession->contentType.length + pSession->encryptedSessionKeyLength;
+ status = FwdLockConv_Status_OK;
+ }
+ }
+ pOutput->fromCloseSession.errorPos = INVALID_OFFSET;
+ }
+ free(pSession->mimeHeaderName.ptr);
+ free(pSession->contentType.ptr);
+ free(pSession->pEncryptedSessionKey);
+ HMAC_CTX_cleanup(&pSession->signingContext);
+ FwdLockConv_ReleaseSession(sessionId);
+ }
+ return status;
+}
+
+FwdLockConv_Status_t FwdLockConv_ConvertOpenFile(int inputFileDesc,
+ FwdLockConv_ReadFunc_t *fpReadFunc,
+ int outputFileDesc,
+ FwdLockConv_WriteFunc_t *fpWriteFunc,
+ FwdLockConv_LSeekFunc_t *fpLSeekFunc,
+ off64_t *pErrorPos) {
+ FwdLockConv_Status_t status;
+ if (pErrorPos != NULL) {
+ *pErrorPos = INVALID_OFFSET;
+ }
+ if (fpReadFunc == NULL || fpWriteFunc == NULL || fpLSeekFunc == NULL || inputFileDesc < 0 ||
+ outputFileDesc < 0) {
+ status = FwdLockConv_Status_InvalidArgument;
+ } else {
+ char *pReadBuffer = malloc(READ_BUFFER_SIZE);
+ if (pReadBuffer == NULL) {
+ status = FwdLockConv_Status_OutOfMemory;
+ } else {
+ int sessionId;
+ FwdLockConv_Output_t output;
+ status = FwdLockConv_OpenSession(&sessionId, &output);
+ if (status == FwdLockConv_Status_OK) {
+ ssize_t numBytesRead;
+ FwdLockConv_Status_t closeStatus;
+ while ((numBytesRead =
+ fpReadFunc(inputFileDesc, pReadBuffer, READ_BUFFER_SIZE)) > 0) {
+ status = FwdLockConv_ConvertData(sessionId, pReadBuffer, (size_t)numBytesRead,
+ &output);
+ if (status == FwdLockConv_Status_OK) {
+ if (output.fromConvertData.pBuffer != NULL &&
+ output.fromConvertData.numBytes > 0) {
+ ssize_t numBytesWritten = fpWriteFunc(outputFileDesc,
+ output.fromConvertData.pBuffer,
+ output.fromConvertData.numBytes);
+ if (numBytesWritten != (ssize_t)output.fromConvertData.numBytes) {
+ status = FwdLockConv_Status_FileWriteError;
+ break;
+ }
+ }
+ } else {
+ if (status == FwdLockConv_Status_SyntaxError && pErrorPos != NULL) {
+ *pErrorPos = output.fromConvertData.errorPos;
+ }
+ break;
+ }
+ } // end while
+ if (numBytesRead < 0) {
+ status = FwdLockConv_Status_FileReadError;
+ }
+ closeStatus = FwdLockConv_CloseSession(sessionId, &output);
+ if (status == FwdLockConv_Status_OK) {
+ if (closeStatus != FwdLockConv_Status_OK) {
+ if (closeStatus == FwdLockConv_Status_SyntaxError && pErrorPos != NULL) {
+ *pErrorPos = output.fromCloseSession.errorPos;
+ }
+ status = closeStatus;
+ } else if (fpLSeekFunc(outputFileDesc, output.fromCloseSession.fileOffset,
+ SEEK_SET) < 0) {
+ status = FwdLockConv_Status_FileSeekError;
+ } else if (fpWriteFunc(outputFileDesc, output.fromCloseSession.signatures,
+ FWD_LOCK_SIGNATURES_SIZE) != FWD_LOCK_SIGNATURES_SIZE) {
+ status = FwdLockConv_Status_FileWriteError;
+ }
+ }
+ }
+ free(pReadBuffer);
+ }
+ }
+ return status;
+}
+
+FwdLockConv_Status_t FwdLockConv_ConvertFile(const char *pInputFilename,
+ const char *pOutputFilename,
+ off64_t *pErrorPos) {
+ FwdLockConv_Status_t status;
+ if (pErrorPos != NULL) {
+ *pErrorPos = INVALID_OFFSET;
+ }
+ if (pInputFilename == NULL || pOutputFilename == NULL) {
+ status = FwdLockConv_Status_InvalidArgument;
+ } else {
+ int inputFileDesc = open(pInputFilename, O_RDONLY);
+ if (inputFileDesc < 0) {
+ status = FwdLockConv_Status_FileNotFound;
+ } else {
+ int outputFileDesc = open(pOutputFilename, O_CREAT | O_TRUNC | O_WRONLY,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ if (outputFileDesc < 0) {
+ status = FwdLockConv_Status_FileCreationFailed;
+ } else {
+ status = FwdLockConv_ConvertOpenFile(inputFileDesc, read, outputFileDesc, write,
+ lseek64, pErrorPos);
+ if (close(outputFileDesc) == 0 && status != FwdLockConv_Status_OK) {
+ remove(pOutputFilename);
+ }
+ }
+ (void)close(inputFileDesc);
+ }
+ }
+ return status;
+}
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.h b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.h
new file mode 100644
index 0000000..e20c0c3
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/converter/FwdLockConv.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FWDLOCKCONV_H__
+#define __FWDLOCKCONV_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+/**
+ * The size of the data and header signatures combined. The signatures are adjacent to each other in
+ * the produced output file.
+ */
+#define FWD_LOCK_SIGNATURES_SIZE (2 * 20)
+
+/**
+ * Data type for the output from FwdLockConv_ConvertData.
+ */
+typedef struct FwdLockConv_ConvertData_Output {
+ /// The converted data.
+ void *pBuffer;
+
+ /// The size of the converted data.
+ size_t numBytes;
+
+ /// The file position where the error occurred, in the case of a syntax error.
+ off64_t errorPos;
+} FwdLockConv_ConvertData_Output_t;
+
+/**
+ * Data type for the output from FwdLockConv_CloseSession.
+ */
+typedef struct FwdLockConv_CloseSession_Output {
+ /// The final set of signatures.
+ unsigned char signatures[FWD_LOCK_SIGNATURES_SIZE];
+
+ /// The offset in the produced output file where the signatures are located.
+ off64_t fileOffset;
+
+ /// The file position where the error occurred, in the case of a syntax error.
+ off64_t errorPos;
+} FwdLockConv_CloseSession_Output_t;
+
+/**
+ * Data type for the output from the conversion process.
+ */
+typedef union FwdLockConv_Output {
+ FwdLockConv_ConvertData_Output_t fromConvertData;
+ FwdLockConv_CloseSession_Output_t fromCloseSession;
+} FwdLockConv_Output_t;
+
+/**
+ * Data type for the Posix-style read function used by the converter in pull mode.
+ *
+ * @param[in] fileDesc The file descriptor of a file opened for reading.
+ * @param[out] pBuffer A reference to the buffer that should receive the read data.
+ * @param[in] numBytes The number of bytes to read.
+ *
+ * @return The number of bytes read.
+ * @retval -1 Failure.
+ */
+typedef ssize_t FwdLockConv_ReadFunc_t(int fileDesc, void *pBuffer, size_t numBytes);
+
+/**
+ * Data type for the Posix-style write function used by the converter in pull mode.
+ *
+ * @param[in] fileDesc The file descriptor of a file opened for writing.
+ * @param[in] pBuffer A reference to the buffer containing the data to be written.
+ * @param[in] numBytes The number of bytes to write.
+ *
+ * @return The number of bytes written.
+ * @retval -1 Failure.
+ */
+typedef ssize_t FwdLockConv_WriteFunc_t(int fileDesc, const void *pBuffer, size_t numBytes);
+
+/**
+ * Data type for the Posix-style lseek function used by the converter in pull mode.
+ *
+ * @param[in] fileDesc The file descriptor of a file opened for writing.
+ * @param[in] offset The offset with which to update the file position.
+ * @param[in] whence One of SEEK_SET, SEEK_CUR, and SEEK_END.
+ *
+ * @return The new file position.
+ * @retval ((off64_t)-1) Failure.
+ */
+typedef off64_t FwdLockConv_LSeekFunc_t(int fileDesc, off64_t offset, int whence);
+
+/**
+ * The status codes returned by the converter functions.
+ */
+typedef enum FwdLockConv_Status {
+ /// The operation was successful.
+ FwdLockConv_Status_OK = 0,
+
+ /// An actual argument to the function is invalid (a program error on the caller's part).
+ FwdLockConv_Status_InvalidArgument = 1,
+
+ /// There is not enough free dynamic memory to complete the operation.
+ FwdLockConv_Status_OutOfMemory = 2,
+
+ /// An error occurred while opening the input file.
+ FwdLockConv_Status_FileNotFound = 3,
+
+ /// An error occurred while creating the output file.
+ FwdLockConv_Status_FileCreationFailed = 4,
+
+ /// An error occurred while reading from the input file.
+ FwdLockConv_Status_FileReadError = 5,
+
+ /// An error occurred while writing to the output file.
+ FwdLockConv_Status_FileWriteError = 6,
+
+ /// An error occurred while seeking to a new file position within the output file.
+ FwdLockConv_Status_FileSeekError = 7,
+
+ /// The input file is not a syntactically correct OMA DRM v1 Forward Lock file.
+ FwdLockConv_Status_SyntaxError = 8,
+
+ /// Support for this DRM file format has been disabled in the current product configuration.
+ FwdLockConv_Status_UnsupportedFileFormat = 9,
+
+ /// The content transfer encoding is not one of "binary", "base64", "7bit", or "8bit"
+ /// (case-insensitive).
+ FwdLockConv_Status_UnsupportedContentTransferEncoding = 10,
+
+ /// The generation of a random number failed.
+ FwdLockConv_Status_RandomNumberGenerationFailed = 11,
+
+ /// Key encryption failed.
+ FwdLockConv_Status_KeyEncryptionFailed = 12,
+
+ /// The calculation of a keyed hash for integrity protection failed.
+ FwdLockConv_Status_IntegrityProtectionFailed = 13,
+
+ /// There are too many ongoing sessions for another one to be opened.
+ FwdLockConv_Status_TooManySessions = 14,
+
+ /// An unexpected error occurred.
+ FwdLockConv_Status_ProgramError = 15
+} FwdLockConv_Status_t;
+
+/**
+ * Opens a session for converting an OMA DRM v1 Forward Lock file to the internal Forward Lock file
+ * format.
+ *
+ * @param[out] pSessionId The session ID.
+ * @param[out] pOutput The output from the conversion process (initialized).
+ *
+ * @return A status code.
+ * @retval FwdLockConv_Status_OK
+ * @retval FwdLockConv_Status_InvalidArgument
+ * @retval FwdLockConv_Status_TooManySessions
+ */
+FwdLockConv_Status_t FwdLockConv_OpenSession(int *pSessionId, FwdLockConv_Output_t *pOutput);
+
+/**
+ * Supplies the converter with data to convert. The caller is expected to write the converted data
+ * to file. Can be called an arbitrary number of times.
+ *
+ * @param[in] sessionId The session ID.
+ * @param[in] pBuffer A reference to a buffer containing the data to convert.
+ * @param[in] numBytes The number of bytes to convert.
+ * @param[in,out] pOutput The output from the conversion process (allocated/reallocated).
+ *
+ * @return A status code.
+ * @retval FwdLockConv_Status_OK
+ * @retval FwdLockConv_Status_InvalidArgument
+ * @retval FwdLockConv_Status_OutOfMemory
+ * @retval FwdLockConv_Status_SyntaxError
+ * @retval FwdLockConv_Status_UnsupportedFileFormat
+ * @retval FwdLockConv_Status_UnsupportedContentTransferEncoding
+ * @retval FwdLockConv_Status_RandomNumberGenerationFailed
+ * @retval FwdLockConv_Status_KeyEncryptionFailed
+ * @retval FwdLockConv_Status_DataEncryptionFailed
+ */
+FwdLockConv_Status_t FwdLockConv_ConvertData(int sessionId,
+ const void *pBuffer,
+ size_t numBytes,
+ FwdLockConv_Output_t *pOutput);
+
+/**
+ * Closes a session for converting an OMA DRM v1 Forward Lock file to the internal Forward Lock
+ * file format. The caller must update the produced output file at the indicated file offset with
+ * the final set of signatures.
+ *
+ * @param[in] sessionId The session ID.
+ * @param[in,out] pOutput The output from the conversion process (deallocated and overwritten).
+ *
+ * @return A status code.
+ * @retval FwdLockConv_Status_OK
+ * @retval FwdLockConv_Status_InvalidArgument
+ * @retval FwdLockConv_Status_OutOfMemory
+ * @retval FwdLockConv_Status_IntegrityProtectionFailed
+ */
+FwdLockConv_Status_t FwdLockConv_CloseSession(int sessionId, FwdLockConv_Output_t *pOutput);
+
+/**
+ * Converts an open OMA DRM v1 Forward Lock file to the internal Forward Lock file format in pull
+ * mode.
+ *
+ * @param[in] inputFileDesc The file descriptor of the open input file.
+ * @param[in] fpReadFunc A reference to a read function that can operate on the open input file.
+ * @param[in] outputFileDesc The file descriptor of the open output file.
+ * @param[in] fpWriteFunc A reference to a write function that can operate on the open output file.
+ * @param[in] fpLSeekFunc A reference to an lseek function that can operate on the open output file.
+ * @param[out] pErrorPos
+ * The file position where the error occurred, in the case of a syntax error. May be NULL.
+ *
+ * @return A status code.
+ * @retval FwdLockConv_Status_OK
+ * @retval FwdLockConv_Status_InvalidArgument
+ * @retval FwdLockConv_Status_OutOfMemory
+ * @retval FwdLockConv_Status_FileReadError
+ * @retval FwdLockConv_Status_FileWriteError
+ * @retval FwdLockConv_Status_FileSeekError
+ * @retval FwdLockConv_Status_SyntaxError
+ * @retval FwdLockConv_Status_UnsupportedFileFormat
+ * @retval FwdLockConv_Status_UnsupportedContentTransferEncoding
+ * @retval FwdLockConv_Status_RandomNumberGenerationFailed
+ * @retval FwdLockConv_Status_KeyEncryptionFailed
+ * @retval FwdLockConv_Status_DataEncryptionFailed
+ * @retval FwdLockConv_Status_IntegrityProtectionFailed
+ * @retval FwdLockConv_Status_TooManySessions
+ */
+FwdLockConv_Status_t FwdLockConv_ConvertOpenFile(int inputFileDesc,
+ FwdLockConv_ReadFunc_t *fpReadFunc,
+ int outputFileDesc,
+ FwdLockConv_WriteFunc_t *fpWriteFunc,
+ FwdLockConv_LSeekFunc_t *fpLSeekFunc,
+ off64_t *pErrorPos);
+
+/**
+ * Converts an OMA DRM v1 Forward Lock file to the internal Forward Lock file format in pull mode.
+ *
+ * @param[in] pInputFilename A reference to the input filename.
+ * @param[in] pOutputFilename A reference to the output filename.
+ * @param[out] pErrorPos
+ * The file position where the error occurred, in the case of a syntax error. May be NULL.
+ *
+ * @return A status code.
+ * @retval FwdLockConv_Status_OK
+ * @retval FwdLockConv_Status_InvalidArgument
+ * @retval FwdLockConv_Status_OutOfMemory
+ * @retval FwdLockConv_Status_FileNotFound
+ * @retval FwdLockConv_Status_FileCreationFailed
+ * @retval FwdLockConv_Status_FileReadError
+ * @retval FwdLockConv_Status_FileWriteError
+ * @retval FwdLockConv_Status_FileSeekError
+ * @retval FwdLockConv_Status_SyntaxError
+ * @retval FwdLockConv_Status_UnsupportedFileFormat
+ * @retval FwdLockConv_Status_UnsupportedContentTransferEncoding
+ * @retval FwdLockConv_Status_RandomNumberGenerationFailed
+ * @retval FwdLockConv_Status_KeyEncryptionFailed
+ * @retval FwdLockConv_Status_DataEncryptionFailed
+ * @retval FwdLockConv_Status_IntegrityProtectionFailed
+ * @retval FwdLockConv_Status_TooManySessions
+ */
+FwdLockConv_Status_t FwdLockConv_ConvertFile(const char *pInputFilename,
+ const char *pOutputFilename,
+ off64_t *pErrorPos);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __FWDLOCKCONV_H__
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk
new file mode 100644
index 0000000..b625edf
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/Android.mk
@@ -0,0 +1,37 @@
+#
+# 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.
+#
+LOCAL_PATH := $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+ FwdLockFile.c
+
+LOCAL_C_INCLUDES := \
+ frameworks/base/drm/libdrmframework/plugins/forward-lock/internal-format/common \
+ external/openssl/include
+
+LOCAL_SHARED_LIBRARIES := libcrypto
+
+LOCAL_WHOLE_STATIC_LIBRARIES := libfwdlock-common
+
+LOCAL_STATIC_LIBRARIES := libfwdlock-common
+
+LOCAL_MODULE := libfwdlock-decoder
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_STATIC_LIBRARY)
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
new file mode 100644
index 0000000..98284e72
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.c
@@ -0,0 +1,447 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <openssl/aes.h>
+#include <openssl/hmac.h>
+
+#include "FwdLockFile.h"
+#include "FwdLockGlue.h"
+
+#define TRUE 1
+#define FALSE 0
+
+#define INVALID_OFFSET ((off64_t)-1)
+
+#define INVALID_BLOCK_INDEX ((uint64_t)-1)
+
+#define MAX_NUM_SESSIONS 128
+
+#define KEY_SIZE AES_BLOCK_SIZE
+#define KEY_SIZE_IN_BITS (KEY_SIZE * 8)
+
+#define SHA1_HASH_SIZE 20
+#define SHA1_BLOCK_SIZE 64
+
+#define FWD_LOCK_VERSION 0
+#define FWD_LOCK_SUBFORMAT 0
+#define USAGE_RESTRICTION_FLAGS 0
+#define CONTENT_TYPE_LENGTH_POS 7
+#define TOP_HEADER_SIZE 8
+
+#define SIG_CALC_BUFFER_SIZE (16 * SHA1_BLOCK_SIZE)
+
+/**
+ * Data type for the per-file state information needed by the decoder.
+ */
+typedef struct FwdLockFile_Session {
+ int fileDesc;
+ unsigned char topHeader[TOP_HEADER_SIZE];
+ char *pContentType;
+ size_t contentTypeLength;
+ void *pEncryptedSessionKey;
+ size_t encryptedSessionKeyLength;
+ unsigned char dataSignature[SHA1_HASH_SIZE];
+ unsigned char headerSignature[SHA1_HASH_SIZE];
+ off64_t dataOffset;
+ off64_t filePos;
+ AES_KEY encryptionRoundKeys;
+ HMAC_CTX signingContext;
+ unsigned char keyStream[AES_BLOCK_SIZE];
+ uint64_t blockIndex;
+} FwdLockFile_Session_t;
+
+static FwdLockFile_Session_t *sessionPtrs[MAX_NUM_SESSIONS] = { NULL };
+
+static pthread_mutex_t sessionAcquisitionMutex = PTHREAD_MUTEX_INITIALIZER;
+
+static const unsigned char topHeaderTemplate[] =
+ { 'F', 'W', 'L', 'K', FWD_LOCK_VERSION, FWD_LOCK_SUBFORMAT, USAGE_RESTRICTION_FLAGS };
+
+/**
+ * Acquires an unused file session for the given file descriptor.
+ *
+ * @param[in] fileDesc A file descriptor.
+ *
+ * @return A session ID.
+ */
+static int FwdLockFile_AcquireSession(int fileDesc) {
+ int sessionId = -1;
+ if (fileDesc < 0) {
+ errno = EBADF;
+ } else {
+ int i;
+ pthread_mutex_lock(&sessionAcquisitionMutex);
+ for (i = 0; i < MAX_NUM_SESSIONS; ++i) {
+ int candidateSessionId = (fileDesc + i) % MAX_NUM_SESSIONS;
+ if (sessionPtrs[candidateSessionId] == NULL) {
+ sessionPtrs[candidateSessionId] = malloc(sizeof **sessionPtrs);
+ if (sessionPtrs[candidateSessionId] != NULL) {
+ sessionPtrs[candidateSessionId]->fileDesc = fileDesc;
+ sessionPtrs[candidateSessionId]->pContentType = NULL;
+ sessionPtrs[candidateSessionId]->pEncryptedSessionKey = NULL;
+ sessionId = candidateSessionId;
+ }
+ break;
+ }
+ }
+ pthread_mutex_unlock(&sessionAcquisitionMutex);
+ if (i == MAX_NUM_SESSIONS) {
+ errno = ENFILE;
+ }
+ }
+ return sessionId;
+}
+
+/**
+ * Finds the file session associated to the given file descriptor.
+ *
+ * @param[in] fileDesc A file descriptor.
+ *
+ * @return A session ID.
+ */
+static int FwdLockFile_FindSession(int fileDesc) {
+ int sessionId = -1;
+ if (fileDesc < 0) {
+ errno = EBADF;
+ } else {
+ int i;
+ pthread_mutex_lock(&sessionAcquisitionMutex);
+ for (i = 0; i < MAX_NUM_SESSIONS; ++i) {
+ int candidateSessionId = (fileDesc + i) % MAX_NUM_SESSIONS;
+ if (sessionPtrs[candidateSessionId] != NULL &&
+ sessionPtrs[candidateSessionId]->fileDesc == fileDesc) {
+ sessionId = candidateSessionId;
+ break;
+ }
+ }
+ pthread_mutex_unlock(&sessionAcquisitionMutex);
+ if (i == MAX_NUM_SESSIONS) {
+ errno = EBADF;
+ }
+ }
+ return sessionId;
+}
+
+/**
+ * Releases a file session.
+ *
+ * @param[in] sessionID A session ID.
+ */
+static void FwdLockFile_ReleaseSession(int sessionId) {
+ pthread_mutex_lock(&sessionAcquisitionMutex);
+ assert(0 <= sessionId && sessionId < MAX_NUM_SESSIONS && sessionPtrs[sessionId] != NULL);
+ free(sessionPtrs[sessionId]->pContentType);
+ free(sessionPtrs[sessionId]->pEncryptedSessionKey);
+ memset(sessionPtrs[sessionId], 0, sizeof *sessionPtrs[sessionId]); // Zero out key data.
+ free(sessionPtrs[sessionId]);
+ sessionPtrs[sessionId] = NULL;
+ pthread_mutex_unlock(&sessionAcquisitionMutex);
+}
+
+/**
+ * Derives keys for encryption and signing from the encrypted session key.
+ *
+ * @param[in,out] pSession A reference to a file session.
+ *
+ * @return A Boolean value indicating whether key derivation was successful.
+ */
+static int FwdLockFile_DeriveKeys(FwdLockFile_Session_t * pSession) {
+ int result;
+ struct FwdLockFile_DeriveKeys_Data {
+ AES_KEY sessionRoundKeys;
+ unsigned char value[KEY_SIZE];
+ unsigned char key[KEY_SIZE];
+ } *pData = malloc(sizeof *pData);
+ if (pData == NULL) {
+ result = FALSE;
+ } else {
+ result = FwdLockGlue_DecryptKey(pSession->pEncryptedSessionKey,
+ pSession->encryptedSessionKeyLength, pData->key, KEY_SIZE);
+ if (result) {
+ if (AES_set_encrypt_key(pData->key, KEY_SIZE_IN_BITS, &pData->sessionRoundKeys) != 0) {
+ result = FALSE;
+ } else {
+ // Encrypt the 16-byte value {0, 0, ..., 0} to produce the encryption key.
+ memset(pData->value, 0, KEY_SIZE);
+ AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys);
+ if (AES_set_encrypt_key(pData->key, KEY_SIZE_IN_BITS,
+ &pSession->encryptionRoundKeys) != 0) {
+ result = FALSE;
+ } else {
+ // Encrypt the 16-byte value {1, 0, ..., 0} to produce the signing key.
+ ++pData->value[0];
+ AES_encrypt(pData->value, pData->key, &pData->sessionRoundKeys);
+ HMAC_CTX_init(&pSession->signingContext);
+ HMAC_Init_ex(&pSession->signingContext, pData->key, KEY_SIZE, EVP_sha1(), NULL);
+ }
+ }
+ }
+ if (!result) {
+ errno = ENOSYS;
+ }
+ memset(pData, 0, sizeof pData); // Zero out key data.
+ free(pData);
+ }
+ return result;
+}
+
+/**
+ * Calculates the counter, treated as a 16-byte little-endian number, used to generate the keystream
+ * for the given block.
+ *
+ * @param[in] pNonce A reference to the nonce.
+ * @param[in] blockIndex The index number of the block.
+ * @param[out] pCounter A reference to the counter.
+ */
+static void FwdLockFile_CalculateCounter(const unsigned char *pNonce,
+ uint64_t blockIndex,
+ unsigned char *pCounter) {
+ unsigned char carry = 0;
+ size_t i = 0;
+ for (; i < sizeof blockIndex; ++i) {
+ unsigned char part = pNonce[i] + (unsigned char)(blockIndex >> (i * CHAR_BIT));
+ pCounter[i] = part + carry;
+ carry = (part < pNonce[i] || pCounter[i] < part) ? 1 : 0;
+ }
+ for (; i < AES_BLOCK_SIZE; ++i) {
+ pCounter[i] = pNonce[i] + carry;
+ carry = (pCounter[i] < pNonce[i]) ? 1 : 0;
+ }
+}
+
+/**
+ * Decrypts the byte at the current file position using AES-128-CTR. In CTR (or "counter") mode,
+ * encryption and decryption are performed using the same algorithm.
+ *
+ * @param[in,out] pSession A reference to a file session.
+ * @param[in] pByte The byte to decrypt.
+ */
+void FwdLockFile_DecryptByte(FwdLockFile_Session_t * pSession, unsigned char *pByte) {
+ uint64_t blockIndex = pSession->filePos / AES_BLOCK_SIZE;
+ uint64_t blockOffset = pSession->filePos % AES_BLOCK_SIZE;
+ if (blockIndex != pSession->blockIndex) {
+ // The first 16 bytes of the encrypted session key is used as the nonce.
+ unsigned char counter[AES_BLOCK_SIZE];
+ FwdLockFile_CalculateCounter(pSession->pEncryptedSessionKey, blockIndex, counter);
+ AES_encrypt(counter, pSession->keyStream, &pSession->encryptionRoundKeys);
+ pSession->blockIndex = blockIndex;
+ }
+ *pByte ^= pSession->keyStream[blockOffset];
+}
+
+int FwdLockFile_attach(int fileDesc) {
+ int sessionId = FwdLockFile_AcquireSession(fileDesc);
+ if (sessionId >= 0) {
+ FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
+ int isSuccess = FALSE;
+ if (read(fileDesc, pSession->topHeader, TOP_HEADER_SIZE) == TOP_HEADER_SIZE &&
+ memcmp(pSession->topHeader, topHeaderTemplate, sizeof topHeaderTemplate) == 0) {
+ pSession->contentTypeLength = pSession->topHeader[CONTENT_TYPE_LENGTH_POS];
+ assert(pSession->contentTypeLength <= UCHAR_MAX); // Untaint scalar for code checkers.
+ pSession->pContentType = malloc(pSession->contentTypeLength + 1);
+ if (pSession->pContentType != NULL &&
+ read(fileDesc, pSession->pContentType, pSession->contentTypeLength) ==
+ (ssize_t)pSession->contentTypeLength) {
+ pSession->pContentType[pSession->contentTypeLength] = '\0';
+ pSession->encryptedSessionKeyLength = FwdLockGlue_GetEncryptedKeyLength(KEY_SIZE);
+ pSession->pEncryptedSessionKey = malloc(pSession->encryptedSessionKeyLength);
+ if (pSession->pEncryptedSessionKey != NULL &&
+ read(fileDesc, pSession->pEncryptedSessionKey,
+ pSession->encryptedSessionKeyLength) ==
+ (ssize_t)pSession->encryptedSessionKeyLength &&
+ read(fileDesc, pSession->dataSignature, SHA1_HASH_SIZE) ==
+ SHA1_HASH_SIZE &&
+ read(fileDesc, pSession->headerSignature, SHA1_HASH_SIZE) ==
+ SHA1_HASH_SIZE) {
+ isSuccess = FwdLockFile_DeriveKeys(pSession);
+ }
+ }
+ }
+ if (isSuccess) {
+ pSession->dataOffset = pSession->contentTypeLength +
+ pSession->encryptedSessionKeyLength + TOP_HEADER_SIZE + 2 * SHA1_HASH_SIZE;
+ pSession->filePos = 0;
+ pSession->blockIndex = INVALID_BLOCK_INDEX;
+ } else {
+ FwdLockFile_ReleaseSession(sessionId);
+ sessionId = -1;
+ }
+ }
+ return (sessionId >= 0) ? 0 : -1;
+}
+
+int FwdLockFile_open(const char *pFilename) {
+ int fileDesc = open(pFilename, O_RDONLY);
+ if (fileDesc >= 0 && FwdLockFile_attach(fileDesc) < 0) {
+ (void)close(fileDesc);
+ fileDesc = -1;
+ }
+ return fileDesc;
+}
+
+ssize_t FwdLockFile_read(int fileDesc, void *pBuffer, size_t numBytes) {
+ ssize_t numBytesRead;
+ int sessionId = FwdLockFile_FindSession(fileDesc);
+ if (sessionId < 0) {
+ numBytesRead = -1;
+ } else {
+ FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
+ ssize_t i;
+ numBytesRead = read(pSession->fileDesc, pBuffer, numBytes);
+ for (i = 0; i < numBytesRead; ++i) {
+ FwdLockFile_DecryptByte(pSession, &((unsigned char *)pBuffer)[i]);
+ ++pSession->filePos;
+ }
+ }
+ return numBytesRead;
+}
+
+off64_t FwdLockFile_lseek(int fileDesc, off64_t offset, int whence) {
+ off64_t newFilePos;
+ int sessionId = FwdLockFile_FindSession(fileDesc);
+ if (sessionId < 0) {
+ newFilePos = INVALID_OFFSET;
+ } else {
+ FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
+ switch (whence) {
+ case SEEK_SET:
+ newFilePos = lseek64(pSession->fileDesc, pSession->dataOffset + offset, whence);
+ break;
+ case SEEK_CUR:
+ case SEEK_END:
+ newFilePos = lseek64(pSession->fileDesc, offset, whence);
+ break;
+ default:
+ errno = EINVAL;
+ newFilePos = INVALID_OFFSET;
+ break;
+ }
+ if (newFilePos != INVALID_OFFSET) {
+ if (newFilePos < pSession->dataOffset) {
+ // The new file position is illegal for an internal Forward Lock file. Restore the
+ // original file position.
+ (void)lseek64(pSession->fileDesc, pSession->dataOffset + pSession->filePos,
+ SEEK_SET);
+ errno = EINVAL;
+ newFilePos = INVALID_OFFSET;
+ } else {
+ // The return value should be the file position that lseek64() would have returned
+ // for the embedded content file.
+ pSession->filePos = newFilePos - pSession->dataOffset;
+ newFilePos = pSession->filePos;
+ }
+ }
+ }
+ return newFilePos;
+}
+
+int FwdLockFile_detach(int fileDesc) {
+ int sessionId = FwdLockFile_FindSession(fileDesc);
+ if (sessionId < 0) {
+ return -1;
+ }
+ HMAC_CTX_cleanup(&sessionPtrs[sessionId]->signingContext);
+ FwdLockFile_ReleaseSession(sessionId);
+ return 0;
+}
+
+int FwdLockFile_close(int fileDesc) {
+ return (FwdLockFile_detach(fileDesc) == 0) ? close(fileDesc) : -1;
+}
+
+int FwdLockFile_CheckDataIntegrity(int fileDesc) {
+ int result;
+ int sessionId = FwdLockFile_FindSession(fileDesc);
+ if (sessionId < 0) {
+ result = FALSE;
+ } else {
+ struct FwdLockFile_CheckDataIntegrity_Data {
+ unsigned char signature[SHA1_HASH_SIZE];
+ unsigned char buffer[SIG_CALC_BUFFER_SIZE];
+ } *pData = malloc(sizeof *pData);
+ if (pData == NULL) {
+ result = FALSE;
+ } else {
+ FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
+ if (lseek64(pSession->fileDesc, pSession->dataOffset, SEEK_SET) !=
+ pSession->dataOffset) {
+ result = FALSE;
+ } else {
+ ssize_t numBytesRead;
+ size_t signatureSize = SHA1_HASH_SIZE;
+ while ((numBytesRead =
+ read(pSession->fileDesc, pData->buffer, SIG_CALC_BUFFER_SIZE)) > 0) {
+ HMAC_Update(&pSession->signingContext, pData->buffer, (size_t)numBytesRead);
+ }
+ if (numBytesRead < 0) {
+ result = FALSE;
+ } else {
+ HMAC_Final(&pSession->signingContext, pData->signature, &signatureSize);
+ assert(signatureSize == SHA1_HASH_SIZE);
+ result = memcmp(pData->signature, pSession->dataSignature, signatureSize) == 0;
+ }
+ HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
+ (void)lseek64(pSession->fileDesc, pSession->dataOffset + pSession->filePos,
+ SEEK_SET);
+ }
+ free(pData);
+ }
+ }
+ return result;
+}
+
+int FwdLockFile_CheckHeaderIntegrity(int fileDesc) {
+ int result;
+ int sessionId = FwdLockFile_FindSession(fileDesc);
+ if (sessionId < 0) {
+ result = FALSE;
+ } else {
+ FwdLockFile_Session_t *pSession = sessionPtrs[sessionId];
+ unsigned char signature[SHA1_HASH_SIZE];
+ size_t signatureSize = SHA1_HASH_SIZE;
+ HMAC_Update(&pSession->signingContext, pSession->topHeader, TOP_HEADER_SIZE);
+ HMAC_Update(&pSession->signingContext, (unsigned char *)pSession->pContentType,
+ pSession->contentTypeLength);
+ HMAC_Update(&pSession->signingContext, pSession->pEncryptedSessionKey,
+ pSession->encryptedSessionKeyLength);
+ HMAC_Update(&pSession->signingContext, pSession->dataSignature, signatureSize);
+ HMAC_Final(&pSession->signingContext, signature, &signatureSize);
+ assert(signatureSize == SHA1_HASH_SIZE);
+ result = memcmp(signature, pSession->headerSignature, signatureSize) == 0;
+ HMAC_Init_ex(&pSession->signingContext, NULL, KEY_SIZE, NULL, NULL);
+ }
+ return result;
+}
+
+int FwdLockFile_CheckIntegrity(int fileDesc) {
+ return FwdLockFile_CheckHeaderIntegrity(fileDesc) && FwdLockFile_CheckDataIntegrity(fileDesc);
+}
+
+const char *FwdLockFile_GetContentType(int fileDesc) {
+ int sessionId = FwdLockFile_FindSession(fileDesc);
+ if (sessionId < 0) {
+ return NULL;
+ }
+ return sessionPtrs[sessionId]->pContentType;
+}
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.h b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.h
new file mode 100644
index 0000000..fc64050
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/decoder/FwdLockFile.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __FWDLOCKFILE_H__
+#define __FWDLOCKFILE_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+
+/**
+ * Attaches to an open Forward Lock file. The file position is assumed to be at the beginning of the
+ * file.
+ *
+ * @param[in] fileDesc The file descriptor of an open Forward Lock file.
+ *
+ * @return A status code.
+ * @retval 0 Success.
+ * @retval -1 Failure.
+ */
+int FwdLockFile_attach(int fileDesc);
+
+/**
+ * Opens a Forward Lock file for reading.
+ *
+ * @param[in] pFilename A reference to a filename.
+ *
+ * @return A file descriptor.
+ * @retval -1 Failure.
+ */
+int FwdLockFile_open(const char *pFilename);
+
+/**
+ * Reads the specified number of bytes from an open Forward Lock file.
+ *
+ * @param[in] fileDesc The file descriptor of an open Forward Lock file.
+ * @param[out] pBuffer A reference to the buffer that should receive the read data.
+ * @param[in] numBytes The number of bytes to read.
+ *
+ * @return The number of bytes read.
+ * @retval -1 Failure.
+ */
+ssize_t FwdLockFile_read(int fileDesc, void *pBuffer, size_t numBytes);
+
+/**
+ * Updates the file position within an open Forward Lock file.
+ *
+ * @param[in] fileDesc The file descriptor of an open Forward Lock file.
+ * @param[in] offset The offset with which to update the file position.
+ * @param[in] whence One of SEEK_SET, SEEK_CUR, and SEEK_END.
+ *
+ * @return The new file position.
+ * @retval ((off64_t)-1) Failure.
+ */
+off64_t FwdLockFile_lseek(int fileDesc, off64_t offset, int whence);
+
+/**
+ * Detaches from an open Forward Lock file.
+ *
+ * @param[in] fileDesc The file descriptor of an open Forward Lock file.
+ *
+ * @return A status code.
+ * @retval 0 Success.
+ * @retval -1 Failure.
+ */
+int FwdLockFile_detach(int fileDesc);
+
+/**
+ * Closes an open Forward Lock file.
+ *
+ * @param[in] fileDesc The file descriptor of an open Forward Lock file.
+ *
+ * @return A status code.
+ * @retval 0 Success.
+ * @retval -1 Failure.
+ */
+int FwdLockFile_close(int fileDesc);
+
+/**
+ * Checks the data integrity of an open Forward Lock file.
+ *
+ * @param[in] fileDesc The file descriptor of an open Forward Lock file.
+ *
+ * @return A Boolean value indicating whether the integrity check was successful.
+ */
+int FwdLockFile_CheckDataIntegrity(int fileDesc);
+
+/**
+ * Checks the header integrity of an open Forward Lock file.
+ *
+ * @param[in] fileDesc The file descriptor of an open Forward Lock file.
+ *
+ * @return A Boolean value indicating whether the integrity check was successful.
+ */
+int FwdLockFile_CheckHeaderIntegrity(int fileDesc);
+
+/**
+ * Checks both the data and header integrity of an open Forward Lock file.
+ *
+ * @param[in] fileDesc The file descriptor of an open Forward Lock file.
+ *
+ * @return A Boolean value indicating whether the integrity check was successful.
+ */
+int FwdLockFile_CheckIntegrity(int fileDesc);
+
+/**
+ * Returns the content type of an open Forward Lock file.
+ *
+ * @param[in] fileDesc The file descriptor of an open Forward Lock file.
+ *
+ * @return
+ * A reference to the content type. The reference remains valid as long as the file is kept open.
+ */
+const char *FwdLockFile_GetContentType(int fileDesc);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // __FWDLOCKFILE_H__
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/doc/FwdLock.html b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/FwdLock.html
new file mode 100755
index 0000000..8f95cd2
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/FwdLock.html
@@ -0,0 +1,1039 @@
+<html>
+
+<head>
+<meta http-equiv=Content-Type content="text/html; charset=windows-1252">
+<meta name=Generator content="Microsoft Word 12 (filtered)">
+<title>Forward Lock Converter and Decoder</title>
+<style>
+<!--
+ /* Font Definitions */
+ @font-face
+ {font-family:SimSun;
+ panose-1:2 1 6 0 3 1 1 1 1 1;}
+@font-face
+ {font-family:"Cambria Math";
+ panose-1:2 4 5 3 5 4 6 3 2 4;}
+@font-face
+ {font-family:Tahoma;
+ panose-1:2 11 6 4 3 5 4 4 2 4;}
+@font-face
+ {font-family:"Lucida Console","DejaVu Sans Mono";
+ panose-1:2 11 6 9 4 5 4 2 2 4;}
+@font-face
+ {font-family:"\@SimSun";
+ panose-1:2 1 6 0 3 1 1 1 1 1;}
+ /* Style Definitions */
+ p.MsoNormal, li.MsoNormal, div.MsoNormal
+ {margin:0cm;
+ margin-bottom:.0001pt;
+ font-size:12.0pt;
+ font-family:"Times New Roman","serif";}
+h1
+ {margin-right:0cm;
+ margin-left:21.6pt;
+ text-indent:-21.6pt;
+ page-break-after:avoid;
+ font-size:16.0pt;
+ font-family:"Arial","sans-serif";}
+h2
+ {margin-top:12.0pt;
+ margin-right:0cm;
+ margin-bottom:3.0pt;
+ margin-left:28.8pt;
+ text-indent:-28.8pt;
+ page-break-after:avoid;
+ font-size:14.0pt;
+ font-family:"Arial","sans-serif";
+ font-style:italic;}
+h3
+ {margin-top:12.0pt;
+ margin-right:0cm;
+ margin-bottom:3.0pt;
+ margin-left:36.0pt;
+ text-indent:-36.0pt;
+ page-break-after:avoid;
+ font-size:13.0pt;
+ font-family:"Arial","sans-serif";}
+h4
+ {margin-top:12.0pt;
+ margin-right:0cm;
+ margin-bottom:3.0pt;
+ margin-left:43.2pt;
+ text-indent:-43.2pt;
+ page-break-after:avoid;
+ font-size:14.0pt;
+ font-family:"Times New Roman","serif";}
+h5
+ {margin-top:12.0pt;
+ margin-right:0cm;
+ margin-bottom:3.0pt;
+ margin-left:50.4pt;
+ text-indent:-50.4pt;
+ font-size:13.0pt;
+ font-family:"Times New Roman","serif";
+ font-style:italic;}
+h6
+ {margin-top:12.0pt;
+ margin-right:0cm;
+ margin-bottom:3.0pt;
+ margin-left:57.6pt;
+ text-indent:-57.6pt;
+ font-size:11.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoHeading7, li.MsoHeading7, div.MsoHeading7
+ {margin-top:12.0pt;
+ margin-right:0cm;
+ margin-bottom:3.0pt;
+ margin-left:64.8pt;
+ text-indent:-64.8pt;
+ font-size:12.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoHeading8, li.MsoHeading8, div.MsoHeading8
+ {margin-top:12.0pt;
+ margin-right:0cm;
+ margin-bottom:3.0pt;
+ margin-left:72.0pt;
+ text-indent:-72.0pt;
+ font-size:12.0pt;
+ font-family:"Times New Roman","serif";
+ font-style:italic;}
+p.MsoHeading9, li.MsoHeading9, div.MsoHeading9
+ {margin-top:12.0pt;
+ margin-right:0cm;
+ margin-bottom:3.0pt;
+ margin-left:79.2pt;
+ text-indent:-79.2pt;
+ font-size:11.0pt;
+ font-family:"Arial","sans-serif";}
+p.MsoToc1, li.MsoToc1, div.MsoToc1
+ {margin-top:6.0pt;
+ margin-right:0cm;
+ margin-bottom:6.0pt;
+ margin-left:0cm;
+ line-height:150%;
+ font-size:10.5pt;
+ font-family:"Times New Roman","serif";
+ text-transform:uppercase;
+ font-weight:bold;}
+p.MsoToc2, li.MsoToc2, div.MsoToc2
+ {margin-top:0cm;
+ margin-right:0cm;
+ margin-bottom:0cm;
+ margin-left:12.0pt;
+ margin-bottom:.0001pt;
+ line-height:150%;
+ font-size:10.5pt;
+ font-family:"Times New Roman","serif";
+ font-variant:small-caps;}
+p.MsoToc3, li.MsoToc3, div.MsoToc3
+ {margin-top:0cm;
+ margin-right:0cm;
+ margin-bottom:0cm;
+ margin-left:24.0pt;
+ margin-bottom:.0001pt;
+ line-height:150%;
+ font-size:10.5pt;
+ font-family:"Times New Roman","serif";
+ font-style:italic;}
+p.MsoToc4, li.MsoToc4, div.MsoToc4
+ {margin-top:0cm;
+ margin-right:0cm;
+ margin-bottom:0cm;
+ margin-left:36.0pt;
+ margin-bottom:.0001pt;
+ font-size:9.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoToc5, li.MsoToc5, div.MsoToc5
+ {margin-top:0cm;
+ margin-right:0cm;
+ margin-bottom:0cm;
+ margin-left:48.0pt;
+ margin-bottom:.0001pt;
+ font-size:9.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoToc6, li.MsoToc6, div.MsoToc6
+ {margin-top:0cm;
+ margin-right:0cm;
+ margin-bottom:0cm;
+ margin-left:60.0pt;
+ margin-bottom:.0001pt;
+ font-size:9.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoToc7, li.MsoToc7, div.MsoToc7
+ {margin-top:0cm;
+ margin-right:0cm;
+ margin-bottom:0cm;
+ margin-left:72.0pt;
+ margin-bottom:.0001pt;
+ font-size:9.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoToc8, li.MsoToc8, div.MsoToc8
+ {margin-top:0cm;
+ margin-right:0cm;
+ margin-bottom:0cm;
+ margin-left:84.0pt;
+ margin-bottom:.0001pt;
+ font-size:9.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoToc9, li.MsoToc9, div.MsoToc9
+ {margin-top:0cm;
+ margin-right:0cm;
+ margin-bottom:0cm;
+ margin-left:96.0pt;
+ margin-bottom:.0001pt;
+ font-size:9.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoFootnoteText, li.MsoFootnoteText, div.MsoFootnoteText
+ {margin:0cm;
+ margin-bottom:.0001pt;
+ font-size:10.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoHeader, li.MsoHeader, div.MsoHeader
+ {margin:0cm;
+ margin-bottom:.0001pt;
+ font-size:12.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoFooter, li.MsoFooter, div.MsoFooter
+ {margin:0cm;
+ margin-bottom:.0001pt;
+ font-size:12.0pt;
+ font-family:"Times New Roman","serif";}
+p.MsoCaption, li.MsoCaption, div.MsoCaption
+ {margin:0cm;
+ margin-bottom:.0001pt;
+ font-size:11.0pt;
+ font-family:"Times New Roman","serif";
+ font-weight:bold;}
+span.MsoFootnoteReference
+ {vertical-align:super;}
+p.MsoTitle, li.MsoTitle, div.MsoTitle
+ {margin-top:12.0pt;
+ margin-right:0cm;
+ margin-bottom:120.0pt;
+ margin-left:0cm;
+ text-align:center;
+ font-size:16.0pt;
+ font-family:"Arial","sans-serif";
+ font-weight:bold;}
+p.MsoBodyText, li.MsoBodyText, div.MsoBodyText
+ {mso-style-link:"Body Text Char";
+ margin-top:0cm;
+ margin-right:0cm;
+ margin-bottom:6.0pt;
+ margin-left:0cm;
+ font-size:12.0pt;
+ font-family:"Times New Roman","serif";}
+a:link, span.MsoHyperlink
+ {color:blue;
+ text-decoration:underline;}
+a:visited, span.MsoHyperlinkFollowed
+ {color:purple;
+ text-decoration:underline;}
+p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
+ {margin:0cm;
+ margin-bottom:.0001pt;
+ font-size:8.0pt;
+ font-family:"Tahoma","sans-serif";}
+span.BodyTextChar
+ {mso-style-name:"Body Text Char";
+ mso-style-link:"Body Text";}
+ /* Page Definitions */
+ @page WordSection1
+ {size:595.45pt 841.7pt;
+ margin:72.0pt 90.0pt 72.0pt 90.0pt;}
+div.WordSection1
+ {page:WordSection1;}
+@page WordSection2
+ {size:595.45pt 841.7pt;
+ margin:72.0pt 90.0pt 72.0pt 90.0pt;}
+div.WordSection2
+ {page:WordSection2;}
+ /* List Definitions */
+ ol
+ {margin-bottom:0cm;}
+ul
+ {margin-bottom:0cm;}
+-->
+</style>
+
+</head>
+
+<body lang=EN-US link=blue vlink=purple>
+
+<div class=WordSection1>
+
+<p class=MsoTitle>Forward Lock Converter And Decoder</p>
+
+<p class=MsoToc1><span
+class=MsoHyperlink><a href="#_Toc276471422">1<span style='font-size:12.0pt;
+line-height:150%;color:windowtext;text-transform:none;font-weight:normal;
+text-decoration:none'> </span>Introduction<span style='color:windowtext;
+display:none;text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>3</span></a></span></p>
+
+<p class=MsoToc1><span class=MsoHyperlink><a href="#_Toc276471423">2<span
+style='font-size:12.0pt;line-height:150%;color:windowtext;text-transform:none;
+font-weight:normal;text-decoration:none'> </span>Overview<span
+style='color:windowtext;display:none;text-decoration:none'>... </span><span
+style='color:windowtext;display:none;text-decoration:none'>3</span></a></span></p>
+
+<p class=MsoToc1><span class=MsoHyperlink><a href="#_Toc276471424">3<span
+style='font-size:12.0pt;line-height:150%;color:windowtext;text-transform:none;
+font-weight:normal;text-decoration:none'> </span>Use Cases<span
+style='color:windowtext;display:none;text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>4</span></a></span></p>
+
+<p class=MsoToc2><span class=MsoHyperlink><span style='font-variant:normal !important;
+text-transform:uppercase'><a href="#_Toc276471425">3.1<span style='font-size:
+12.0pt;line-height:150%;color:windowtext;text-transform:none;text-decoration:
+none'> </span>Converter<span style='color:windowtext;display:none;
+text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>4</span></a></span></span></p>
+
+<p class=MsoToc3><span class=MsoHyperlink><a href="#_Toc276471426">3.1.1<span
+style='font-size:12.0pt;line-height:150%;color:windowtext;font-style:normal;
+text-decoration:none'> </span>Convert Data (Push-Mode Conversion)<span
+style='color:windowtext;display:none;text-decoration:none'> </span><span
+style='color:windowtext;display:none;text-decoration:none'>4</span></a></span></p>
+
+<p class=MsoToc3><span class=MsoHyperlink><a href="#_Toc276471427">3.1.2<span
+style='font-size:12.0pt;line-height:150%;color:windowtext;font-style:normal;
+text-decoration:none'> </span>Convert File (Pull-Mode Conversion)<span
+style='color:windowtext;display:none;text-decoration:none'> </span><span
+style='color:windowtext;display:none;text-decoration:none'>6</span></a></span></p>
+
+<p class=MsoToc2><span class=MsoHyperlink><span style='font-variant:normal !important;
+text-transform:uppercase'><a href="#_Toc276471428">3.2<span style='font-size:
+12.0pt;line-height:150%;color:windowtext;text-transform:none;text-decoration:
+none'> </span>Decoder<span style='color:windowtext;display:none;
+text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>7</span></a></span></span></p>
+
+<p class=MsoToc3><span class=MsoHyperlink><a href="#_Toc276471429">3.2.1<span
+style='font-size:12.0pt;line-height:150%;color:windowtext;font-style:normal;
+text-decoration:none'> </span>Check Integrity<span style='color:windowtext;
+display:none;text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>8</span></a></span></p>
+
+<p class=MsoToc3><span class=MsoHyperlink><a href="#_Toc276471430">3.2.2<span
+style='font-size:12.0pt;line-height:150%;color:windowtext;font-style:normal;
+text-decoration:none'> </span>Get Content Type<span style='color:windowtext;
+display:none;text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>9</span></a></span></p>
+
+<p class=MsoToc3><span class=MsoHyperlink><a href="#_Toc276471431">3.2.3<span
+style='font-size:12.0pt;line-height:150%;color:windowtext;font-style:normal;
+text-decoration:none'> </span>Decode File<span style='color:windowtext;
+display:none;text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>10</span></a></span></p>
+
+<p class=MsoToc1><span class=MsoHyperlink><a href="#_Toc276471432">4<span
+style='font-size:12.0pt;line-height:150%;color:windowtext;text-transform:none;
+font-weight:normal;text-decoration:none'> </span>Definition of the
+Internal Forward Lock File Format<span style='color:windowtext;display:none;
+text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>11</span></a></span></p>
+
+<p class=MsoToc2><span class=MsoHyperlink><span style='font-variant:normal !important;
+text-transform:uppercase'><a href="#_Toc276471433">4.1<span style='font-size:
+12.0pt;line-height:150%;color:windowtext;text-transform:none;text-decoration:
+none'> </span>Key Derivation<span style='color:windowtext;display:none;
+text-decoration:none'>.. </span><span
+style='color:windowtext;display:none;text-decoration:none'>11</span></a></span></span></p>
+
+<p class=MsoToc2><span class=MsoHyperlink><span style='font-variant:normal !important;
+text-transform:uppercase'><a href="#_Toc276471434">4.2<span style='font-size:
+12.0pt;line-height:150%;color:windowtext;text-transform:none;text-decoration:
+none'> </span>Calculation of the Counters<span style='color:windowtext;
+display:none;text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>12</span></a></span></span></p>
+
+<p class=MsoToc1><span class=MsoHyperlink><a href="#_Toc276471435">5<span
+style='font-size:12.0pt;line-height:150%;color:windowtext;text-transform:none;
+font-weight:normal;text-decoration:none'> </span>Unit Test Cases<span
+style='color:windowtext;display:none;text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>12</span></a></span></p>
+
+<p class=MsoToc1><span class=MsoHyperlink><a href="#_Toc276471436">6<span
+style='font-size:12.0pt;line-height:150%;color:windowtext;text-transform:none;
+font-weight:normal;text-decoration:none'> </span>References<span
+style='color:windowtext;display:none;text-decoration:none'>. </span><span
+style='color:windowtext;display:none;text-decoration:none'>12</span></a></span></p>
+
+<p class=MsoBodyText></p>
+
+</div>
+
+<span style='font-size:12.0pt;font-family:"Times New Roman","serif"'><br
+clear=all style='page-break-before:right'>
+</span>
+
+<div class=WordSection2>
+
+<h1><a name="_Toc276471422"></a><a name="_Ref263085474">1<span
+style='font:7.0pt "Times New Roman"'> </span>Introduction</a></h1>
+
+<p class=MsoBodyText>The internal Forward Lock file format is used for encrypting
+inherently unencrypted OMA DRM version 1 Forward Lock and Combined Delivery
+files so they can be securely stored on externally accessible file system partitions
+such as memory stick.</p>
+
+<p class=MsoBodyText>Our general strategy is to convert such <i>OMA DRM Message</i>
+(‘.dm’) files to internal Forward Lock (‘.fl’) files as soon as they are
+downloaded or otherwise transferred to the phone, and not actually provide any
+decoders for ‘.dm’ files.</p>
+
+<h1><a name="_Toc276471423">2<span style='font:7.0pt "Times New Roman"'>
+</span>Overview</a></h1>
+
+<p class=MsoBodyText>The <i>Forward Lock Converter</i> converts OMA DRM Message
+files to the internal file format. The <i>Forward Lock Decoder</i> provides a
+POSIX-level API for transparent reading and seeking through such a converted
+file as if it were unencrypted. The API also includes functions for checking a
+fileÂ’s integrity and getting the MIME type of its embedded content.</p>
+
+<p class=MsoBodyText style='margin-bottom:24.0pt'>The converter and decoder are
+built into two separate libraries, which share common code for random number
+generation and key encryption in a third library. For test purposes there is
+also a unit test application. See Figure 1.</p>
+
+<p class=MsoBodyText style='page-break-after:avoid'><img width=288 height=364
+src="images/image001.gif"></p>
+
+<p class=MsoCaption style='margin-top:12.0pt;margin-right:0cm;margin-bottom:
+12.0pt;margin-left:0cm'><a name="_Ref262730885">Figure </a>1. Block diagram illustrating the dependencies between the executable modules.</p>
+
+<b><span style='font-size:16.0pt;font-family:"Arial","sans-serif"'><br
+clear=all style='page-break-before:always'>
+</span></b>
+
+<h1><a name="_Toc276471424">3<span style='font:7.0pt "Times New Roman"'>
+</span>Use Cases</a></h1>
+
+<p class=MsoBodyText>This section describes all the use cases for the converter
+and decoder. It shows the sequence of API calls that should be used to solve
+these use cases.</p>
+
+<h2><a name="_Toc276471425">3.1<span style='font:7.0pt "Times New Roman"'>
+</span>Converter</a></h2>
+
+<p class=MsoBodyText>Through the converter API, conversion can be performed in one
+of two ways:</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>1.<span
+style='font:7.0pt "Times New Roman"'> </span><i>Push-mode
+conversion</i> is when the client progressively feeds data to the converter as
+it arrives. This is appropriate when data arrives gradually in chunks, with
+idle time in between. Consequently, push mode is used for converting files
+being downloaded through HTTP. See section 3.1.1.</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>2.<span
+style='font:7.0pt "Times New Roman"'> </span><i>Pull-mode
+conversion</i> is when the converter drives the process and consumes data from
+the client as it needs it. This is appropriate when the entire file to be
+converted is readily available. Hence, pull mode is used by the unit test application.
+See section 3.1.2.</p>
+
+<p class=MsoBodyText>Internally, pull-mode conversion is implemented in terms
+of the API for push-mode conversion.</p>
+
+<h3><a name="_Toc276471426"></a><a name="_Ref263085478">3.1.1<span
+style='font:7.0pt "Times New Roman"'> </span>Convert Data
+(Push-Mode Conversion)</a></h3>
+
+<p class=MsoBodyText>Push-mode conversion is performed as follows (see also Figure 2):</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>1.<span
+style='font:7.0pt "Times New Roman"'> </span><span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockConv_OpenSession</span>
+initializes the output parameter and returns a <i>session ID</i> to be used in
+subsequent calls to the API. The output parameter is a union of return values
+whose correct use at any given moment is determined by the API function last
+called.</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>2.<span
+style='font:7.0pt "Times New Roman"'> </span><span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockConv_ConvertData</span>
+is called repeatedly until no more input data remains. Each call converts the
+maximum amount of data possible and writes it to the output buffer. The client then
+writes this data to file.</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>3.<span
+style='font:7.0pt "Times New Roman"'> </span><span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockConv_CloseSession</span>
+cleans up the session and deallocates the output buffer. If all has gone well, a
+two-part cryptographic signature of the output file is calculated. The client
+must go back and rewrite part of the file header with this updated signature
+information.</p>
+
+<p class=MsoBodyText>Every time a file is being converted, the converter calls <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockGlue_GetRandomNumber</span>
+to generate a new, unique session key. No two converted files look alike, even
+if the original files are the same.</p>
+
+<p class=MsoBodyText><b>Note:</b> The random bytes cannot come from any bare-minimum
+implementation of the C-library <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>rand</span>
+function—they must be cryptographically secure. Otherwise, security will be
+compromised.</p>
+
+<p class=MsoBodyText>The session key is encrypted and stored within the
+converted file. Key encryption is performed using <span style='font-size:10.0pt;
+font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockGlue_GetEncryptedKeyLength</span> and <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockGlue_EncryptKey</span>.
+These two functions, together with the corresponding decryption function (<span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockGlue_DecryptKey</span>),
+are the integration points where an OEM manufacturer may implement their own
+key-encryption scheme.</p>
+
+<p class=MsoBodyText><b>Note:</b> The key-encryption key must be unique to each
+device; this is what makes the files forward lock–protected. Ideally, it should
+be derived from secret hardware parameters, but at the very least it should be
+persistent from one master reset to the next.</p>
+
+<div style='margin-bottom:24.0pt;border:solid windowtext 1.0pt;padding:1.0pt 4.0pt 1.0pt 4.0pt;
+background:#F2F2F2'>
+
+<p class=MsoBodyText style='background:#F2F2F2;border:
+none;padding:0cm'><b>Note:</b> In the open-source implementation of the <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>libfwdlock-common</span>
+library, a random key-encryption key is generated and stored in plaintext in
+the file system, without being obfuscated in any way (doing so would be futile
+since the source code is openly available). This key must be kept secret from
+the user, and shouldnÂ’t be possible to extract through backup-and-restore
+functionality or the like. OEM manufacturers will probably want to implement a
+truly hardware-based device-unique key.</p>
+
+</div>
+
+<p class=MsoBodyText style='page-break-after:avoid'><img width=531 height=563
+src="images/image002.gif"></p>
+
+<p class=MsoCaption style='margin-top:6.0pt;margin-right:0cm;margin-bottom:
+12.0pt;margin-left:0cm'><a name="_Ref263085187">Figure </a>2. Converter UC: Convert Data.</p>
+
+<b><span style='font-size:13.0pt;font-family:"Arial","sans-serif"'><br
+clear=all style='page-break-before:always'>
+</span></b>
+
+<h3><a name="_Toc276471427"></a><a name="_Ref263163082">3.1.2<span
+style='font:7.0pt "Times New Roman"'> </span>Convert File
+(Pull-Mode Conversion)</a></h3>
+
+<p class=MsoBodyText>Pull-mode conversion is performed by calling <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_ConvertFile</span>
+with the filename, unless there is need for a specialized <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>read</span> function, in
+which case <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_ConvertOpenFile</span>
+should be used directly instead. See Figure 3.</p>
+
+<p class=MsoBodyText style='margin-bottom:24.0pt'>Internally, <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_ConvertFile</span>
+calls <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_ConvertOpenFile</span>.
+The latter then proceeds with the conversion using the push-mode API, acting as
+the client in the previous use case; see section 3.1.1.</p>
+
+<p class=MsoBodyText style='page-break-after:avoid'><img width=531 height=731
+src="images/image003.gif"></p>
+
+<p class=MsoCaption style='margin-top:6.0pt;margin-right:0cm;margin-bottom:
+12.0pt;margin-left:0cm'><a name="_Ref263085208">Figure </a>3. Converter UC: Convert File.</p>
+
+<b><i><span style='font-size:14.0pt;font-family:"Arial","sans-serif"'><br
+clear=all style='page-break-before:always'>
+</span></i></b>
+
+<h2><a name="_Toc276471428">3.2<span style='font:7.0pt "Times New Roman"'>
+</span>Decoder</a></h2>
+
+<p class=MsoBodyText>The decoder API allows the client to do the following:</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>1.<span
+style='font:7.0pt "Times New Roman"'> </span>Check
+the integrity of an internal Forward Lock file, i.e., detect whether it has
+been manipulated in any way; see section 3.2.1.</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>2.<span
+style='font:7.0pt "Times New Roman"'> </span>Get
+the MIME type of the embedded content (the “original” MIME type before DRM protection
+was applied); see section 3.2.2.</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>3.<span
+style='font:7.0pt "Times New Roman"'> </span>Decode
+the file by random access, i.e., read and seek through it in an arbitrary
+manner; see section 3.2.3.</p>
+
+<p class=MsoBodyText>All subsequent operations on a file first require it to be
+opened. Opening a file returns a <i>file descriptor</i>—a handle to be used in
+these subsequent operations.</p>
+
+<p class=MsoBodyText>If the filename is known, an internal Forward Lock file
+can be opened using <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_open</span>.
+If only the file descriptor of an already open file is available, a decoding
+session can instead be initialized using <span style='font-size:10.0pt;
+font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_attach</span>.</p>
+
+<p class=MsoBodyText>Internally, <span style='font-size:10.0pt;font-family:
+"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_open</span> calls <span style='font-size:10.0pt;
+font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_attach</span>. For efficiency
+reasons, <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_attach</span>
+therefore assumes that the file position is at the beginning of the file when
+the function gets called. A client who calls it directly must make sure that
+this assumption holds.</p>
+
+<p class=MsoBodyText>When a file is being attached, the session key stored in
+the file during conversion is decrypted using <span style='font-size:10.0pt;
+font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockGlue_GetEncryptedKeyLength</span> and <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockGlue_DecryptKey</span>,
+in order to set up for decoding and integrity checking.</p>
+
+<p class=MsoBodyText>For just getting the content type, however, retrieving the
+session key would strictly speaking not be necessary, so there is an
+opportunity here to optimize for that if it proves necessary later.</p>
+
+<p class=MsoBodyText>Symmetrical to <span style='font-size:10.0pt;font-family:
+"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_open</span> and <span style='font-size:10.0pt;
+font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_attach</span>, there are also functions
+for closing a file or detaching from it:</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>1.<span
+style='font:7.0pt "Times New Roman"'> </span>If
+it was opened with <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_open</span>
+it should be closed with <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_close</span>.</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>2.<span
+style='font:7.0pt "Times New Roman"'> </span>If
+it was attached with <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_attach</span>
+it should be detached with <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_detach</span>.</p>
+
+<b><span style='font-size:13.0pt;font-family:"Arial","sans-serif"'><br
+clear=all style='page-break-before:always'>
+</span></b>
+
+<h3><a name="_Ref263163099"></a><a name="_Toc276471429">3.2.1<span
+style='font:7.0pt "Times New Roman"'> </span>Check Integrity</a></h3>
+
+<p class=MsoBodyText>There are three methods for checking the integrity of an
+internal Forward Lock file, in whole or in part (see also Figure 4):</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>1.<span
+style='font:7.0pt "Times New Roman"'> </span><span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_CheckDataIntegrity</span>,
+which checks the integrity of the encrypted content data.</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>2.<span
+style='font:7.0pt "Times New Roman"'> </span><span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_CheckHeaderIntegrity</span>,
+which checks the integrity of the file header, including the content type and
+other fields not currently supported but reserved for future use.</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>3.<span
+style='font:7.0pt "Times New Roman"'> </span><span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_CheckIntegrity</span>,
+which internally calls first <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_CheckHeaderIntegrity</span>
+and then <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_CheckDataIntegrity</span>.</p>
+
+<p class=MsoBodyText style='margin-bottom:24.0pt'><span style='font-size:10.0pt;
+font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_CheckHeaderIntegrity</span> is
+generally much faster than <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_CheckDataIntegrity</span>,
+whose running time is directly proportional to the size of the file.</p>
+
+<p class=MsoBodyText style='page-break-after:avoid'><img width=543 height=575
+src="images/image004.gif"></p>
+
+<p class=MsoCaption style='margin-top:6.0pt;margin-right:0cm;margin-bottom:
+12.0pt;margin-left:0cm'><a name="_Ref263163308">Figure </a>4. Decoder UC: Check Integrity.</p>
+
+<b><span style='font-size:13.0pt;font-family:"Arial","sans-serif"'><br
+clear=all style='page-break-before:always'>
+</span></b>
+
+<h3><a name="_Toc276471430"></a><a name="_Ref263163117">3.2.2<span
+style='font:7.0pt "Times New Roman"'> </span>Get Content Type</a></h3>
+
+<p class=MsoBodyText style='margin-bottom:24.0pt'><span style='font-size:10.0pt;
+font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_GetContentType</span> returns a
+read-only reference to an ASCII string containing the MIME type of the
+embedded content. This reference is valid as long as the file is kept open.
+Clients who need access to the content type after closing the file should make
+a copy of the string. See Figure 5 below.</p>
+
+<p class=MsoBodyText style='page-break-after:avoid'><img width=543 height=488
+src="images/image005.gif"></p>
+
+<p class=MsoCaption style='margin-top:6.0pt;margin-right:0cm;margin-bottom:
+12.0pt;margin-left:0cm'><a name="_Ref263163392">Figure </a>5. Decoder UC: Get Content Type.</p>
+
+<b><span style='font-size:13.0pt;font-family:"Arial","sans-serif"'><br
+clear=all style='page-break-before:always'>
+</span></b>
+
+<h3><a name="_Toc276471431"></a><a name="_Ref263163137">3.2.3<span
+style='font:7.0pt "Times New Roman"'> </span>Decode File</a></h3>
+
+<p class=MsoBodyText>After opening an internal Forward Lock file (or attaching
+to an already open one), it can be transparently read from as if it were
+unencrypted. Any number of calls to read data from the current file position or
+set it to a new one (which is what <span style='font-size:10.0pt;font-family:
+"Lucida Console","DejaVu Sans Mono"'>lseek</span> does) can be made in any order; this is what we
+call <i>random access</i>. See Figure 6.</p>
+
+<p class=MsoBodyText>The Forward Lock Decoder versions of the <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>read</span>, <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>lseek</span>, and <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>close</span> functions
+have the exact same signatures as their POSIX counterparts. So, for example,
+the call <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_lseek(fd,
+0, SEEK_END)</span> returns the size of the embedded content data, i.e., the
+size of the original file before DRM protection.</p>
+
+<p class=MsoBodyText style='margin-bottom:24.0pt'>Moreover, <span
+style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>FwdLockFile_open</span>
+is like regular POSIX <span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>open</span>
+except it takes only the filename as a parameter—access is always read-only.</p>
+
+<p class=MsoBodyText style='page-break-after:avoid'><img width=543 height=522
+src="images/image006.gif"></p>
+
+<p class=MsoCaption style='margin-top:6.0pt;margin-right:0cm;margin-bottom:
+12.0pt;margin-left:0cm'><a name="_Ref263166303">Figure </a>6. Decoder UC: Decode File.</p>
+
+<b><span style='font-size:16.0pt;font-family:"Arial","sans-serif"'><br
+clear=all style='page-break-before:always'>
+</span></b>
+
+<h1><a name="_Toc276471432">4<span style='font:7.0pt "Times New Roman"'>
+</span>Definition of the Internal Forward Lock File Format</a></h1>
+
+<p class=MsoBodyText style='margin-bottom:12.0pt'>The inner structure of an internal
+Forward Lock file is defined in Table 1 below.</p>
+
+<table class=MsoNormalTable border=1 cellspacing=0 cellpadding=0
+ style='border-collapse:collapse;border:none'>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'><b>Offset [bytes]</b></p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border:solid windowtext 1.0pt;
+ border-left:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'><b>Size [bytes]</b></p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border:solid windowtext 1.0pt;
+ border-left:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'><b>Description</b></p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>0</p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>4</p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>The file signature (so-called
+ <i>magic number</i>): a four-character code consisting of the letters
+ F-W-L-K.</p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>4</p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>1</p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>Version number (0 for the
+ first version).</p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>5</p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>1</p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>Indicates the subformat:</p>
+ <p class=MsoNormal style='page-break-after:avoid'><i>0x00 Forward Lock</i></p>
+ <p class=MsoNormal style='page-break-after:avoid'><i>0x01 Combined Delivery</i></p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>6</p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>1</p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>Usage restriction flags (prohibitions
+ against usage as ringtone or as wallpaper and screen saver). Also indicates
+ if the file is bound to a specific SIM card.</p>
+ <p class=MsoNormal style='page-break-after:avoid'><i>0x00 No usage
+ restrictions</i></p>
+ <p class=MsoNormal style='page-break-after:avoid'><i>0x01 Ringtone usage
+ prohibited</i></p>
+ <p class=MsoNormal style='page-break-after:avoid'><i>0x02 Screen usage
+ prohibited</i></p>
+ <p class=MsoNormal style='page-break-after:avoid'><i>0x80 Bound to SIM</i></p>
+ <p class=MsoNormal style='page-break-after:avoid'>(Any number of these may be
+ OR-ed together.)</p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>7</p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>1</p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>Length of the MIME content
+ type (<i>k</i>).</p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>8</p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'><i>k</i></p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>The MIME content type
+ (ASCII-encoded without null-character termination).</p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>8+<i>k</i></p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'><i>l </i>= 0 or 16</p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>If the subformat is
+ Combined Delivery, this field contains the auto-generated content ID (16 bytes).
+ If not, this field is zero-size.</p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>8+<i>k</i>+<i>l</i></p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'><i>m </i>= 0 or 9</p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>If the file is bound to a
+ specific SIM card, this field contains the 9-byte packed IMSI number. If not,
+ this field is zero-size.</p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>8+<i>k</i>+<i>l</i>+<i>m</i></p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'><i>n</i> ≥ 16</p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>The encrypted session key, the
+ first sixteen bytes of which are also used as the CTR-mode <i>nonce</i> (similar
+ to the CBC-mode <i>initialization vector</i>).</p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>8+<i>k</i>+<i>l</i>+<i>m</i>+<i>n</i></p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>20</p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>Data signature—the SHA-1
+ HMAC of the encrypted content data.</p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>28+<i>k</i>+<i>l</i>+<i>m</i>+<i>n</i></p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>20</p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>Header signature—the SHA-1
+ HMAC of all the fields above, including the encrypted session key and data
+ signature.</p>
+ </td>
+ </tr>
+ <tr>
+ <td width=111 valign=top style='width:83.4pt;border:solid windowtext 1.0pt;
+ border-top:none;padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>48+<i>k</i>+<i>l</i>+<i>m</i>+<i>n</i></p>
+ </td>
+ <td width=96 valign=top style='width:72.0pt;border-top:none;border-left:none;
+ border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'><i><to the end of the
+ file></i></p>
+ </td>
+ <td width=361 valign=top style='width:270.85pt;border-top:none;border-left:
+ none;border-bottom:solid windowtext 1.0pt;border-right:solid windowtext 1.0pt;
+ padding:0cm 5.4pt 0cm 5.4pt'>
+ <p class=MsoNormal style='page-break-after:avoid'>The content data encrypted
+ using 128-bit AES in CTR mode.</p>
+ </td>
+ </tr>
+</table>
+
+<p class=MsoCaption style='margin-top:6.0pt;margin-right:0cm;margin-bottom:
+12.0pt;margin-left:0cm;page-break-after:avoid'><a name="_Ref151269206">Table </a>1. Definition of the fields of an internal Forward Lock file.</p>
+
+<p class=MsoBodyText>As of now, neither Combined Delivery nor usage
+restrictions (including SIM binding) are supported. These fields are reserved
+for future use.</p>
+
+<h2><a name="_Toc276471433">4.1<span style='font:7.0pt "Times New Roman"'>
+</span>Key Derivation</a></h2>
+
+<p class=MsoBodyText>The session key consists of sixteen bytes fetched from a
+cryptographically secure random number generator. From the session key, two
+separate keys are derived: one used for encryption, the other for signing.</p>
+
+<p class=MsoBodyText>The encryption key is the output from encrypting the
+16-byte all-zero input block {0, 0, Â…, 0} using 128-bit AES with the random session
+key as the key. The signing key is the output from encrypting the 16-byte input
+block {1, 0, Â…, 0} the same way. The keys so derived will be cryptographically
+independent from each other.</p>
+
+<p class=MsoBodyText>The session key is encrypted using a hardware-dependent
+key-encryption key unique to each device. The encrypted session key is stored
+inside the file, and its first sixteen bytes are also used as the <i>nonce</i>
+for the CTR-mode encryption of the content data.</p>
+
+<h2><a name="_Toc276471434">4.2<span style='font:7.0pt "Times New Roman"'>
+</span>Calculation of the Counters</a></h2>
+
+<p class=MsoBodyText>Using CTR (“counter”) mode, a block cipher such as AES can
+be turned into a stream cipher. The process of encryption and decryption is
+well defined in [1], except for the specifics of the calculation of the
+counters. For the internal Forward Lock file format, the counters are
+calculated as follows:</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>1.<span
+style='font:7.0pt "Times New Roman"'> </span>The
+nonce is interpreted as a 128-bit unsigned integer in little-endian format.</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>2.<span
+style='font:7.0pt "Times New Roman"'> </span>The
+zero-based block sequence number (also a little-endian unsigned integer) is
+added modulo 2<sup>128</sup> to the nonce to produce the counter for a given
+block.</p>
+
+<h1><a name="_Toc276471435">5<span style='font:7.0pt "Times New Roman"'>
+</span>Unit Test Cases</a></h1>
+
+<p class=MsoBodyText>Unit test cases for the converter and decoder come in two
+varieties:</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>1.<span
+style='font:7.0pt "Times New Roman"'> </span><i>Black-box</i>
+test cases aim to verify that you get sensible results from malformed or
+“tricky” input data.</p>
+
+<p class=MsoBodyText style='margin-left:36.0pt;text-indent:-18.0pt'>2.<span
+style='font:7.0pt "Times New Roman"'> </span><i>White-box</i>
+test cases aim to maximize code coverage using knowledge of code internals.</p>
+
+<p class=MsoBodyText>The black-box test cases are dependent on a specifically
+designed set of input files found in the <span style='font-size:10.0pt;
+font-family:"Lucida Console","DejaVu Sans Mono"'>forward-lock/internal-format/test/res</span>
+directory in the repository. For ‘tests’ variants of the software, these input
+files will be automatically installed in the file system image during build.</p>
+
+<p class=MsoBodyText>Run the test cases from the ADB shell command line as
+follows:</p>
+
+<p class=MsoNormal style='margin-top:0cm;margin-right:0cm;margin-bottom:6.0pt;
+margin-left:21.55pt'><span style='font-size:10.0pt;font-family:"Lucida Console","DejaVu Sans Mono"'>#
+gtest_fwdlock</span></p>
+
+<p class=MsoBodyText>If all black-box but no white-box test cases fail, the
+input files probably canÂ’t be found in the working directory.</p>
+
+<h1><a name="_Toc276471436">6<span style='font:7.0pt "Times New Roman"'>
+</span>References</a></h1>
+
+<p class=MsoBodyText style='margin-left:28.9pt;text-indent:-28.9pt'>[1]<span
+style='font:7.0pt "Times New Roman"'>
+</span><a
+href="http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf">Dworkin,
+Morris: “Recommendation for Block Cipher Modes of Operation—Methods and
+Techniques,” NIST Special Publication 800-38A, December 2001.</a><a
+name="_Ref151269073"></a></p>
+
+</div>
+
+</body>
+
+</html>
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image001.gif b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image001.gif
new file mode 100644
index 0000000..ee94513
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image001.gif
Binary files differ
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image002.gif b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image002.gif
new file mode 100644
index 0000000..8c12f46
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image002.gif
Binary files differ
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image003.gif b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image003.gif
new file mode 100644
index 0000000..9e019ca
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image003.gif
Binary files differ
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image004.gif b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image004.gif
new file mode 100644
index 0000000..cae1d01
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image004.gif
Binary files differ
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image005.gif b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image005.gif
new file mode 100644
index 0000000..0d87be9
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image005.gif
Binary files differ
diff --git a/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image006.gif b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image006.gif
new file mode 100644
index 0000000..9445b6b
--- /dev/null
+++ b/drm/libdrmframework/plugins/forward-lock/internal-format/doc/images/image006.gif
Binary files differ
diff --git a/include/drm/DrmManagerClient.h b/include/drm/DrmManagerClient.h
index e6ba3c4..085ebf1 100644
--- a/include/drm/DrmManagerClient.h
+++ b/include/drm/DrmManagerClient.h
@@ -49,6 +49,9 @@
class OnInfoListener: virtual public RefBase {
public:
+ virtual ~OnInfoListener() {}
+
+ public:
virtual void onInfo(const DrmInfoEvent& event) = 0;
};
diff --git a/include/utils/ResourceTypes.h b/include/utils/ResourceTypes.h
index ed7f53d1..6227f3e 100644
--- a/include/utils/ResourceTypes.h
+++ b/include/utils/ResourceTypes.h
@@ -1985,6 +1985,7 @@
#ifndef HAVE_ANDROID_OS
void print(bool inclValues) const;
+ static String8 normalizeForOutput(const char* input);
#endif
private:
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index 73ff230..7197ad7 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -4141,6 +4141,38 @@
}
}
+// Normalize a string for output
+String8 ResTable::normalizeForOutput( const char *input )
+{
+ String8 ret;
+ char buff[2];
+ buff[1] = '\0';
+
+ while (*input != '\0') {
+ switch (*input) {
+ // All interesting characters are in the ASCII zone, so we are making our own lives
+ // easier by scanning the string one byte at a time.
+ case '\\':
+ ret += "\\\\";
+ break;
+ case '\n':
+ ret += "\\n";
+ break;
+ case '"':
+ ret += "\\\"";
+ break;
+ default:
+ buff[0] = *input;
+ ret += buff;
+ break;
+ }
+
+ input++;
+ }
+
+ return ret;
+}
+
void ResTable::print_value(const Package* pkg, const Res_value& value) const
{
if (value.dataType == Res_value::TYPE_NULL) {
@@ -4154,13 +4186,13 @@
const char* str8 = pkg->header->values.string8At(
value.data, &len);
if (str8 != NULL) {
- printf("(string8) \"%s\"\n", str8);
+ printf("(string8) \"%s\"\n", normalizeForOutput(str8).string());
} else {
const char16_t* str16 = pkg->header->values.stringAt(
value.data, &len);
if (str16 != NULL) {
printf("(string16) \"%s\"\n",
- String8(str16, len).string());
+ normalizeForOutput(String8(str16, len).string()).string());
} else {
printf("(string) null\n");
}
diff --git a/libs/utils/Threads.cpp b/libs/utils/Threads.cpp
index ad9a94f..b1bd828 100644
--- a/libs/utils/Threads.cpp
+++ b/libs/utils/Threads.cpp
@@ -778,6 +778,7 @@
// called by a new thread using the same thread ID as this one.
self->mThread = thread_id_t(-1);
self->mThreadExitedCondition.broadcast();
+ self->mThread = thread_id_t(-1); // thread id could be reused
self->mLock.unlock();
break;
}
diff --git a/media/java/android/media/MediaRecorder.java b/media/java/android/media/MediaRecorder.java
index 11900d4..edefb22 100644
--- a/media/java/android/media/MediaRecorder.java
+++ b/media/java/android/media/MediaRecorder.java
@@ -343,7 +343,7 @@
degrees != 270) {
throw new IllegalArgumentException("Unsupported angle: " + degrees);
}
- setParameter(String.format("video-param-rotation-angle-degrees=%d", degrees));
+ setParameter("video-param-rotation-angle-degrees=" + degrees);
}
/**
@@ -463,7 +463,7 @@
if (samplingRate <= 0) {
throw new IllegalArgumentException("Audio sampling rate is not positive");
}
- setParameter(String.format("audio-param-sampling-rate=%d", samplingRate));
+ setParameter("audio-param-sampling-rate=" + samplingRate);
}
/**
@@ -478,7 +478,7 @@
if (numChannels <= 0) {
throw new IllegalArgumentException("Number of channels is not positive");
}
- setParameter(String.format("audio-param-number-of-channels=%d", numChannels));
+ setParameter("audio-param-number-of-channels=" + numChannels);
}
/**
@@ -494,7 +494,7 @@
if (bitRate <= 0) {
throw new IllegalArgumentException("Audio encoding bit rate is not positive");
}
- setParameter(String.format("audio-param-encoding-bitrate=%d", bitRate));
+ setParameter("audio-param-encoding-bitrate=" + bitRate);
}
/**
@@ -510,7 +510,7 @@
if (bitRate <= 0) {
throw new IllegalArgumentException("Video encoding bit rate is not positive");
}
- setParameter(String.format("video-param-encoding-bitrate=%d", bitRate));
+ setParameter("video-param-encoding-bitrate=" + bitRate);
}
/**
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png
new file mode 100644
index 0000000..1aea612
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png
new file mode 100644
index 0000000..425535e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png
new file mode 100644
index 0000000..fcad363
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png
new file mode 100644
index 0000000..4ff7db3
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png
new file mode 100644
index 0000000..2c4a07f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_fully_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png
new file mode 100644
index 0000000..879c703
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.png
new file mode 100644
index 0000000..61a7503
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inadnout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png
new file mode 100644
index 0000000..c5edf2c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png
new file mode 100644
index 0000000..ddf88be
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/stat_sys_data_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
index 78ece9e..c77e61e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
index 31fc1b0..b9f721a 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png
new file mode 100644
index 0000000..cff969e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
index 19adb4b..d2d7ab3 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
index fd419ea..83ce6d0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
index 94e77ae..abe511f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
index 91328c0..d685af8 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
index 2fee6924..8c697a1 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png
new file mode 100644
index 0000000..9a4b807
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
index d0968aa..eb11d04 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
index 991228b..6e54de0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
index ae03e38..5bfb33b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_connected_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png
index 97b011e..119067b 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png
index a826866..a70cc2e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png
new file mode 100644
index 0000000..ea3dba7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png
index f6a6891..53221b9 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png
index 19b9816..11d44d0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png
index f8c0961..9defd79 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png
index 22deb70..136576d 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png
index c7c1b49..26ca31f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png
new file mode 100644
index 0000000..de8c5ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png
index d9a0702..64dbf3c 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png
index 6beed8a..34923fb 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png
index e4179c1..506b5c6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png
index 4b2f86d..163976f 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png
index 6779604..a6af649 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png
new file mode 100644
index 0000000..0c08e52
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png
index 1309a97..1d02edb 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png
index 2fc1e8e..edc9536 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png
index 0eef2c1..8376817 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_fully_out_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
index f8904e2..ecef547 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
index 3ef306e..a7c48b6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png
new file mode 100644
index 0000000..f4bcd9a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
index 2ff6d90..b46bb3a 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
index 8ff49b0..e8b70f2 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
index f416203..4e23c4e 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_in_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png
new file mode 100644
index 0000000..ced9175
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inadnout_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
index 24b7daa..92d4a19 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
index 5ea9142..a208736 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png
new file mode 100644
index 0000000..f407bc9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
index 002bf46..b8a65c2 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
index 924b84f..a978b68 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_inandout_h.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
index bd0d1ca..710dd52 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_1x.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
index f583eec..a7b35e4 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_3g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png
new file mode 100644
index 0000000..bb05449
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_4g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
index 66940eaf..a144222 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_e.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
index 0381f52..b0eafb6 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_g.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
index 0b84fe8..f6b83d0 100644
--- a/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
+++ b/packages/SystemUI/res/drawable-mdpi/stat_sys_data_out_h.png
Binary files differ
diff --git a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
index a834266..1368baa 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/UsbStorageActivity.java
@@ -71,6 +71,7 @@
private static final int DLG_CONFIRM_KILL_STORAGE_USERS = 1;
private static final int DLG_ERROR_SHARING = 2;
static final boolean localLOGV = false;
+ private boolean mDestroyed;
// UI thread
private Handler mUIHandler;
@@ -136,6 +137,12 @@
mProgressBar = (ProgressBar) findViewById(com.android.internal.R.id.progress);
}
+ @Override
+ protected void onDestroy() {
+ super.onDestroy();
+ mDestroyed = true;
+ }
+
private void switchDisplay(final boolean usbStorageInUse) {
mUIHandler.post(new Runnable() {
@Override
@@ -232,9 +239,16 @@
return null;
}
- private void showDialogInner(int id) {
- removeDialog(id);
- showDialog(id);
+ private void scheduleShowDialog(final int id) {
+ mUIHandler.post(new Runnable() {
+ @Override
+ public void run() {
+ if (!mDestroyed) {
+ removeDialog(id);
+ showDialog(id);
+ }
+ }
+ });
}
private void switchUsbMassStorage(final boolean on) {
@@ -276,7 +290,7 @@
IMountService ims = getMountService();
if (ims == null) {
// Display error dialog
- showDialogInner(DLG_ERROR_SHARING);
+ scheduleShowDialog(DLG_ERROR_SHARING);
}
String extStoragePath = Environment.getExternalStorageDirectory().toString();
boolean showDialog = false;
@@ -294,11 +308,11 @@
}
} catch (RemoteException e) {
// Display error dialog
- showDialogInner(DLG_ERROR_SHARING);
+ scheduleShowDialog(DLG_ERROR_SHARING);
}
if (showDialog) {
// Display dialog to user
- showDialogInner(DLG_CONFIRM_KILL_STORAGE_USERS);
+ scheduleShowDialog(DLG_CONFIRM_KILL_STORAGE_USERS);
} else {
if (localLOGV) Log.i(TAG, "Enabling UMS");
switchUsbMassStorage(true);
diff --git a/services/audioflinger/AudioMixer.cpp b/services/audioflinger/AudioMixer.cpp
index 8aaa325..433f1f7 100644
--- a/services/audioflinger/AudioMixer.cpp
+++ b/services/audioflinger/AudioMixer.cpp
@@ -975,7 +975,6 @@
{
int32_t* const outTemp = state->outputTemp;
const size_t size = sizeof(int32_t) * MAX_NUM_CHANNELS * state->frameCount;
- memset(outTemp, 0, size);
size_t numFrames = state->frameCount;
@@ -997,6 +996,7 @@
}
e0 &= ~(e1);
int32_t *out = t1.mainBuffer;
+ memset(outTemp, 0, size);
while (e1) {
const int i = 31 - __builtin_clz(e1);
e1 &= ~(1<<i);
diff --git a/services/java/com/android/server/NativeDaemonConnector.java b/services/java/com/android/server/NativeDaemonConnector.java
index cf87a9d..88d94c2 100644
--- a/services/java/com/android/server/NativeDaemonConnector.java
+++ b/services/java/com/android/server/NativeDaemonConnector.java
@@ -97,11 +97,12 @@
LocalSocketAddress.Namespace.RESERVED);
socket.connect(address);
- mCallbacks.onDaemonConnected();
InputStream inputStream = socket.getInputStream();
mOutputStream = socket.getOutputStream();
+ mCallbacks.onDaemonConnected();
+
byte[] buffer = new byte[BUFFER_SIZE];
int start = 0;
diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java
index f3b5f4b..9ee71e8 100644
--- a/services/java/com/android/server/PackageManagerService.java
+++ b/services/java/com/android/server/PackageManagerService.java
@@ -8023,14 +8023,6 @@
sharedUser = orig.sharedUser;
}
- public void copyFrom(PackageSetting base) {
- super.copyFrom((PackageSettingBase) base);
-
- userId = base.userId;
- sharedUser = base.sharedUser;
- pkg = base.pkg;
- }
-
@Override
public String toString() {
return "PackageSetting{"
diff --git a/services/java/com/android/server/WindowManagerService.java b/services/java/com/android/server/WindowManagerService.java
index 2efb444..3978b99 100644
--- a/services/java/com/android/server/WindowManagerService.java
+++ b/services/java/com/android/server/WindowManagerService.java
@@ -928,9 +928,8 @@
} catch (InterruptedException e) {
}
}
+ return thr.mService;
}
-
- return thr.mService;
}
static class WMThread extends Thread {
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 254a19b..c24fe8e 100755
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -4504,12 +4504,15 @@
perm.modeFlags |= modeFlags;
if (owner == null) {
perm.globalModeFlags |= modeFlags;
- } else if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
- perm.readOwners.add(owner);
- owner.addReadPermission(perm);
- } else if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
- perm.writeOwners.add(owner);
- owner.addWritePermission(perm);
+ } else {
+ if ((modeFlags&Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
+ perm.readOwners.add(owner);
+ owner.addReadPermission(perm);
+ }
+ if ((modeFlags&Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
+ perm.writeOwners.add(owner);
+ owner.addWritePermission(perm);
+ }
}
}
diff --git a/telephony/java/com/android/internal/telephony/CommandsInterface.java b/telephony/java/com/android/internal/telephony/CommandsInterface.java
index 5e4c136..259acdb 100644
--- a/telephony/java/com/android/internal/telephony/CommandsInterface.java
+++ b/telephony/java/com/android/internal/telephony/CommandsInterface.java
@@ -1289,18 +1289,25 @@
void setCdmaSubscription(int cdmaSubscriptionType, Message response);
/**
- * Set the TTY mode for the CDMA phone
+ * Set the TTY mode
*
- * @param enable is true to enable, false to disable
+ * @param ttyMode one of the following:
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
* @param response is callback message
*/
void setTTYMode(int ttyMode, Message response);
/**
- * Query the TTY mode for the CDMA phone
+ * Query the TTY mode
* (AsyncResult)response.obj).result is an int[] with element [0] set to
- * 0 for disabled, 1 for enabled.
- *
+ * tty mode:
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
* @param response is callback message
*/
void queryTTYMode(Message response);
diff --git a/telephony/java/com/android/internal/telephony/Phone.java b/telephony/java/com/android/internal/telephony/Phone.java
index d0b5540..ef9e783 100644
--- a/telephony/java/com/android/internal/telephony/Phone.java
+++ b/telephony/java/com/android/internal/telephony/Phone.java
@@ -1430,9 +1430,11 @@
/**
* setTTYMode
* sets a TTY mode option.
- *
- * @param ttyMode is a boolean representing the state that you are
- * requesting, true for enabled, false for disabled.
+ * @param ttyMode is a one of the following:
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
* @param onComplete a callback message when the action is completed
*/
void setTTYMode(int ttyMode, Message onComplete);
diff --git a/telephony/java/com/android/internal/telephony/PhoneBase.java b/telephony/java/com/android/internal/telephony/PhoneBase.java
index 5887130..cbff130 100644
--- a/telephony/java/com/android/internal/telephony/PhoneBase.java
+++ b/telephony/java/com/android/internal/telephony/PhoneBase.java
@@ -702,13 +702,11 @@
}
public void setTTYMode(int ttyMode, Message onComplete) {
- // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
- logUnexpectedCdmaMethodCall("setTTYMode");
+ mCM.setTTYMode(ttyMode, onComplete);
}
public void queryTTYMode(Message onComplete) {
- // This function should be overridden by the class CDMAPhone. Not implemented in GSMPhone.
- logUnexpectedCdmaMethodCall("queryTTYMode");
+ mCM.queryTTYMode(onComplete);
}
public void enableEnhancedVoicePrivacy(boolean enable, Message onComplete) {
diff --git a/telephony/java/com/android/internal/telephony/SMSDispatcher.java b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
old mode 100644
new mode 100755
index 99123af..befee8c
--- a/telephony/java/com/android/internal/telephony/SMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/SMSDispatcher.java
@@ -66,6 +66,7 @@
public abstract class SMSDispatcher extends Handler {
private static final String TAG = "SMS";
+ private static final String SEND_NEXT_MSG_EXTRA = "SendNextMsg";
/** Default checking period for SMS sent without user permit */
private static final int DEFAULT_SMS_CHECK_PERIOD = 3600000;
@@ -162,6 +163,8 @@
protected boolean mSmsReceiveDisabled;
protected boolean mSmsSendDisabled;
+ protected static int mRemainingMessages = -1;
+
protected static int getNextConcatenatedRef() {
sConcatenatedRef += 1;
return sConcatenatedRef;
@@ -409,6 +412,7 @@
mCm.reportSmsMemoryStatus(mStorageAvailable,
obtainMessage(EVENT_REPORT_MEMORY_STATUS_DONE));
}
+ break;
case EVENT_NEW_BROADCAST_SMS:
handleBroadcastSms((AsyncResult)msg.obj);
@@ -486,7 +490,17 @@
if (sentIntent != null) {
try {
- sentIntent.send(Activity.RESULT_OK);
+ if (mRemainingMessages > -1) {
+ mRemainingMessages--;
+ }
+
+ if (mRemainingMessages == 0) {
+ Intent sendNext = new Intent();
+ sendNext.putExtra(SEND_NEXT_MSG_EXTRA, true);
+ sentIntent.send(mContext, Activity.RESULT_OK, sendNext);
+ } else {
+ sentIntent.send(Activity.RESULT_OK);
+ }
} catch (CanceledException ex) {}
}
} else {
@@ -525,8 +539,15 @@
if (ar.result != null) {
fillIn.putExtra("errorCode", ((SmsResponse)ar.result).errorCode);
}
- tracker.mSentIntent.send(mContext, error, fillIn);
+ if (mRemainingMessages > -1) {
+ mRemainingMessages--;
+ }
+ if (mRemainingMessages == 0) {
+ fillIn.putExtra(SEND_NEXT_MSG_EXTRA, true);
+ }
+
+ tracker.mSentIntent.send(mContext, error, fillIn);
} catch (CanceledException ex) {}
}
}
diff --git a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
index a1d5121..bd00a0b 100755
--- a/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
+++ b/telephony/java/com/android/internal/telephony/cdma/CDMAPhone.java
@@ -1103,20 +1103,6 @@
}
/**
- * Set the TTY mode of the CDMAPhone
- */
- public void setTTYMode(int ttyMode, Message onComplete) {
- this.mCM.setTTYMode(ttyMode, onComplete);
- }
-
- /**
- * Queries the TTY mode of the CDMAPhone
- */
- public void queryTTYMode(Message onComplete) {
- this.mCM.queryTTYMode(onComplete);
- }
-
- /**
* Activate or deactivate cell broadcast SMS.
*
* @param activate 0 = activate, 1 = deactivate
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
index fe7a5cb..2962e0f 100644
--- a/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmMmiCode.java
@@ -155,7 +155,7 @@
static final int MATCH_GROUP_SIC = 9;
static final int MATCH_GROUP_PWD_CONFIRM = 11;
static final int MATCH_GROUP_DIALING_NUMBER = 12;
-
+ static private String[] sTwoDigitNumberPattern;
//***** Public Class methods
@@ -198,6 +198,9 @@
ret = new GsmMmiCode(phone);
ret.poundString = dialString;
+ } else if (isTwoDigitShortCode(phone.getContext(), dialString)) {
+ //Is a country-specific exception to short codes as defined in TS 22.030, 6.5.3.2
+ ret = null;
} else if (isShortCode(dialString, phone)) {
// this may be a short code, as defined in TS 22.030, 6.5.3.2
ret = new GsmMmiCode(phone);
@@ -452,6 +455,28 @@
}
+ static private boolean
+ isTwoDigitShortCode(Context context, String dialString) {
+ Log.d(LOG_TAG, "isTwoDigitShortCode");
+
+ if (dialString == null || dialString.length() != 2) return false;
+
+ if (sTwoDigitNumberPattern == null) {
+ sTwoDigitNumberPattern = context.getResources().getStringArray(
+ com.android.internal.R.array.config_twoDigitNumberPattern);
+ }
+
+ for (String dialnumber : sTwoDigitNumberPattern) {
+ Log.d(LOG_TAG, "Two Digit Number Pattern " + dialnumber);
+ if (dialString.equals(dialnumber)) {
+ Log.d(LOG_TAG, "Two Digit Number Pattern -true");
+ return true;
+ }
+ }
+ Log.d(LOG_TAG, "Two Digit Number Pattern -false");
+ return false;
+ }
+
/**
* Helper function for newFromDialString. Returns true if dialString appears
* to be a short code AND conditions are correct for it to be treated as
diff --git a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
old mode 100644
new mode 100755
index bbe579d..f576b4e
--- a/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
+++ b/telephony/java/com/android/internal/telephony/gsm/GsmSMSDispatcher.java
@@ -23,6 +23,7 @@
import android.os.AsyncResult;
import android.os.Message;
import android.os.SystemProperties;
+import android.provider.Telephony.Sms;
import android.provider.Telephony.Sms.Intents;
import android.telephony.ServiceState;
import android.telephony.SmsCbMessage;
@@ -69,13 +70,17 @@
String pduString = (String) ar.result;
SmsMessage sms = SmsMessage.newFromCDS(pduString);
+ int tpStatus = sms.getStatus();
+
if (sms != null) {
int messageRef = sms.messageRef;
for (int i = 0, count = deliveryPendingList.size(); i < count; i++) {
SmsTracker tracker = deliveryPendingList.get(i);
if (tracker.mMessageRef == messageRef) {
// Found it. Remove from list and broadcast.
- deliveryPendingList.remove(i);
+ if(tpStatus >= Sms.STATUS_FAILED || tpStatus < Sms.STATUS_PENDING ) {
+ deliveryPendingList.remove(i);
+ }
PendingIntent intent = tracker.mDeliveryIntent;
Intent fillIn = new Intent();
fillIn.putExtra("pdu", IccUtils.hexStringToBytes(pduString));
@@ -195,6 +200,8 @@
int msgCount = parts.size();
int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
+ mRemainingMessages = msgCount;
+
for (int i = 0; i < msgCount; i++) {
TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
if (encoding != details.codeUnitSize
@@ -284,6 +291,8 @@
int msgCount = parts.size();
int encoding = android.telephony.SmsMessage.ENCODING_UNKNOWN;
+ mRemainingMessages = msgCount;
+
for (int i = 0; i < msgCount; i++) {
TextEncodingDetails details = SmsMessage.calculateLength(parts.get(i), false);
if (encoding != details.codeUnitSize
diff --git a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
old mode 100644
new mode 100755
index 438996f..3b133da
--- a/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
+++ b/telephony/java/com/android/internal/telephony/gsm/SIMRecords.java
@@ -144,6 +144,25 @@
private static final int EVENT_GET_CFIS_DONE = 32;
private static final int EVENT_GET_CSP_CPHS_DONE = 33;
+ // Lookup table for carriers known to produce SIMs which incorrectly indicate MNC length.
+
+ private static final String[] MCCMNC_CODES_HAVING_3DIGITS_MNC = {
+ "405025", "405026", "405027", "405028", "405029", "405030", "405031", "405032",
+ "405033", "405034", "405035", "405036", "405037", "405038", "405039", "405040",
+ "405041", "405042", "405043", "405044", "405045", "405046", "405047", "405750",
+ "405751", "405752", "405753", "405754", "405755", "405756", "405799", "405800",
+ "405801", "405802", "405803", "405804", "405805", "405806", "405807", "405808",
+ "405809", "405810", "405811", "405812", "405813", "405814", "405815", "405816",
+ "405817", "405818", "405819", "405820", "405821", "405822", "405823", "405824",
+ "405825", "405826", "405827", "405828", "405829", "405830", "405831", "405832",
+ "405833", "405834", "405835", "405836", "405837", "405838", "405839", "405840",
+ "405841", "405842", "405843", "405844", "405845", "405846", "405847", "405848",
+ "405849", "405850", "405851", "405852", "405853", "405875", "405876", "405877",
+ "405878", "405879", "405880", "405881", "405882", "405883", "405884", "405885",
+ "405886", "405908", "405909", "405910", "405911", "405925", "405926", "405927",
+ "405928", "405929", "405932"
+ };
+
// ***** Constructor
SIMRecords(GSMPhone p) {
@@ -501,6 +520,17 @@
Log.d(LOG_TAG, "IMSI: " + imsi.substring(0, 6) + "xxxxxxx");
+ if (((mncLength == UNKNOWN) || (mncLength == 2)) &&
+ ((imsi != null) && (imsi.length() >= 6))) {
+ String mccmncCode = imsi.substring(0, 6);
+ for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
+ if (mccmnc.equals(mccmncCode)) {
+ mncLength = 3;
+ break;
+ }
+ }
+ }
+
if (mncLength == UNKNOWN) {
// the SIM has told us all it knows, but it didn't know the mnc length.
// guess using the mcc
@@ -752,6 +782,17 @@
mncLength = UNKNOWN;
}
} finally {
+ if (((mncLength == UNINITIALIZED) || (mncLength == UNKNOWN) ||
+ (mncLength == 2)) && ((imsi != null) && (imsi.length() >= 6))) {
+ String mccmncCode = imsi.substring(0, 6);
+ for (String mccmnc : MCCMNC_CODES_HAVING_3DIGITS_MNC) {
+ if (mccmnc.equals(mccmncCode)) {
+ mncLength = 3;
+ break;
+ }
+ }
+ }
+
if (mncLength == UNKNOWN || mncLength == UNINITIALIZED) {
if (imsi != null) {
try {
diff --git a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
index 41f3b23..a9efc98 100755
--- a/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
+++ b/telephony/java/com/android/internal/telephony/gsm/UsimPhoneBookManager.java
@@ -305,8 +305,15 @@
fileIds = mPbrFile.mFileIds.get(recNum);
if (fileIds == null || fileIds.isEmpty()) return;
+
+ int extEf = 0;
+ // Only call fileIds.get while EFEXT1_TAG is available
+ if (fileIds.containsKey(USIM_EFEXT1_TAG)) {
+ extEf = fileIds.get(USIM_EFEXT1_TAG);
+ }
+
mAdnCache.requestLoadAllAdnLike(fileIds.get(USIM_EFADN_TAG),
- fileIds.get(USIM_EFEXT1_TAG), obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
+ extEf, obtainMessage(EVENT_USIM_ADN_LOAD_DONE));
try {
mLock.wait();
} catch (InterruptedException e) {
diff --git a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
index 37867b2..8b3a3ad 100644
--- a/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
+++ b/telephony/java/com/android/internal/telephony/test/SimulatedCommands.java
@@ -1392,23 +1392,28 @@
}
/**
- * Set the TTY mode for the CDMA phone
+ * Set the TTY mode
*
- * @param enable is true to enable, false to disable
- * @param serviceClass is a sum of SERVICE_CLASS_*
+ * @param ttyMode is one of the following:
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
* @param response is callback message
*/
public void setTTYMode(int ttyMode, Message response) {
- Log.w(LOG_TAG, "CDMA not implemented in SimulatedCommands");
+ Log.w(LOG_TAG, "Not implemented in SimulatedCommands");
unimplemented(response);
}
/**
- * Query the TTY mode for the CDMA phone
+ * Query the TTY mode
* (AsyncResult)response.obj).result is an int[] with element [0] set to
- * 0 for disabled, 1 for enabled.
- *
- * @param serviceClass is a sum of SERVICE_CLASS_*
+ * tty mode:
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_OFF}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_FULL}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_HCO}
+ * - {@link com.android.internal.telephony.Phone#TTY_MODE_VCO}
* @param response is callback message
*/
public void queryTTYMode(Message response) {
diff --git a/tools/aapt/AaptAssets.cpp b/tools/aapt/AaptAssets.cpp
index e4f447e..2b2ec7b 100644
--- a/tools/aapt/AaptAssets.cpp
+++ b/tools/aapt/AaptAssets.cpp
@@ -685,13 +685,11 @@
if (*c != 0) return false;
if (c-val == 0 || c-val > 3) return false;
- int d = atoi(val);
- if (d != 0) {
- if (out) out->mnc = d;
- return true;
+ if (out) {
+ out->mnc = atoi(val);
}
- return false;
+ return true;
}
/*
diff --git a/tools/aapt/XMLNode.cpp b/tools/aapt/XMLNode.cpp
index 8551b0f..c0d7427 100644
--- a/tools/aapt/XMLNode.cpp
+++ b/tools/aapt/XMLNode.cpp
@@ -451,13 +451,15 @@
printf("=?0x%x", (int)value.data);
} else if (value.dataType == Res_value::TYPE_STRING) {
printf("=\"%s\"",
- String8(block->getAttributeStringValue(i, &len)).string());
+ ResTable::normalizeForOutput(String8(block->getAttributeStringValue(i,
+ &len)).string()).string());
} else {
printf("=(type 0x%x)0x%x", (int)value.dataType, (int)value.data);
}
const char16_t* val = block->getAttributeStringValue(i, &len);
if (val != NULL) {
- printf(" (Raw: \"%s\")", String8(val).string());
+ printf(" (Raw: \"%s\")", ResTable::normalizeForOutput(String8(val).string()).
+ string());
}
printf("\n");
}
diff --git a/tools/layoutlib/bridge/.classpath b/tools/layoutlib/bridge/.classpath
index 2eaf8e3..5cfda29 100644
--- a/tools/layoutlib/bridge/.classpath
+++ b/tools/layoutlib/bridge/.classpath
@@ -8,6 +8,6 @@
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/kxml2/kxml2-2.3.0.jar" sourcepath="/ANDROID_PLAT_SRC/dalvik/libcore/xml/src/main/java"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/out/host/common/obj/JAVA_LIBRARIES/temp_layoutlib_intermediates/javalib.jar" sourcepath="/ANDROID_PLAT_SRC/frameworks/base"/>
<classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/ninepatch/ninepatch-prebuilt.jar"/>
- <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/common/common-prebuilt.jar"/>
+ <classpathentry kind="var" path="ANDROID_PLAT_SRC/prebuilt/common/tools-common/tools-common-prebuilt.jar"/>
<classpathentry kind="output" path="bin"/>
</classpath>
diff --git a/tools/layoutlib/bridge/Android.mk b/tools/layoutlib/bridge/Android.mk
index ca7db8c..7e70f33 100644
--- a/tools/layoutlib/bridge/Android.mk
+++ b/tools/layoutlib/bridge/Android.mk
@@ -23,7 +23,7 @@
LOCAL_JAVA_LIBRARIES := \
kxml2-2.3.0 \
layoutlib_api-prebuilt \
- common-prebuilt
+ tools-common-prebuilt
LOCAL_STATIC_JAVA_LIBRARIES := \
temp_layoutlib \
diff --git a/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml b/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
index 5211b0a..d3c492e 100644
--- a/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
+++ b/tools/layoutlib/bridge/resources/bars/phone_system_bar.xml
@@ -9,5 +9,7 @@
android:layout_width="wrap_content"/>
<ImageView
android:layout_height="wrap_content"
- android:layout_width="wrap_content"/>
+ android:layout_width="wrap_content"
+ android:layout_marginLeft="3dip"
+ android:layout_marginRight="5dip"/>
</merge>
diff --git a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
index 7d41d1c..7b444aa 100644
--- a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
@@ -17,6 +17,7 @@
package android.animation;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.animation.PropertyValuesHolder
@@ -34,20 +35,24 @@
*/
/*package*/ class PropertyValuesHolder_Delegate {
+ @LayoutlibDelegate
/*package*/ static int nGetIntMethod(Class<?> targetClass, String methodName) {
// return 0 to force PropertyValuesHolder to use Java reflection.
return 0;
}
+ @LayoutlibDelegate
/*package*/ static int nGetFloatMethod(Class<?> targetClass, String methodName) {
// return 0 to force PropertyValuesHolder to use Java reflection.
return 0;
}
+ @LayoutlibDelegate
/*package*/ static void nCallIntMethod(Object target, int methodID, int arg) {
// do nothing
}
+ @LayoutlibDelegate
/*package*/ static void nCallFloatMethod(Object target, int methodID, float arg) {
// do nothing
}
diff --git a/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java b/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java
index 60ad645..aabd3f1 100644
--- a/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java
@@ -17,6 +17,7 @@
package android.app;
import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.content.Context;
import android.os.Bundle;
@@ -48,6 +49,7 @@
* Like {@link #instantiate(Context, String, Bundle)} but with a null
* argument Bundle.
*/
+ @LayoutlibDelegate
/*package*/ static Fragment instantiate(Context context, String fname) {
return instantiate(context, fname, null);
}
@@ -66,6 +68,7 @@
* the given fragment class. This is a runtime exception; it is not
* normally expected to happen.
*/
+ @LayoutlibDelegate
/*package*/ static Fragment instantiate(Context context, String fname, Bundle args) {
try {
if (sProjectCallback != null) {
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
index 03f3980..413894b 100644
--- a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
@@ -17,6 +17,7 @@
package android.content.res;
import com.android.layoutlib.bridge.impl.RenderSessionImpl;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.content.res.Resources.NotFoundException;
import android.content.res.Resources.Theme;
@@ -32,12 +33,14 @@
*/
public class Resources_Theme_Delegate {
+ @LayoutlibDelegate
/*package*/ static TypedArray obtainStyledAttributes(
Resources thisResources, Theme thisTheme,
int[] attrs) {
return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
}
+ @LayoutlibDelegate
/*package*/ static TypedArray obtainStyledAttributes(
Resources thisResources, Theme thisTheme,
int resid, int[] attrs)
@@ -45,6 +48,7 @@
return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid, attrs);
}
+ @LayoutlibDelegate
/*package*/ static TypedArray obtainStyledAttributes(
Resources thisResources, Theme thisTheme,
AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
@@ -52,6 +56,7 @@
set, attrs, defStyleAttr, defStyleRes);
}
+ @LayoutlibDelegate
/*package*/ static boolean resolveAttribute(
Resources thisResources, Theme thisTheme,
int resid, TypedValue outValue,
diff --git a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
index 190eb37..a50a2bd 100644
--- a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Composite;
@@ -59,9 +60,10 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate(int opColor, int tolerance, int nativeMode) {
AvoidXfermode_Delegate newDelegate = new AvoidXfermode_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
index c4fffc86..080b85f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -21,6 +21,7 @@
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.ninepatch.NinePatchChunk;
import com.android.resources.Density;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.BitmapFactory.Options;
@@ -42,6 +43,7 @@
// ------ Java delegates ------
+ @LayoutlibDelegate
/*package*/ static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
if (bm == null || opts == null) {
return bm;
@@ -82,10 +84,12 @@
// ------ Native Delegates ------
+ @LayoutlibDelegate
/*package*/ static void nativeSetDefaultConfig(int nativeConfig) {
// pass
}
+ @LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage,
Rect padding, Options opts) {
Bitmap bm = null;
@@ -129,29 +133,34 @@
return bm;
}
+ @LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
Rect padding, Options opts) {
opts.inBitmap = null;
return null;
}
+ @LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts) {
opts.inBitmap = null;
return null;
}
+ @LayoutlibDelegate
/*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset,
int length, Options opts) {
opts.inBitmap = null;
return null;
}
+ @LayoutlibDelegate
/*package*/ static byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad) {
// don't scale for now. This should not be called anyway since we re-implement
// BitmapFactory.finishDecode();
return chunk;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeIsSeekable(FileDescriptor fd) {
return true;
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
index 73c5a1a..9a8cf04 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -19,6 +19,7 @@
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Shader.TileMode;
@@ -63,6 +64,7 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate(int native_bitmap, int shaderTileModeX,
int shaderTileModeY) {
Bitmap_Delegate bitmap = Bitmap_Delegate.getDelegate(native_bitmap);
@@ -74,9 +76,10 @@
bitmap.getImage(),
Shader_Delegate.getTileMode(shaderTileModeX),
Shader_Delegate.getTileMode(shaderTileModeY));
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int nativePostCreate(int native_shader, int native_bitmap,
int shaderTileModeX, int shaderTileModeY) {
// pass, not needed.
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
index 3e80614..66e59d8 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -20,6 +20,7 @@
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.resources.Density;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
@@ -53,7 +54,7 @@
// ---- delegate manager ----
private static final DelegateManager<Bitmap_Delegate> sManager =
- new DelegateManager<Bitmap_Delegate>();
+ new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class);
// ---- delegate helper data ----
@@ -196,6 +197,7 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
int height, int nativeConfig, boolean mutable) {
int imageType = getBufferedImageType(nativeConfig);
@@ -213,6 +215,7 @@
return createBitmap(delegate, mutable, Bitmap.getDefaultDensity());
}
+ @LayoutlibDelegate
/*package*/ static Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable) {
Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(srcBitmap);
if (srcBmpDelegate == null) {
@@ -240,14 +243,17 @@
return createBitmap(delegate, isMutable, Bitmap.getDefaultDensity());
}
+ @LayoutlibDelegate
/*package*/ static void nativeDestructor(int nativeBitmap) {
- sManager.removeDelegate(nativeBitmap);
+ sManager.removeJavaReferenceFor(nativeBitmap);
}
+ @LayoutlibDelegate
/*package*/ static void nativeRecycle(int nativeBitmap) {
- sManager.removeDelegate(nativeBitmap);
+ sManager.removeJavaReferenceFor(nativeBitmap);
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeCompress(int nativeBitmap, int format, int quality,
OutputStream stream, byte[] tempStorage) {
Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
@@ -255,6 +261,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static void nativeErase(int nativeBitmap, int color) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -274,6 +281,7 @@
}
}
+ @LayoutlibDelegate
/*package*/ static int nativeWidth(int nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -284,6 +292,7 @@
return delegate.mImage.getWidth();
}
+ @LayoutlibDelegate
/*package*/ static int nativeHeight(int nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -294,6 +303,7 @@
return delegate.mImage.getHeight();
}
+ @LayoutlibDelegate
/*package*/ static int nativeRowBytes(int nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -304,6 +314,7 @@
return delegate.mImage.getWidth();
}
+ @LayoutlibDelegate
/*package*/ static int nativeConfig(int nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -314,6 +325,7 @@
return delegate.mConfig.nativeInt;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeHasAlpha(int nativeBitmap) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -324,6 +336,7 @@
return delegate.mHasAlpha;
}
+ @LayoutlibDelegate
/*package*/ static int nativeGetPixel(int nativeBitmap, int x, int y) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -334,6 +347,7 @@
return delegate.mImage.getRGB(x, y);
}
+ @LayoutlibDelegate
/*package*/ static void nativeGetPixels(int nativeBitmap, int[] pixels, int offset,
int stride, int x, int y, int width, int height) {
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -345,6 +359,7 @@
}
+ @LayoutlibDelegate
/*package*/ static void nativeSetPixel(int nativeBitmap, int x, int y, int color) {
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
@@ -354,6 +369,7 @@
delegate.getImage().setRGB(x, y, color);
}
+ @LayoutlibDelegate
/*package*/ static void nativeSetPixels(int nativeBitmap, int[] colors, int offset,
int stride, int x, int y, int width, int height) {
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -364,16 +380,21 @@
delegate.getImage().setRGB(x, y, width, height, colors, offset, stride);
}
+ @LayoutlibDelegate
/*package*/ static void nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst) {
// FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeCopyPixelsToBuffer");
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Bitmap.copyPixelsToBuffer is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void nativeCopyPixelsFromBuffer(int nb, Buffer src) {
// FIXME implement native delegate
- throw new UnsupportedOperationException("Native delegate needed for Bitmap.nativeCopyPixelsFromBuffer");
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Bitmap.copyPixelsFromBuffer is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static int nativeGenerationId(int nativeBitmap) {
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
if (delegate == null) {
@@ -383,6 +404,7 @@
return delegate.mGenerationId;
}
+ @LayoutlibDelegate
/*package*/ static Bitmap nativeCreateFromParcel(Parcel p) {
// This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only
// used during aidl call so really this should not be called.
@@ -392,6 +414,7 @@
return null;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeWriteToParcel(int nativeBitmap, boolean isMutable,
int density, Parcel p) {
// This is only called when sending a bitmap through aidl, so really this should not
@@ -402,6 +425,7 @@
return false;
}
+ @LayoutlibDelegate
/*package*/ static Bitmap nativeExtractAlpha(int nativeBitmap, int nativePaint,
int[] offsetXY) {
Bitmap_Delegate bitmap = sManager.getDelegate(nativeBitmap);
@@ -429,10 +453,12 @@
Density.DEFAULT_DENSITY /*density*/);
}
+ @LayoutlibDelegate
/*package*/ static void nativePrepareToDraw(int nativeBitmap) {
// nothing to be done here.
}
+ @LayoutlibDelegate
/*package*/ static void nativeSetHasAlpha(int nativeBitmap, boolean hasAlpha) {
// get the delegate from the native int.
Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
@@ -443,6 +469,7 @@
delegate.mHasAlpha = hasAlpha;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeSameAs(int nb0, int nb1) {
Bitmap_Delegate delegate1 = sManager.getDelegate(nb0);
if (delegate1 == null) {
@@ -495,7 +522,7 @@
private static Bitmap createBitmap(Bitmap_Delegate delegate, boolean isMutable, int density) {
// get its native_int
- int nativeInt = sManager.addDelegate(delegate);
+ int nativeInt = sManager.addNewDelegate(delegate);
// and create/return a new Bitmap with it
return new Bitmap(nativeInt, null /* buffer */, isMutable, null /*ninePatchChunk*/, density);
diff --git a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
index 34824b4..4becba1 100644
--- a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.BlurMaskFilter
@@ -53,9 +54,10 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeConstructor(float radius, int style) {
BlurMaskFilter_Delegate newDelegate = new BlurMaskFilter_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
index 5a6902c..4decd1a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -20,6 +20,7 @@
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.impl.GcSnapshot;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Bitmap.Config;
import android.graphics.Paint_Delegate.FontInfo;
@@ -53,7 +54,7 @@
// ---- delegate manager ----
private static final DelegateManager<Canvas_Delegate> sManager =
- new DelegateManager<Canvas_Delegate>();
+ new DelegateManager<Canvas_Delegate>(Canvas_Delegate.class);
// ---- delegate helper data ----
@@ -63,7 +64,7 @@
private Bitmap_Delegate mBitmap;
private GcSnapshot mSnapshot;
- private int mDrawFilter = 0;
+ private DrawFilter_Delegate mDrawFilter = null;
// ---- Public Helper methods ----
@@ -94,11 +95,12 @@
* @return the delegate or null.
*/
public DrawFilter_Delegate getDrawFilter() {
- return DrawFilter_Delegate.getDelegate(mDrawFilter);
+ return mDrawFilter;
}
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static boolean isOpaque(Canvas thisCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
@@ -109,6 +111,7 @@
return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
}
+ @LayoutlibDelegate
/*package*/ static int getWidth(Canvas thisCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
@@ -119,6 +122,7 @@
return canvasDelegate.mBitmap.getImage().getWidth();
}
+ @LayoutlibDelegate
/*package*/ static int getHeight(Canvas thisCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
@@ -129,7 +133,8 @@
return canvasDelegate.mBitmap.getImage().getHeight();
}
- /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
+ @LayoutlibDelegate
+ /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
if (canvasDelegate == null) {
@@ -139,6 +144,7 @@
canvasDelegate.getSnapshot().translate(dx, dy);
}
+ @LayoutlibDelegate
/*package*/ static void rotate(Canvas thisCanvas, float degrees) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
@@ -149,7 +155,8 @@
canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
}
- /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
+ @LayoutlibDelegate
+ /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
if (canvasDelegate == null) {
@@ -159,7 +166,8 @@
canvasDelegate.getSnapshot().scale(sx, sy);
}
- /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
+ @LayoutlibDelegate
+ /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
if (canvasDelegate == null) {
@@ -182,15 +190,18 @@
g.setTransform(currentTx);
}
+ @LayoutlibDelegate
/*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
}
+ @LayoutlibDelegate
/*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
return clipRect(thisCanvas, (float) rect.left, (float) rect.top,
(float) rect.right, (float) rect.bottom);
}
+ @LayoutlibDelegate
/*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
float bottom) {
// get the delegate from the native int.
@@ -202,16 +213,19 @@
return canvasDelegate.clipRect(left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
}
+ @LayoutlibDelegate
/*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right,
int bottom) {
return clipRect(thisCanvas, (float) left, (float) top, (float) right, (float) bottom);
}
+ @LayoutlibDelegate
/*package*/ static int save(Canvas thisCanvas) {
return save(thisCanvas, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG);
}
+ @LayoutlibDelegate
/*package*/ static int save(Canvas thisCanvas, int saveFlags) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
@@ -222,6 +236,7 @@
return canvasDelegate.save(saveFlags);
}
+ @LayoutlibDelegate
/*package*/ static void restore(Canvas thisCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
@@ -232,6 +247,7 @@
canvasDelegate.restore();
}
+ @LayoutlibDelegate
/*package*/ static int getSaveCount(Canvas thisCanvas) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
@@ -242,6 +258,7 @@
return canvasDelegate.getSnapshot().size();
}
+ @LayoutlibDelegate
/*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
@@ -252,17 +269,22 @@
canvasDelegate.restoreTo(saveCount);
}
+ @LayoutlibDelegate
/*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
Paint paint) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPoint is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPoint is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void drawLines(Canvas thisCanvas,
final float[] pts, final int offset, final int count,
Paint paint) {
@@ -277,10 +299,12 @@
});
}
+ @LayoutlibDelegate
/*package*/ static void freeCaches() {
// nothing to be done here.
}
+ @LayoutlibDelegate
/*package*/ static int initRaster(int nativeBitmapOrZero) {
if (nativeBitmapOrZero > 0) {
// get the Bitmap from the int
@@ -289,15 +313,16 @@
// create a new Canvas_Delegate with the given bitmap and return its new native int.
Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
} else {
// create a new Canvas_Delegate and return its new native int.
Canvas_Delegate newDelegate = new Canvas_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
}
+ @LayoutlibDelegate
/*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -314,6 +339,7 @@
canvasDelegate.setBitmap(bitmapDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds,
int paint, int layerFlags) {
// get the delegate from the native int.
@@ -330,6 +356,7 @@
return canvasDelegate.saveLayer(bounds, paintDelegate, layerFlags);
}
+ @LayoutlibDelegate
/*package*/ static int native_saveLayer(int nativeCanvas, float l,
float t, float r, float b,
int paint, int layerFlags) {
@@ -348,6 +375,7 @@
paintDelegate, layerFlags);
}
+ @LayoutlibDelegate
/*package*/ static int native_saveLayerAlpha(int nativeCanvas,
RectF bounds, int alpha,
int layerFlags) {
@@ -360,6 +388,7 @@
return canvasDelegate.saveLayerAlpha(bounds, alpha, layerFlags);
}
+ @LayoutlibDelegate
/*package*/ static int native_saveLayerAlpha(int nativeCanvas, float l,
float t, float r, float b,
int alpha, int layerFlags) {
@@ -373,6 +402,7 @@
}
+ @LayoutlibDelegate
/*package*/ static void native_concat(int nCanvas, int nMatrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
@@ -400,6 +430,7 @@
snapshot.setTransform(currentTx);
}
+ @LayoutlibDelegate
/*package*/ static void native_setMatrix(int nCanvas, int nMatrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
@@ -429,6 +460,7 @@
}
}
+ @LayoutlibDelegate
/*package*/ static boolean native_clipRect(int nCanvas,
float left, float top,
float right, float bottom,
@@ -443,6 +475,7 @@
return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
}
+ @LayoutlibDelegate
/*package*/ static boolean native_clipPath(int nativeCanvas,
int nativePath,
int regionOp) {
@@ -459,6 +492,7 @@
return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp);
}
+ @LayoutlibDelegate
/*package*/ static boolean native_clipRegion(int nativeCanvas,
int nativeRegion,
int regionOp) {
@@ -475,29 +509,23 @@
return canvasDelegate.mSnapshot.clip(region.getJavaArea(), regionOp);
}
- /*package*/ static void nativeSetDrawFilter(int nativeCanvas,
- int nativeFilter) {
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetDrawFilter(int nativeCanvas, int nativeFilter) {
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
if (canvasDelegate == null) {
return;
}
- canvasDelegate.mDrawFilter = nativeFilter;
+ canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter);
- // get the delegate only because we don't support them at all for the moment, so
- // we can display the message now.
-
- DrawFilter_Delegate filterDelegate = DrawFilter_Delegate.getDelegate(nativeFilter);
- if (canvasDelegate == null) {
- return;
- }
-
- if (filterDelegate.isSupported() == false) {
+ if (canvasDelegate.mDrawFilter != null &&
+ canvasDelegate.mDrawFilter.isSupported() == false) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER,
- filterDelegate.getSupportMessage(), null, null /*data*/);
+ canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/);
}
}
+ @LayoutlibDelegate
/*package*/ static boolean native_getClipBounds(int nativeCanvas,
Rect bounds) {
// get the delegate from the native int.
@@ -518,6 +546,7 @@
return false;
}
+ @LayoutlibDelegate
/*package*/ static void native_getCTM(int canvas, int matrix) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
@@ -534,6 +563,7 @@
matrixDelegate.set(Matrix_Delegate.makeValues(transform));
}
+ @LayoutlibDelegate
/*package*/ static boolean native_quickReject(int nativeCanvas,
RectF rect,
int native_edgeType) {
@@ -541,6 +571,7 @@
return false;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_quickReject(int nativeCanvas,
int path,
int native_edgeType) {
@@ -548,6 +579,7 @@
return false;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_quickReject(int nativeCanvas,
float left, float top,
float right, float bottom,
@@ -556,21 +588,25 @@
return false;
}
+ @LayoutlibDelegate
/*package*/ static void native_drawRGB(int nativeCanvas, int r, int g, int b) {
native_drawColor(nativeCanvas, 0xFF000000 | r << 16 | (g&0xFF) << 8 | (b&0xFF),
PorterDuff.Mode.SRC_OVER.nativeInt);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawARGB(int nativeCanvas, int a, int r, int g, int b) {
native_drawColor(nativeCanvas, a << 24 | (r&0xFF) << 16 | (g&0xFF) << 8 | (b&0xFF),
PorterDuff.Mode.SRC_OVER.nativeInt);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawColor(int nativeCanvas, int color) {
native_drawColor(nativeCanvas, color, PorterDuff.Mode.SRC_OVER.nativeInt);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawColor(int nativeCanvas, final int color, final int mode) {
// get the delegate from the native int.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -600,11 +636,14 @@
});
}
+ @LayoutlibDelegate
/*package*/ static void native_drawPaint(int nativeCanvas, int paint) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPaint is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawLine(int nativeCanvas,
final float startX, final float startY, final float stopX, final float stopY,
int paint) {
@@ -617,11 +656,13 @@
});
}
+ @LayoutlibDelegate
/*package*/ static void native_drawRect(int nativeCanvas, RectF rect,
int paint) {
native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawRect(int nativeCanvas,
final float left, final float top, final float right, final float bottom, int paint) {
@@ -646,6 +687,7 @@
});
}
+ @LayoutlibDelegate
/*package*/ static void native_drawOval(int nativeCanvas, final RectF oval, int paint) {
if (oval.right > oval.left && oval.bottom > oval.top) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
@@ -670,21 +712,23 @@
}
}
- /*package*/ static void native_drawCircle(int nativeCanvas, float cx,
- float cy, float radius,
- int paint) {
+ @LayoutlibDelegate
+ /*package*/ static void native_drawCircle(int nativeCanvas,
+ float cx, float cy, float radius, int paint) {
native_drawOval(nativeCanvas,
new RectF(cx - radius, cy - radius, radius*2, radius*2),
paint);
}
- /*package*/ static void native_drawArc(int nativeCanvas, RectF oval,
- float startAngle, float sweep,
- boolean useCenter, int paint) {
+ @LayoutlibDelegate
+ /*package*/ static void native_drawArc(int nativeCanvas,
+ RectF oval, float startAngle, float sweep, boolean useCenter, int paint) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawArc is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawRoundRect(int nativeCanvas,
final RectF rect, final float rx, final float ry, int paint) {
@@ -713,8 +757,8 @@
});
}
- /*package*/ static void native_drawPath(int nativeCanvas, int path,
- int paint) {
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPath(int nativeCanvas, int path, int paint) {
final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
if (pathDelegate == null) {
return;
@@ -739,6 +783,7 @@
});
}
+ @LayoutlibDelegate
/*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
float left, float top,
int nativePaintOrZero,
@@ -760,6 +805,7 @@
(int)left, (int)top, (int)right, (int)bottom);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
Rect src, RectF dst,
int nativePaintOrZero,
@@ -784,6 +830,7 @@
}
}
+ @LayoutlibDelegate
/*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap,
Rect src, Rect dst,
int nativePaintOrZero,
@@ -808,6 +855,7 @@
}
}
+ @LayoutlibDelegate
/*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors,
int offset, int stride, final float x,
final float y, int width, int height,
@@ -832,6 +880,7 @@
});
}
+ @LayoutlibDelegate
/*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
int nMatrix, int nPaint) {
// get the delegate from the native int.
@@ -871,29 +920,35 @@
}, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/);
}
+ @LayoutlibDelegate
/*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
- int meshWidth, int meshHeight,
- float[] verts, int vertOffset,
- int[] colors, int colorOffset, int nPaint) {
+ int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors,
+ int colorOffset, int nPaint) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawBitmapMesh is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void nativeDrawVertices(int nCanvas, int mode, int n,
- float[] verts, int vertOffset, float[] texs, int texOffset,
- int[] colors, int colorOffset, short[] indices,
- int indexOffset, int indexCount, int nPaint) {
+ float[] verts, int vertOffset,
+ float[] texs, int texOffset,
+ int[] colors, int colorOffset,
+ short[] indices, int indexOffset,
+ int indexCount, int nPaint) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawVertices is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawText(int nativeCanvas,
final char[] text, final int index, final int count,
final float startX, final float startY, int flags, int paint) {
draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
new GcSnapshot.Drawable() {
public void draw(Graphics2D graphics, Paint_Delegate paint) {
- // WARNING: the logic in this method is similar to Paint.measureText.
+ // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
// Any change to this method should be reflected in Paint.measureText
// Paint.TextAlign indicates how the text is positioned relative to X.
// LEFT is the default and there's nothing to do.
@@ -986,6 +1041,7 @@
});
}
+ @LayoutlibDelegate
/*package*/ static void native_drawText(int nativeCanvas, String text,
int start, int end, float x,
float y, int flags, int paint) {
@@ -996,6 +1052,7 @@
native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawTextRun(int nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
float x, float y, int flags, int paint) {
@@ -1006,27 +1063,33 @@
native_drawText(nativeCanvas, buffer, start, end, x, y, flags, paint);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawTextRun(int nativeCanvas, char[] text,
int start, int count, int contextStart, int contextCount,
float x, float y, int flags, int paint) {
native_drawText(nativeCanvas, text, start, count, x, y, flags, paint);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawPosText(int nativeCanvas,
char[] text, int index,
int count, float[] pos,
int paint) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPosText is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawPosText(int nativeCanvas,
String text, float[] pos,
int paint) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPosText is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawTextOnPath(int nativeCanvas,
char[] text, int index,
int count, int path,
@@ -1034,24 +1097,30 @@
float vOffset, int bidiFlags,
int paint) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawTextOnPath(int nativeCanvas,
String text, int path,
float hOffset,
float vOffset,
int flags, int paint) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_drawPicture(int nativeCanvas,
int nativePicture) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPicture is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void finalizer(int nativeCanvas) {
// get the delegate from the native int so that it can be disposed.
Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
@@ -1062,7 +1131,7 @@
canvasDelegate.dispose();
// remove it from the manager.
- sManager.removeDelegate(nativeCanvas);
+ sManager.removeJavaReferenceFor(nativeCanvas);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
index 3df170f..e5a7ab6 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.ColorFilter
@@ -37,7 +38,7 @@
// ---- delegate manager ----
protected static final DelegateManager<ColorFilter_Delegate> sManager =
- new DelegateManager<ColorFilter_Delegate>();
+ new DelegateManager<ColorFilter_Delegate>(ColorFilter_Delegate.class);
// ---- delegate helper data ----
@@ -54,8 +55,9 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static void finalizer(int native_instance, int nativeColorFilter) {
- sManager.removeDelegate(native_instance);
+ sManager.removeJavaReferenceFor(native_instance);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
index 42843279..2de344b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.ColorMatrixColorFilter
@@ -53,11 +54,13 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeColorMatrixFilter(float[] array) {
ColorMatrixColorFilter_Delegate newDelegate = new ColorMatrixColorFilter_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int nColorMatrixFilter(int nativeFilter, float[] array) {
// pass
return 0;
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java
index 39cbbc6..7c04a87 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
@@ -60,9 +61,10 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate(int outerpe, int innerpe) {
ComposePathEffect_Delegate newDelegate = new ComposePathEffect_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
index b4baa6f..f6e1d00 100644
--- a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Paint;
@@ -61,33 +62,36 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate1(int native_shaderA, int native_shaderB,
int native_mode) {
// FIXME not supported yet.
ComposeShader_Delegate newDelegate = new ComposeShader_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int nativeCreate2(int native_shaderA, int native_shaderB,
int porterDuffMode) {
// FIXME not supported yet.
ComposeShader_Delegate newDelegate = new ComposeShader_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int nativePostCreate1(int native_shader, int native_skiaShaderA,
int native_skiaShaderB, int native_mode) {
// pass, not needed.
return 0;
}
+ @LayoutlibDelegate
/*package*/ static int nativePostCreate2(int native_shader, int native_skiaShaderA,
int native_skiaShaderB, int porterDuffMode) {
// pass, not needed.
return 0;
}
-
// ---- Private delegate/helper methods ----
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java
index 0307cfb..b0f8168 100644
--- a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
@@ -60,9 +61,10 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate(float radius) {
CornerPathEffect_Delegate newDelegate = new CornerPathEffect_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
index 5a704a7..d97c2ec 100644
--- a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.BasicStroke;
import java.awt.Stroke;
@@ -71,9 +72,10 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate(float intervals[], float phase) {
DashPathEffect_Delegate newDelegate = new DashPathEffect_Delegate(intervals, phase);
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
index 04d7170..ec4a810 100644
--- a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
@@ -60,9 +61,10 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate(float length, float deviation) {
DiscretePathEffect_Delegate newDelegate = new DiscretePathEffect_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
index ddf20b6..870c46b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.DrawFilter
@@ -37,7 +38,7 @@
// ---- delegate manager ----
protected static final DelegateManager<DrawFilter_Delegate> sManager =
- new DelegateManager<DrawFilter_Delegate>();
+ new DelegateManager<DrawFilter_Delegate>(DrawFilter_Delegate.class);
// ---- delegate helper data ----
@@ -54,8 +55,9 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static void nativeDestructor(int nativeDrawFilter) {
- sManager.removeDelegate(nativeDrawFilter);
+ sManager.removeJavaReferenceFor(nativeDrawFilter);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
index 82f1da3..ebc1c1d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.EmbossMaskFilter
@@ -53,10 +54,11 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeConstructor(float[] direction, float ambient,
float specular, float blurRadius) {
EmbossMaskFilter_Delegate newDelegate = new EmbossMaskFilter_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
index 132004f9..51e0576 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.LayerRasterizer
@@ -53,11 +54,13 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeConstructor() {
LayerRasterizer_Delegate newDelegate = new LayerRasterizer_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static void nativeAddLayer(int native_layer, int native_paint, float dx, float dy) {
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
index ba2cfad..0ee883d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.LightingColorFilter
@@ -53,11 +54,13 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int native_CreateLightingFilter(int mul, int add) {
LightingColorFilter_Delegate newDelegate = new LightingColorFilter_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int nCreateLightingFilter(int nativeFilter, int mul, int add) {
// pass
return 0;
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
index 9525dcf..a2ba758 100644
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -19,6 +19,7 @@
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Shader.TileMode;
@@ -52,13 +53,16 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate1(LinearGradient thisGradient,
float x0, float y0, float x1, float y1,
int colors[], float positions[], int tileMode) {
LinearGradient_Delegate newDelegate = new LinearGradient_Delegate(x0, y0, x1, y1,
colors, positions, Shader_Delegate.getTileMode(tileMode));
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+
+ @LayoutlibDelegate
/*package*/ static int nativeCreate2(LinearGradient thisGradient,
float x0, float y0, float x1, float y1,
int color0, int color1, int tileMode) {
@@ -66,12 +70,16 @@
x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/,
tileMode);
}
+
+ @LayoutlibDelegate
/*package*/ static int nativePostCreate1(LinearGradient thisGradient,
int native_shader, float x0, float y0, float x1, float y1,
int colors[], float positions[], int tileMode) {
// nothing to be done here.
return 0;
}
+
+ @LayoutlibDelegate
/*package*/ static int nativePostCreate2(LinearGradient thisGradient,
int native_shader, float x0, float y0, float x1, float y1,
int color0, int color1, int tileMode) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
index c582a91..c2f27e4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.MaskFilter
@@ -37,7 +38,7 @@
// ---- delegate manager ----
protected static final DelegateManager<MaskFilter_Delegate> sManager =
- new DelegateManager<MaskFilter_Delegate>();
+ new DelegateManager<MaskFilter_Delegate>(MaskFilter_Delegate.class);
// ---- delegate helper data ----
@@ -54,8 +55,9 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static void nativeDestructor(int native_filter) {
- sManager.removeDelegate(native_filter);
+ sManager.removeJavaReferenceFor(native_filter);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
index 2d77d40..451edd2 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -20,6 +20,7 @@
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Matrix.ScaleToFit;
@@ -45,7 +46,7 @@
// ---- delegate manager ----
private static final DelegateManager<Matrix_Delegate> sManager =
- new DelegateManager<Matrix_Delegate>();
+ new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class);
// ---- delegate data ----
private float mValues[] = new float[MATRIX_SIZE];
@@ -172,6 +173,7 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int native_create(int native_src_or_zero) {
// create the delegate
Matrix_Delegate newDelegate = new Matrix_Delegate();
@@ -187,9 +189,10 @@
}
}
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static boolean native_isIdentity(int native_object) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -199,6 +202,7 @@
return d.isIdentity();
}
+ @LayoutlibDelegate
/*package*/ static boolean native_rectStaysRect(int native_object) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -208,6 +212,7 @@
return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
}
+ @LayoutlibDelegate
/*package*/ static void native_reset(int native_object) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -217,6 +222,7 @@
reset(d.mValues);
}
+ @LayoutlibDelegate
/*package*/ static void native_set(int native_object, int other) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -231,6 +237,7 @@
System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE);
}
+ @LayoutlibDelegate
/*package*/ static void native_setTranslate(int native_object, float dx, float dy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -240,6 +247,7 @@
setTranslate(d.mValues, dx, dy);
}
+ @LayoutlibDelegate
/*package*/ static void native_setScale(int native_object, float sx, float sy,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -250,6 +258,7 @@
d.mValues = getScale(sx, sy, px, py);
}
+ @LayoutlibDelegate
/*package*/ static void native_setScale(int native_object, float sx, float sy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -267,6 +276,7 @@
d.mValues[8] = 1;
}
+ @LayoutlibDelegate
/*package*/ static void native_setRotate(int native_object, float degrees, float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -276,6 +286,7 @@
d.mValues = getRotate(degrees, px, py);
}
+ @LayoutlibDelegate
/*package*/ static void native_setRotate(int native_object, float degrees) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -285,6 +296,7 @@
setRotate(d.mValues, degrees);
}
+ @LayoutlibDelegate
/*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -303,6 +315,7 @@
d.postTransform(getTranslate(px, py));
}
+ @LayoutlibDelegate
/*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -312,6 +325,7 @@
setRotate(d.mValues, sinValue, cosValue);
}
+ @LayoutlibDelegate
/*package*/ static void native_setSkew(int native_object, float kx, float ky,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -322,6 +336,7 @@
d.mValues = getSkew(kx, ky, px, py);
}
+ @LayoutlibDelegate
/*package*/ static void native_setSkew(int native_object, float kx, float ky) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -339,6 +354,7 @@
d.mValues[8] = 1;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_setConcat(int native_object, int a, int b) {
if (a == native_object) {
return native_preConcat(native_object, b);
@@ -366,6 +382,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_preTranslate(int native_object, float dx, float dy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -376,6 +393,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_preScale(int native_object, float sx, float sy,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -387,6 +405,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_preScale(int native_object, float sx, float sy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -397,6 +416,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_preRotate(int native_object, float degrees,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -408,6 +428,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_preRotate(int native_object, float degrees) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -422,6 +443,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_preSkew(int native_object, float kx, float ky,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -433,6 +455,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_preSkew(int native_object, float kx, float ky) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -443,6 +466,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_preConcat(int native_object, int other_matrix) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -458,6 +482,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_postTranslate(int native_object, float dx, float dy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -468,6 +493,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_postScale(int native_object, float sx, float sy,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -479,6 +505,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_postScale(int native_object, float sx, float sy) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -489,6 +516,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_postRotate(int native_object, float degrees,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -500,6 +528,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_postRotate(int native_object, float degrees) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -510,6 +539,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_postSkew(int native_object, float kx, float ky,
float px, float py) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -521,6 +551,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_postSkew(int native_object, float kx, float ky) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -531,6 +562,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_postConcat(int native_object, int other_matrix) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -546,6 +578,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_setRectToRect(int native_object, RectF src,
RectF dst, int stf) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -610,6 +643,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex,
float[] dst, int dstIndex, int pointCount) {
// FIXME
@@ -619,6 +653,7 @@
return false;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_invert(int native_object, int inverse) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -646,6 +681,7 @@
}
}
+ @LayoutlibDelegate
/*package*/ static void native_mapPoints(int native_object, float[] dst, int dstIndex,
float[] src, int srcIndex, int ptCount, boolean isPts) {
Matrix_Delegate d = sManager.getDelegate(native_object);
@@ -660,6 +696,7 @@
}
}
+ @LayoutlibDelegate
/*package*/ static boolean native_mapRect(int native_object, RectF dst, RectF src) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -669,6 +706,7 @@
return d.mapRect(dst, src);
}
+ @LayoutlibDelegate
/*package*/ static float native_mapRadius(int native_object, float radius) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -684,6 +722,7 @@
return (float) Math.sqrt(l1 * l2);
}
+ @LayoutlibDelegate
/*package*/ static void native_getValues(int native_object, float[] values) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -693,6 +732,7 @@
System.arraycopy(d.mValues, 0, d.mValues, 0, MATRIX_SIZE);
}
+ @LayoutlibDelegate
/*package*/ static void native_setValues(int native_object, float[] values) {
Matrix_Delegate d = sManager.getDelegate(native_object);
if (d == null) {
@@ -702,6 +742,7 @@
System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE);
}
+ @LayoutlibDelegate
/*package*/ static boolean native_equals(int native_a, int native_b) {
Matrix_Delegate a = sManager.getDelegate(native_a);
if (a == null) {
@@ -722,8 +763,9 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static void finalizer(int native_instance) {
- sManager.removeDelegate(native_instance);
+ sManager.removeJavaReferenceFor(native_instance);
}
// ---- Private helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
index 61ed71e..5e882ce 100644
--- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -21,6 +21,7 @@
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.impl.GcSnapshot;
import com.android.ninepatch.NinePatchChunk;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.drawable.NinePatchDrawable;
@@ -137,6 +138,7 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static boolean isNinePatchChunk(byte[] chunk) {
NinePatchChunk chunkObject = getChunk(chunk);
if (chunkObject != null) {
@@ -146,12 +148,14 @@
return false;
}
+ @LayoutlibDelegate
/*package*/ static void validateNinePatchChunk(int bitmap, byte[] chunk) {
// the default JNI implementation only checks that the byte[] has the same
// size as the C struct it represent. Since we cannot do the same check (serialization
// will return different size depending on content), we do nothing.
}
+ @LayoutlibDelegate
/*package*/ static void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) {
draw(canvas_instance,
@@ -160,6 +164,7 @@
destDensity, srcDensity);
}
+ @LayoutlibDelegate
/*package*/ static void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) {
draw(canvas_instance,
@@ -168,54 +173,53 @@
destDensity, srcDensity);
}
- private static void draw(int canvas_instance,
- final int left, final int top, final int right, final int bottom,
- int bitmap_instance, byte[] c, int paint_instance_or_null,
- final int destDensity, final int srcDensity) {
- // get the delegate from the native int.
- final Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance);
- if (bitmap_delegate == null) {
- return;
- }
-
- if (c == null) {
- // not a 9-patch?
- BufferedImage image = bitmap_delegate.getImage();
- Canvas_Delegate.native_drawBitmap(canvas_instance, bitmap_instance,
- new Rect(0, 0, image.getWidth(), image.getHeight()),
- new Rect(left, top, right, bottom),
- paint_instance_or_null, destDensity, srcDensity);
- return;
- }
-
- final NinePatchChunk chunkObject = getChunk(c);
- assert chunkObject != null;
- if (chunkObject == null) {
- return;
- }
-
- Canvas_Delegate canvas_delegate = Canvas_Delegate.getDelegate(canvas_instance);
- if (canvas_delegate == null) {
- return;
- }
-
- // this one can be null
- Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null);
-
- canvas_delegate.getSnapshot().draw(new GcSnapshot.Drawable() {
- public void draw(Graphics2D graphics, Paint_Delegate paint) {
- chunkObject.draw(bitmap_delegate.getImage(), graphics,
- left, top, right - left, bottom - top, destDensity, srcDensity);
- }
- }, paint_delegate, true /*compositeOnly*/, false /*forceSrcMode*/);
-
- }
-
+ @LayoutlibDelegate
/*package*/ static int nativeGetTransparentRegion(int bitmap, byte[] chunk, Rect location) {
return 0;
}
// ---- Private Helper methods ----
+ private static void draw(int canvas_instance,
+ final int left, final int top, final int right, final int bottom,
+ int bitmap_instance, byte[] c, int paint_instance_or_null,
+ final int destDensity, final int srcDensity) {
+ // get the delegate from the native int.
+ final Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance);
+ if (bitmap_delegate == null) {
+ return;
+ }
+ if (c == null) {
+ // not a 9-patch?
+ BufferedImage image = bitmap_delegate.getImage();
+ Canvas_Delegate.native_drawBitmap(canvas_instance, bitmap_instance,
+ new Rect(0, 0, image.getWidth(), image.getHeight()),
+ new Rect(left, top, right, bottom),
+ paint_instance_or_null, destDensity, srcDensity);
+ return;
+ }
+
+ final NinePatchChunk chunkObject = getChunk(c);
+ assert chunkObject != null;
+ if (chunkObject == null) {
+ return;
+ }
+
+ Canvas_Delegate canvas_delegate = Canvas_Delegate.getDelegate(canvas_instance);
+ if (canvas_delegate == null) {
+ return;
+ }
+
+ // this one can be null
+ Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null);
+
+ canvas_delegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ chunkObject.draw(bitmap_delegate.getImage(), graphics,
+ left, top, right - left, bottom - top, destDensity, srcDensity);
+ }
+ }, paint_delegate, true /*compositeOnly*/, false /*forceSrcMode*/);
+
+ }
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
index ec92507..71d346a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.PaintFlagsDrawFilter
@@ -53,9 +54,10 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeConstructor(int clearBits, int setBits) {
PaintFlagsDrawFilter_Delegate newDelegate = new PaintFlagsDrawFilter_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 87164fb..373f482 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -19,6 +19,7 @@
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Paint.FontMetrics;
import android.graphics.Paint.FontMetricsInt;
@@ -31,6 +32,7 @@
import java.awt.Toolkit;
import java.awt.font.FontRenderContext;
import java.awt.geom.AffineTransform;
+import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@@ -60,7 +62,7 @@
// ---- delegate manager ----
private static final DelegateManager<Paint_Delegate> sManager =
- new DelegateManager<Paint_Delegate>();
+ new DelegateManager<Paint_Delegate>(Paint_Delegate.class);
// ---- delegate helper data ----
private List<FontInfo> mFonts;
@@ -74,19 +76,19 @@
private int mCap;
private int mJoin;
private int mTextAlign;
- private int mTypeface;
+ private Typeface_Delegate mTypeface;
private float mStrokeWidth;
private float mStrokeMiter;
private float mTextSize;
private float mTextScaleX;
private float mTextSkewX;
- private int mXfermode;
- private int mColorFilter;
- private int mShader;
- private int mPathEffect;
- private int mMaskFilter;
- private int mRasterizer;
+ private Xfermode_Delegate mXfermode;
+ private ColorFilter_Delegate mColorFilter;
+ private Shader_Delegate mShader;
+ private PathEffect_Delegate mPathEffect;
+ private MaskFilter_Delegate mMaskFilter;
+ private Rasterizer_Delegate mRasterizer;
// ---- Public Helper methods ----
@@ -171,17 +173,16 @@
}
public Stroke getJavaStroke() {
- PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(mPathEffect);
- if (effectDelegate != null) {
- if (effectDelegate.isSupported()) {
- Stroke stroke = effectDelegate.getStroke(this);
+ if (mPathEffect != null) {
+ if (mPathEffect.isSupported()) {
+ Stroke stroke = mPathEffect.getStroke(this);
assert stroke != null;
if (stroke != null) {
return stroke;
}
} else {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT,
- effectDelegate.getSupportMessage(),
+ mPathEffect.getSupportMessage(),
null, null /*data*/);
}
}
@@ -200,7 +201,7 @@
* @return the delegate or null.
*/
public Xfermode_Delegate getXfermode() {
- return Xfermode_Delegate.getDelegate(mXfermode);
+ return mXfermode;
}
/**
@@ -209,7 +210,7 @@
* @return the delegate or null.
*/
public ColorFilter_Delegate getColorFilter() {
- return ColorFilter_Delegate.getDelegate(mColorFilter);
+ return mColorFilter;
}
/**
@@ -218,7 +219,7 @@
* @return the delegate or null.
*/
public Shader_Delegate getShader() {
- return Shader_Delegate.getDelegate(mShader);
+ return mShader;
}
/**
@@ -227,7 +228,7 @@
* @return the delegate or null.
*/
public MaskFilter_Delegate getMaskFilter() {
- return MaskFilter_Delegate.getDelegate(mMaskFilter);
+ return mMaskFilter;
}
/**
@@ -236,11 +237,12 @@
* @return the delegate or null.
*/
public Rasterizer_Delegate getRasterizer() {
- return Rasterizer_Delegate.getDelegate(mRasterizer);
+ return mRasterizer;
}
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int getFlags(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -251,6 +253,7 @@
return delegate.mFlags;
}
+ @LayoutlibDelegate
/*package*/ static void setFlags(Paint thisPaint, int flags) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -261,38 +264,47 @@
delegate.mFlags = flags;
}
+ @LayoutlibDelegate
/*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
}
+ @LayoutlibDelegate
/*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
}
+ @LayoutlibDelegate
/*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
}
+ @LayoutlibDelegate
/*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
}
+ @LayoutlibDelegate
/*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
}
+ @LayoutlibDelegate
/*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
}
+ @LayoutlibDelegate
/*package*/ static void setDither(Paint thisPaint, boolean dither) {
setFlag(thisPaint, Paint.DITHER_FLAG, dither);
}
+ @LayoutlibDelegate
/*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
}
+ @LayoutlibDelegate
/*package*/ static int getColor(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -303,6 +315,7 @@
return delegate.mColor;
}
+ @LayoutlibDelegate
/*package*/ static void setColor(Paint thisPaint, int color) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -313,6 +326,7 @@
delegate.mColor = color;
}
+ @LayoutlibDelegate
/*package*/ static int getAlpha(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -323,6 +337,7 @@
return delegate.getAlpha();
}
+ @LayoutlibDelegate
/*package*/ static void setAlpha(Paint thisPaint, int a) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -333,6 +348,7 @@
delegate.setAlpha(a);
}
+ @LayoutlibDelegate
/*package*/ static float getStrokeWidth(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -343,6 +359,7 @@
return delegate.mStrokeWidth;
}
+ @LayoutlibDelegate
/*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -353,6 +370,7 @@
delegate.mStrokeWidth = width;
}
+ @LayoutlibDelegate
/*package*/ static float getStrokeMiter(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -363,6 +381,7 @@
return delegate.mStrokeMiter;
}
+ @LayoutlibDelegate
/*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -373,6 +392,7 @@
delegate.mStrokeMiter = miter;
}
+ @LayoutlibDelegate
/*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
int color) {
// FIXME
@@ -380,6 +400,7 @@
"Paint.setShadowLayer is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static float getTextSize(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -390,6 +411,7 @@
return delegate.mTextSize;
}
+ @LayoutlibDelegate
/*package*/ static void setTextSize(Paint thisPaint, float textSize) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -401,6 +423,7 @@
delegate.updateFontObject();
}
+ @LayoutlibDelegate
/*package*/ static float getTextScaleX(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -411,6 +434,7 @@
return delegate.mTextScaleX;
}
+ @LayoutlibDelegate
/*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -422,6 +446,7 @@
delegate.updateFontObject();
}
+ @LayoutlibDelegate
/*package*/ static float getTextSkewX(Paint thisPaint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -432,6 +457,7 @@
return delegate.mTextSkewX;
}
+ @LayoutlibDelegate
/*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -443,6 +469,7 @@
delegate.updateFontObject();
}
+ @LayoutlibDelegate
/*package*/ static float ascent(Paint thisPaint) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -459,6 +486,7 @@
return 0;
}
+ @LayoutlibDelegate
/*package*/ static float descent(Paint thisPaint) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -475,6 +503,7 @@
}
+ @LayoutlibDelegate
/*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -485,6 +514,7 @@
return delegate.getFontMetrics(metrics);
}
+ @LayoutlibDelegate
/*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
@@ -509,11 +539,9 @@
return 0;
}
+ @LayoutlibDelegate
/*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
int count) {
- // WARNING: the logic in this method is similar to Canvas.drawText.
- // Any change to this method should be reflected in Canvas.drawText
-
// get the delegate
Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
if (delegate == null) {
@@ -523,32 +551,73 @@
return delegate.measureText(text, index, count);
}
+ @LayoutlibDelegate
/*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
return native_measureText(thisPaint, text.toCharArray(), start, end - start);
}
+ @LayoutlibDelegate
/*package*/ static float native_measureText(Paint thisPaint, String text) {
return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
}
+ @LayoutlibDelegate
/*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
float maxWidth, float[] measuredWidth) {
- // FIXME
- throw new UnsupportedOperationException();
+
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ int inc = count > 0 ? 1 : -1;
+
+ int measureIndex = 0;
+ float measureAcc = 0;
+ for (int i = index; i != index + count; i += inc, measureIndex++) {
+ int start, end;
+ if (i < index) {
+ start = i;
+ end = index;
+ } else {
+ start = index;
+ end = i;
+ }
+
+ // measure from start to end
+ float res = delegate.measureText(text, start, end - start + 1);
+
+ if (measuredWidth != null) {
+ measuredWidth[measureIndex] = res;
+ }
+
+ measureAcc += res;
+ if (res > maxWidth) {
+ // we should not return this char index, but since it's 0-based
+ // and we need to return a count, we simply return measureIndex;
+ return measureIndex;
+ }
+
+ }
+
+ return measureIndex;
}
+ @LayoutlibDelegate
/*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
float maxWidth, float[] measuredWidth) {
- // FIXME
- throw new UnsupportedOperationException();
+ return native_breakText(thisPaint, text.toCharArray(), 0, text.length(), maxWidth,
+ measuredWidth);
}
-
+ @LayoutlibDelegate
/*package*/ static int native_init() {
Paint_Delegate newDelegate = new Paint_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int native_initWithPaint(int paint) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(paint);
@@ -557,9 +626,10 @@
}
Paint_Delegate newDelegate = new Paint_Delegate(delegate);
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static void native_reset(int native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -570,6 +640,7 @@
delegate.reset();
}
+ @LayoutlibDelegate
/*package*/ static void native_set(int native_dst, int native_src) {
// get the delegate from the native int.
Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
@@ -586,6 +657,7 @@
delegate_dst.set(delegate_src);
}
+ @LayoutlibDelegate
/*package*/ static int native_getStyle(int native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -596,6 +668,7 @@
return delegate.mStyle;
}
+ @LayoutlibDelegate
/*package*/ static void native_setStyle(int native_object, int style) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -606,6 +679,7 @@
delegate.mStyle = style;
}
+ @LayoutlibDelegate
/*package*/ static int native_getStrokeCap(int native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -616,6 +690,7 @@
return delegate.mCap;
}
+ @LayoutlibDelegate
/*package*/ static void native_setStrokeCap(int native_object, int cap) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -626,6 +701,7 @@
delegate.mCap = cap;
}
+ @LayoutlibDelegate
/*package*/ static int native_getStrokeJoin(int native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -636,6 +712,7 @@
return delegate.mJoin;
}
+ @LayoutlibDelegate
/*package*/ static void native_setStrokeJoin(int native_object, int join) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -646,6 +723,7 @@
delegate.mJoin = join;
}
+ @LayoutlibDelegate
/*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
Paint_Delegate paint = sManager.getDelegate(native_object);
if (paint == null) {
@@ -671,6 +749,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static int native_setShader(int native_object, int shader) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -678,9 +757,12 @@
return shader;
}
- return delegate.mShader = shader;
+ delegate.mShader = Shader_Delegate.getDelegate(shader);
+
+ return shader;
}
+ @LayoutlibDelegate
/*package*/ static int native_setColorFilter(int native_object, int filter) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -688,18 +770,18 @@
return filter;
}
- delegate.mColorFilter = filter;
+ delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);;
// since none of those are supported, display a fidelity warning right away
- ColorFilter_Delegate filterDelegate = delegate.getColorFilter();
- if (filterDelegate != null && filterDelegate.isSupported() == false) {
+ if (delegate.mColorFilter != null && delegate.mColorFilter.isSupported() == false) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER,
- filterDelegate.getSupportMessage(), null, null /*data*/);
+ delegate.mColorFilter.getSupportMessage(), null, null /*data*/);
}
return filter;
}
+ @LayoutlibDelegate
/*package*/ static int native_setXfermode(int native_object, int xfermode) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -707,9 +789,12 @@
return xfermode;
}
- return delegate.mXfermode = xfermode;
+ delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode);
+
+ return xfermode;
}
+ @LayoutlibDelegate
/*package*/ static int native_setPathEffect(int native_object, int effect) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -717,9 +802,12 @@
return effect;
}
- return delegate.mPathEffect = effect;
+ delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect);
+
+ return effect;
}
+ @LayoutlibDelegate
/*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -727,18 +815,18 @@
return maskfilter;
}
- delegate.mMaskFilter = maskfilter;
+ delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter);
// since none of those are supported, display a fidelity warning right away
- MaskFilter_Delegate filterDelegate = delegate.getMaskFilter();
- if (filterDelegate != null && filterDelegate.isSupported() == false) {
+ if (delegate.mMaskFilter != null && delegate.mMaskFilter.isSupported() == false) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
- filterDelegate.getSupportMessage(), null, null /*data*/);
+ delegate.mMaskFilter.getSupportMessage(), null, null /*data*/);
}
return maskfilter;
}
+ @LayoutlibDelegate
/*package*/ static int native_setTypeface(int native_object, int typeface) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -746,11 +834,12 @@
return 0;
}
- delegate.mTypeface = typeface;
+ delegate.mTypeface = Typeface_Delegate.getDelegate(typeface);
delegate.updateFontObject();
- return delegate.mTypeface;
+ return typeface;
}
+ @LayoutlibDelegate
/*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -758,18 +847,18 @@
return rasterizer;
}
- delegate.mRasterizer = rasterizer;
+ delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer);
// since none of those are supported, display a fidelity warning right away
- Rasterizer_Delegate rasterizerDelegate = delegate.getRasterizer();
- if (rasterizerDelegate != null && rasterizerDelegate.isSupported() == false) {
+ if (delegate.mRasterizer != null && delegate.mRasterizer.isSupported() == false) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER,
- rasterizerDelegate.getSupportMessage(), null, null /*data*/);
+ delegate.mRasterizer.getSupportMessage(), null, null /*data*/);
}
return rasterizer;
}
+ @LayoutlibDelegate
/*package*/ static int native_getTextAlign(int native_object) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -780,6 +869,7 @@
return delegate.mTextAlign;
}
+ @LayoutlibDelegate
/*package*/ static void native_setTextAlign(int native_object, int align) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_object);
@@ -790,6 +880,7 @@
delegate.mTextAlign = align;
}
+ @LayoutlibDelegate
/*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
// get the delegate from the native int.
Paint_Delegate delegate = sManager.getDelegate(native_paint);
@@ -800,18 +891,55 @@
return delegate.getFontMetrics(metrics);
}
+ @LayoutlibDelegate
/*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
int count, float[] widths) {
- // FIXME
- throw new UnsupportedOperationException();
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ // FIXME: handle multi-char characters (see measureText)
+ float totalAdvance = 0;
+ for (int i = 0; i < count; i++) {
+ char c = text[i + index];
+ boolean found = false;
+ for (FontInfo info : delegate.mFonts) {
+ if (info.mFont.canDisplay(c)) {
+ float adv = info.mMetrics.charWidth(c);
+ totalAdvance += adv;
+ if (widths != null) {
+ widths[i] = adv;
+ }
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ // no advance for this char.
+ if (widths != null) {
+ widths[i] = 0.f;
+ }
+ }
+ }
+
+ return (int) totalAdvance;
+ }
+
+ return 0;
}
+ @LayoutlibDelegate
/*package*/ static int native_getTextWidths(int native_object, String text, int start,
int end, float[] widths) {
- // FIXME
- throw new UnsupportedOperationException();
+ return native_getTextWidths(native_object, text.toCharArray(), start, end - start, widths);
}
+ @LayoutlibDelegate
/*package*/ static float native_getTextRunAdvances(int native_object,
char[] text, int index, int count, int contextIndex, int contextCount,
int flags, float[] advances, int advancesIndex) {
@@ -855,6 +983,7 @@
}
+ @LayoutlibDelegate
/*package*/ static float native_getTextRunAdvances(int native_object,
String text, int start, int end, int contextStart, int contextEnd,
int flags, float[] advances, int advancesIndex) {
@@ -867,44 +996,70 @@
contextEnd - contextStart, flags, advances, advancesIndex);
}
+ @LayoutlibDelegate
/*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextRunCursor is not supported.", null, null /*data*/);
+ return 0;
}
+ @LayoutlibDelegate
/*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextRunCursor is not supported.", null, null /*data*/);
+ return 0;
}
+ @LayoutlibDelegate
/*package*/ static void native_getTextPath(int native_object, int bidiFlags,
char[] text, int index, int count, float x, float y, int path) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextPath is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_getTextPath(int native_object, int bidiFlags,
String text, int start, int end, float x, float y, int path) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextPath is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
int end, Rect bounds) {
- // FIXME
- throw new UnsupportedOperationException();
+ nativeGetCharArrayBounds(nativePaint, text.toCharArray(), start, end - start, bounds);
}
+ @LayoutlibDelegate
/*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
int count, Rect bounds) {
- // FIXME
- throw new UnsupportedOperationException();
+
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ // FIXME should test if the main font can display all those characters.
+ // See MeasureText
+ if (delegate.mFonts.size() > 0) {
+ FontInfo mainInfo = delegate.mFonts.get(0);
+
+ Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count,
+ delegate.mFontContext);
+ bounds.set(0, 0, (int) rect.getWidth(), (int) rect.getHeight());
+ }
}
+ @LayoutlibDelegate
/*package*/ static void finalizer(int nativePaint) {
- sManager.removeDelegate(nativePaint);
+ sManager.removeJavaReferenceFor(nativePaint);
}
// ---- Private delegate/helper methods ----
@@ -946,18 +1101,18 @@
mCap = Paint.Cap.BUTT.nativeInt;
mJoin = Paint.Join.MITER.nativeInt;
mTextAlign = 0;
- mTypeface = Typeface.sDefaults[0].native_instance;
+ mTypeface = Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance);
mStrokeWidth = 1.f;
mStrokeMiter = 4.f;
mTextSize = 20.f;
mTextScaleX = 1.f;
mTextSkewX = 0.f;
- mXfermode = 0;
- mColorFilter = 0;
- mShader = 0;
- mPathEffect = 0;
- mMaskFilter = 0;
- mRasterizer = 0;
+ mXfermode = null;
+ mColorFilter = null;
+ mShader = null;
+ mPathEffect = null;
+ mMaskFilter = null;
+ mRasterizer = null;
updateFontObject();
}
@@ -966,9 +1121,9 @@
*/
@SuppressWarnings("deprecation")
private void updateFontObject() {
- if (mTypeface != 0) {
+ if (mTypeface != null) {
// Get the fonts from the TypeFace object.
- List<Font> fonts = Typeface_Delegate.getFonts(mTypeface);
+ List<Font> fonts = mTypeface.getFonts();
// create new font objects as well as FontMetrics, based on the current text size
// and skew info.
@@ -991,6 +1146,10 @@
}
/*package*/ float measureText(char[] text, int index, int count) {
+
+ // WARNING: the logic in this method is similar to Canvas_Delegate.native_drawText
+ // Any change to this method should be reflected there as well
+
if (mFonts.size() > 0) {
FontInfo mainFont = mFonts.get(0);
int i = index;
@@ -1038,6 +1197,8 @@
i += size;
}
}
+
+ return total;
}
return 0;
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
index d12bfea..c448f0e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
@@ -60,10 +61,11 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate(int native_path, float advance, float phase,
int native_style) {
PathDashPathEffect_Delegate newDelegate = new PathDashPathEffect_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
index c588423..bd2b6de 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
@@ -39,7 +40,7 @@
// ---- delegate manager ----
protected static final DelegateManager<PathEffect_Delegate> sManager =
- new DelegateManager<PathEffect_Delegate>();
+ new DelegateManager<PathEffect_Delegate>(PathEffect_Delegate.class);
// ---- delegate helper data ----
@@ -58,8 +59,9 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static void nativeDestructor(int native_patheffect) {
- sManager.removeDelegate(native_patheffect);
+ sManager.removeJavaReferenceFor(native_patheffect);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
index a4e43c1..6c9f48f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -19,6 +19,7 @@
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Path.Direction;
import android.graphics.Path.FillType;
@@ -49,7 +50,7 @@
// ---- delegate manager ----
private static final DelegateManager<Path_Delegate> sManager =
- new DelegateManager<Path_Delegate>();
+ new DelegateManager<Path_Delegate>(Path_Delegate.class);
// ---- delegate data ----
private FillType mFillType = FillType.WINDING;
@@ -84,13 +85,15 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int init1() {
// create the delegate
Path_Delegate newDelegate = new Path_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int init2(int nPath) {
// create the delegate
Path_Delegate newDelegate = new Path_Delegate();
@@ -101,9 +104,10 @@
newDelegate.set(pathDelegate);
}
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static void native_reset(int nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -113,12 +117,14 @@
pathDelegate.mPath.reset();
}
+ @LayoutlibDelegate
/*package*/ static void native_rewind(int nPath) {
// call out to reset since there's nothing to optimize in
// terms of data structs.
native_reset(nPath);
}
+ @LayoutlibDelegate
/*package*/ static void native_set(int native_dst, int native_src) {
Path_Delegate pathDstDelegate = sManager.getDelegate(native_dst);
if (pathDstDelegate == null) {
@@ -133,6 +139,7 @@
pathDstDelegate.set(pathSrcDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int native_getFillType(int nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -142,6 +149,7 @@
return pathDelegate.mFillType.nativeInt;
}
+ @LayoutlibDelegate
/*package*/ static void native_setFillType(int nPath, int ft) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -151,6 +159,7 @@
pathDelegate.mFillType = Path.sFillTypeArray[ft];
}
+ @LayoutlibDelegate
/*package*/ static boolean native_isEmpty(int nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -160,6 +169,7 @@
return pathDelegate.isEmpty();
}
+ @LayoutlibDelegate
/*package*/ static boolean native_isRect(int nPath, RectF rect) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -179,6 +189,7 @@
return false;
}
+ @LayoutlibDelegate
/*package*/ static void native_computeBounds(int nPath, RectF bounds) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -188,11 +199,13 @@
pathDelegate.fillBounds(bounds);
}
+ @LayoutlibDelegate
/*package*/ static void native_incReserve(int nPath, int extraPtCount) {
// since we use a java2D path, there's no way to pre-allocate new points,
// so we do nothing.
}
+ @LayoutlibDelegate
/*package*/ static void native_moveTo(int nPath, float x, float y) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -202,6 +215,7 @@
pathDelegate.moveTo(x, y);
}
+ @LayoutlibDelegate
/*package*/ static void native_rMoveTo(int nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -211,6 +225,7 @@
pathDelegate.rMoveTo(dx, dy);
}
+ @LayoutlibDelegate
/*package*/ static void native_lineTo(int nPath, float x, float y) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -220,6 +235,7 @@
pathDelegate.lineTo(x, y);
}
+ @LayoutlibDelegate
/*package*/ static void native_rLineTo(int nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -229,6 +245,7 @@
pathDelegate.rLineTo(dx, dy);
}
+ @LayoutlibDelegate
/*package*/ static void native_quadTo(int nPath, float x1, float y1, float x2, float y2) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -238,6 +255,7 @@
pathDelegate.quadTo(x1, y1, x2, y2);
}
+ @LayoutlibDelegate
/*package*/ static void native_rQuadTo(int nPath, float dx1, float dy1, float dx2, float dy2) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -247,6 +265,7 @@
pathDelegate.rQuadTo(dx1, dy1, dx2, dy2);
}
+ @LayoutlibDelegate
/*package*/ static void native_cubicTo(int nPath, float x1, float y1,
float x2, float y2, float x3, float y3) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -257,6 +276,7 @@
pathDelegate.cubicTo(x1, y1, x2, y2, x3, y3);
}
+ @LayoutlibDelegate
/*package*/ static void native_rCubicTo(int nPath, float x1, float y1,
float x2, float y2, float x3, float y3) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -267,6 +287,7 @@
pathDelegate.rCubicTo(x1, y1, x2, y2, x3, y3);
}
+ @LayoutlibDelegate
/*package*/ static void native_arcTo(int nPath, RectF oval,
float startAngle, float sweepAngle, boolean forceMoveTo) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -277,6 +298,7 @@
pathDelegate.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
}
+ @LayoutlibDelegate
/*package*/ static void native_close(int nPath) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -286,6 +308,7 @@
pathDelegate.close();
}
+ @LayoutlibDelegate
/*package*/ static void native_addRect(int nPath, RectF rect, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -295,6 +318,7 @@
pathDelegate.addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
}
+ @LayoutlibDelegate
/*package*/ static void native_addRect(int nPath,
float left, float top, float right, float bottom, int dir) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -305,47 +329,63 @@
pathDelegate.addRect(left, top, right, bottom, dir);
}
+ @LayoutlibDelegate
/*package*/ static void native_addOval(int nPath, RectF oval, int dir) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addOval is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_addCircle(int nPath, float x, float y, float radius, int dir) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addCircle is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_addArc(int nPath, RectF oval,
float startAngle, float sweepAngle) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addArc is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_addRoundRect(int nPath, RectF rect,
float rx, float ry, int dir) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addRoundRect is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_addRoundRect(int nPath, RectF r, float[] radii, int dir) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addRoundRect is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_addPath(int nPath, int src, float dx, float dy) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addPath is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_addPath(int nPath, int src) {
native_addPath(nPath, src, 0, 0);
}
+ @LayoutlibDelegate
/*package*/ static void native_addPath(int nPath, int src, int matrix) {
// FIXME
- throw new UnsupportedOperationException();
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addPath is not supported.", null, null /*data*/);
}
+ @LayoutlibDelegate
/*package*/ static void native_offset(int nPath, float dx, float dy, int dst_path) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -358,10 +398,12 @@
pathDelegate.offset(dx, dy, dstDelegate);
}
+ @LayoutlibDelegate
/*package*/ static void native_offset(int nPath, float dx, float dy) {
native_offset(nPath, dx, dy, 0);
}
+ @LayoutlibDelegate
/*package*/ static void native_setLastPoint(int nPath, float dx, float dy) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
if (pathDelegate == null) {
@@ -372,6 +414,7 @@
pathDelegate.mLastY = dy;
}
+ @LayoutlibDelegate
/*package*/ static void native_transform(int nPath, int matrix,
int dst_path) {
Path_Delegate pathDelegate = sManager.getDelegate(nPath);
@@ -390,12 +433,14 @@
pathDelegate.transform(matrixDelegate, dstDelegate);
}
+ @LayoutlibDelegate
/*package*/ static void native_transform(int nPath, int matrix) {
native_transform(nPath, matrix, 0);
}
+ @LayoutlibDelegate
/*package*/ static void finalizer(int nPath) {
- sManager.removeDelegate(nPath);
+ sManager.removeJavaReferenceFor(nPath);
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
index 516a2b9..4ab044b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Composite;
@@ -59,9 +60,10 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate(int opColor) {
PixelXorXfermode_Delegate newDelegate = new PixelXorXfermode_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
index 9038636..c45dbaa 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.PorterDuffColorFilter
@@ -53,11 +54,13 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode) {
PorterDuffColorFilter_Delegate newDelegate = new PorterDuffColorFilter_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int nCreatePorterDuffFilter(int nativeFilter, int srcColor,
int porterDuffMode) {
// pass
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
index 147e1d0..4301c1a 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
@@ -19,6 +19,7 @@
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.AlphaComposite;
import java.awt.Composite;
@@ -125,9 +126,10 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreateXfermode(int mode) {
PorterDuffXfermode_Delegate newDelegate = new PorterDuffXfermode_Delegate(mode);
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
index ffdf5dd..9bf78b4 100644
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -19,6 +19,7 @@
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Shader.TileMode;
@@ -52,25 +53,29 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate1(float x, float y, float radius,
int colors[], float positions[], int tileMode) {
RadialGradient_Delegate newDelegate = new RadialGradient_Delegate(x, y, radius,
colors, positions, Shader_Delegate.getTileMode(tileMode));
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int nativeCreate2(float x, float y, float radius,
int color0, int color1, int tileMode) {
return nativeCreate1(x, y, radius, new int[] { color0, color1 }, null /*positions*/,
tileMode);
}
+ @LayoutlibDelegate
/*package*/ static int nativePostCreate1(int native_shader, float x, float y, float radius,
int colors[], float positions[], int tileMode) {
// nothing to be done here.
return 0;
}
+ @LayoutlibDelegate
/*package*/ static int nativePostCreate2(int native_shader, float x, float y, float radius,
int color0, int color1, int tileMode) {
// nothing to be done here.
diff --git a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
index 9fd67be..2812b6b 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.Rasterizer
@@ -37,7 +38,7 @@
// ---- delegate manager ----
protected static final DelegateManager<Rasterizer_Delegate> sManager =
- new DelegateManager<Rasterizer_Delegate>();
+ new DelegateManager<Rasterizer_Delegate>(Rasterizer_Delegate.class);
// ---- delegate helper data ----
@@ -54,8 +55,9 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static void finalizer(int native_instance) {
- sManager.removeDelegate(native_instance);
+ sManager.removeJavaReferenceFor(native_instance);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
index d2b6b27..cb31b8f 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
@@ -19,6 +19,7 @@
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.os.Parcel;
@@ -47,7 +48,7 @@
// ---- delegate manager ----
protected static final DelegateManager<Region_Delegate> sManager =
- new DelegateManager<Region_Delegate>();
+ new DelegateManager<Region_Delegate>(Region_Delegate.class);
// ---- delegate helper data ----
@@ -136,6 +137,7 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static boolean isEmpty(Region thisRegion) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
@@ -145,6 +147,7 @@
return regionDelegate.mArea.isEmpty();
}
+ @LayoutlibDelegate
/*package*/ static boolean isRect(Region thisRegion) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
@@ -154,6 +157,7 @@
return regionDelegate.mArea.isRectangular();
}
+ @LayoutlibDelegate
/*package*/ static boolean isComplex(Region thisRegion) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
@@ -163,6 +167,7 @@
return regionDelegate.mArea.isSingular() == false;
}
+ @LayoutlibDelegate
/*package*/ static boolean contains(Region thisRegion, int x, int y) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
@@ -172,6 +177,7 @@
return regionDelegate.mArea.contains(x, y);
}
+ @LayoutlibDelegate
/*package*/ static boolean quickContains(Region thisRegion,
int left, int top, int right, int bottom) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
@@ -183,6 +189,7 @@
regionDelegate.mArea.contains(left, top, right - left, bottom - top);
}
+ @LayoutlibDelegate
/*package*/ static boolean quickReject(Region thisRegion,
int left, int top, int right, int bottom) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
@@ -194,6 +201,7 @@
regionDelegate.mArea.intersects(left, top, right - left, bottom - top) == false;
}
+ @LayoutlibDelegate
/*package*/ static boolean quickReject(Region thisRegion, Region rgn) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
@@ -211,6 +219,7 @@
}
+ @LayoutlibDelegate
/*package*/ static void translate(Region thisRegion, int dx, int dy, Region dst) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
@@ -232,6 +241,7 @@
}
}
+ @LayoutlibDelegate
/*package*/ static void scale(Region thisRegion, float scale, Region dst) {
Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
if (regionDelegate == null) {
@@ -253,15 +263,18 @@
}
}
+ @LayoutlibDelegate
/*package*/ static int nativeConstructor() {
Region_Delegate newDelegate = new Region_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static void nativeDestructor(int native_region) {
- sManager.removeDelegate(native_region);
+ sManager.removeJavaReferenceFor(native_region);
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeSetRegion(int native_dst, int native_src) {
Region_Delegate dstRegion = sManager.getDelegate(native_dst);
if (dstRegion == null) {
@@ -279,6 +292,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeSetRect(int native_dst,
int left, int top, int right, int bottom) {
Region_Delegate dstRegion = sManager.getDelegate(native_dst);
@@ -290,6 +304,7 @@
return dstRegion.mArea.getBounds().isEmpty() == false;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeSetPath(int native_dst, int native_path, int native_clip) {
Region_Delegate dstRegion = sManager.getDelegate(native_dst);
if (dstRegion == null) {
@@ -311,6 +326,7 @@
return dstRegion.mArea.getBounds().isEmpty() == false;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeGetBounds(int native_region, Rect rect) {
Region_Delegate region = sManager.getDelegate(native_region);
if (region == null) {
@@ -330,6 +346,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeGetBoundaryPath(int native_region, int native_path) {
Region_Delegate region = sManager.getDelegate(native_region);
if (region == null) {
@@ -350,6 +367,7 @@
return true;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeOp(int native_dst,
int left, int top, int right, int bottom, int op) {
Region_Delegate region = sManager.getDelegate(native_dst);
@@ -368,6 +386,7 @@
return region.mArea.getBounds().isEmpty() == false;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeOp(int native_dst, Rect rect, int native_region, int op) {
Region_Delegate region = sManager.getDelegate(native_dst);
if (region == null) {
@@ -385,6 +404,7 @@
return region.mArea.getBounds().isEmpty() == false;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeOp(int native_dst,
int native_region1, int native_region2, int op) {
Region_Delegate dstRegion = sManager.getDelegate(native_dst);
@@ -413,6 +433,7 @@
}
+ @LayoutlibDelegate
/*package*/ static int nativeCreateFromParcel(Parcel p) {
// This is only called by Region.CREATOR (Parcelable.Creator<Region>), which is only
// used during aidl call so really this should not be called.
@@ -422,6 +443,7 @@
return 0;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeWriteToParcel(int native_region,
Parcel p) {
// This is only called when sending a region through aidl, so really this should not
@@ -432,6 +454,7 @@
return false;
}
+ @LayoutlibDelegate
/*package*/ static boolean nativeEquals(int native_r1, int native_r2) {
Region_Delegate region1 = sManager.getDelegate(native_r1);
if (region1 == null) {
@@ -446,6 +469,7 @@
return region1.mArea.equals(region2.mArea);
}
+ @LayoutlibDelegate
/*package*/ static String nativeToString(int native_region) {
Region_Delegate region = sManager.getDelegate(native_region);
if (region == null) {
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
index 7903ac9..368c0384 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.graphics.Shader.TileMode;
@@ -39,12 +40,12 @@
// ---- delegate manager ----
protected static final DelegateManager<Shader_Delegate> sManager =
- new DelegateManager<Shader_Delegate>();
+ new DelegateManager<Shader_Delegate>(Shader_Delegate.class);
// ---- delegate helper data ----
// ---- delegate data ----
- private int mLocalMatrix = 0;
+ private Matrix_Delegate mLocalMatrix = null;
// ---- Public Helper methods ----
@@ -74,36 +75,12 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static void nativeDestructor(int native_shader, int native_skiaShader) {
- sManager.removeDelegate(native_shader);
+ sManager.removeJavaReferenceFor(native_shader);
}
- /*package*/ static boolean nativeGetLocalMatrix(int native_shader, int matrix_instance) {
- // get the delegate from the native int.
- Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
- if (shaderDelegate == null) {
- return false;
- }
-
- // can be null if shader has no matrix (int is 0)
- Matrix_Delegate localMatrixDelegate = Matrix_Delegate.getDelegate(
- shaderDelegate.mLocalMatrix);
-
- // can be null if the int is 0.
- Matrix_Delegate destMatrixDelegate = Matrix_Delegate.getDelegate(matrix_instance);
- if (destMatrixDelegate != null) {
- if (localMatrixDelegate != null) {
- destMatrixDelegate.set(localMatrixDelegate);
- } else {
- // since there's no local matrix, it's considered to be the identity, reset
- // the destination matrix
- destMatrixDelegate.reset();
- }
- }
-
- return localMatrixDelegate == null || localMatrixDelegate.isIdentity();
- }
-
+ @LayoutlibDelegate
/*package*/ static void nativeSetLocalMatrix(int native_shader, int native_skiaShader,
int matrix_instance) {
// get the delegate from the native int.
@@ -112,15 +89,14 @@
return;
}
- shaderDelegate.mLocalMatrix = matrix_instance;
+ shaderDelegate.mLocalMatrix = Matrix_Delegate.getDelegate(matrix_instance);
}
// ---- Private delegate/helper methods ----
protected java.awt.geom.AffineTransform getLocalMatrix() {
- Matrix_Delegate localMatrixDelegate = Matrix_Delegate.getDelegate(mLocalMatrix);
- if (localMatrixDelegate != null) {
- return localMatrixDelegate.getAffineTransform();
+ if (mLocalMatrix != null) {
+ return mLocalMatrix.getAffineTransform();
}
return new java.awt.geom.AffineTransform();
diff --git a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java
index 0f92ca5..410df0c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Stroke;
@@ -60,9 +61,10 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate(int first, int second) {
SumPathEffect_Delegate newDelegate = new SumPathEffect_Delegate();
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
index 048990a..966e06e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -19,6 +19,7 @@
import com.android.ide.common.rendering.api.LayoutLog;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.graphics.SweepGradient
@@ -50,21 +51,25 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static int nativeCreate1(float x, float y, int colors[], float positions[]) {
SweepGradient_Delegate newDelegate = new SweepGradient_Delegate(x, y, colors, positions);
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static int nativeCreate2(float x, float y, int color0, int color1) {
return nativeCreate1(x, y, new int[] { color0, color1 }, null /*positions*/);
}
+ @LayoutlibDelegate
/*package*/ static int nativePostCreate1(int native_shader, float cx, float cy,
int[] colors, float[] positions) {
// nothing to be done here.
return 0;
}
+ @LayoutlibDelegate
/*package*/ static int nativePostCreate2(int native_shader, float cx, float cy,
int color0, int color1) {
// nothing to be done here.
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
index 00a2a57..0f084f7 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -20,6 +20,7 @@
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.layoutlib.bridge.impl.FontLoader;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import android.content.res.AssetManager;
@@ -45,7 +46,7 @@
// ---- delegate manager ----
private static final DelegateManager<Typeface_Delegate> sManager =
- new DelegateManager<Typeface_Delegate>();
+ new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class);
// ---- delegate helper data ----
private static final String DEFAULT_FAMILY = "sans-serif";
@@ -73,6 +74,10 @@
sPostInitDelegate.clear();
}
+ public static Typeface_Delegate getDelegate(int nativeTypeface) {
+ return sManager.getDelegate(nativeTypeface);
+ }
+
public static List<Font> getFonts(Typeface typeface) {
return getFonts(typeface.native_instance);
}
@@ -83,11 +88,16 @@
return null;
}
- return delegate.mFonts;
+ return delegate.getFonts();
+ }
+
+ public List<Font> getFonts() {
+ return mFonts;
}
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static synchronized int nativeCreate(String familyName, int style) {
if (familyName == null) {
familyName = DEFAULT_FAMILY;
@@ -103,9 +113,10 @@
sPostInitDelegate.add(newDelegate);
}
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static synchronized int nativeCreateFromTypeface(int native_instance, int style) {
Typeface_Delegate delegate = sManager.getDelegate(native_instance);
if (delegate == null) {
@@ -122,25 +133,29 @@
sPostInitDelegate.add(newDelegate);
}
- return sManager.addDelegate(newDelegate);
+ return sManager.addNewDelegate(newDelegate);
}
+ @LayoutlibDelegate
/*package*/ static synchronized int nativeCreateFromAsset(AssetManager mgr, String path) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Typeface.createFromAsset() is not supported.", null /*throwable*/, null /*data*/);
return 0;
}
+ @LayoutlibDelegate
/*package*/ static synchronized int nativeCreateFromFile(String path) {
Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
"Typeface.createFromFile() is not supported.", null /*throwable*/, null /*data*/);
return 0;
}
+ @LayoutlibDelegate
/*package*/ static void nativeUnref(int native_instance) {
- sManager.removeDelegate(native_instance);
+ sManager.removeJavaReferenceFor(native_instance);
}
+ @LayoutlibDelegate
/*package*/ static int nativeGetStyle(int native_instance) {
Typeface_Delegate delegate = sManager.getDelegate(native_instance);
if (delegate == null) {
@@ -150,6 +165,7 @@
return delegate.mStyle;
}
+ @LayoutlibDelegate
/*package*/ static void setGammaForText(float blackGamma, float whiteGamma) {
// This is for device testing only: pass
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
index 312318a..962d69c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
@@ -17,6 +17,7 @@
package android.graphics;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.awt.Composite;
@@ -39,7 +40,7 @@
// ---- delegate manager ----
protected static final DelegateManager<Xfermode_Delegate> sManager =
- new DelegateManager<Xfermode_Delegate>();
+ new DelegateManager<Xfermode_Delegate>(Xfermode_Delegate.class);
// ---- delegate helper data ----
@@ -58,8 +59,9 @@
// ---- native methods ----
+ @LayoutlibDelegate
/*package*/ static void finalizer(int native_instance) {
- sManager.removeDelegate(native_instance);
+ sManager.removeJavaReferenceFor(native_instance);
}
// ---- Private delegate/helper methods ----
diff --git a/tools/layoutlib/bridge/src/android/os/Build_Delegate.java b/tools/layoutlib/bridge/src/android/os/Build_Delegate.java
index f71860f..ff82a5e 100644
--- a/tools/layoutlib/bridge/src/android/os/Build_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/os/Build_Delegate.java
@@ -18,6 +18,7 @@
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.util.Map;
@@ -33,6 +34,7 @@
*/
public class Build_Delegate {
+ @LayoutlibDelegate
/*package*/ static String getString(String property) {
Map<String, String> properties = Bridge.getPlatformProperties();
String value = properties.get(property);
diff --git a/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java b/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java
index 4d4ec7f4..2152c8a 100644
--- a/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java
@@ -16,6 +16,8 @@
package android.os;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
/**
* Delegate overriding selected methods of android.os.Handler
@@ -29,6 +31,7 @@
// -------- Delegate methods
+ @LayoutlibDelegate
/*package*/ static boolean sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
// get the callback
IHandlerCallback callback = sCallbacks.get();
diff --git a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
index be222fc..63711a7 100644
--- a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
@@ -17,6 +17,7 @@
package android.os;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.os.SystemClock
@@ -31,6 +32,7 @@
public class SystemClock_Delegate {
private static long sBootTime = System.currentTimeMillis();
+ @LayoutlibDelegate
/*package*/ static boolean setCurrentTimeMillis(long millis) {
return true;
}
@@ -42,6 +44,7 @@
*
* @return milliseconds of non-sleep uptime since boot.
*/
+ @LayoutlibDelegate
/*package*/ static long uptimeMillis() {
return System.currentTimeMillis() - sBootTime;
}
@@ -51,6 +54,7 @@
*
* @return elapsed milliseconds since boot.
*/
+ @LayoutlibDelegate
/*package*/ static long elapsedRealtime() {
return System.currentTimeMillis() - sBootTime;
}
@@ -60,6 +64,7 @@
*
* @return elapsed milliseconds in the thread
*/
+ @LayoutlibDelegate
/*package*/ static long currentThreadTimeMillis() {
return System.currentTimeMillis();
}
diff --git a/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
index 9ca1338..1df78c2 100644
--- a/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
@@ -17,6 +17,7 @@
package android.util;
import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
/**
* Delegate implementing the native methods of android.util.FloatMath
@@ -40,6 +41,7 @@
* @param value to be converted
* @return the floor of value
*/
+ @LayoutlibDelegate
/*package*/ static float floor(float value) {
return (float)Math.floor(value);
}
@@ -51,6 +53,7 @@
* @param value to be converted
* @return the ceiling of value
*/
+ @LayoutlibDelegate
/*package*/ static float ceil(float value) {
return (float)Math.ceil(value);
}
@@ -61,6 +64,7 @@
* @param angle to compute the cosine of, in radians
* @return the sine of angle
*/
+ @LayoutlibDelegate
/*package*/ static float sin(float angle) {
return (float)Math.sin(angle);
}
@@ -71,6 +75,7 @@
* @param angle to compute the cosine of, in radians
* @return the cosine of angle
*/
+ @LayoutlibDelegate
/*package*/ static float cos(float angle) {
return (float)Math.cos(angle);
}
@@ -82,6 +87,7 @@
* @param value to compute sqrt of
* @return the square root of value
*/
+ @LayoutlibDelegate
/*package*/ static float sqrt(float value) {
return (float)Math.sqrt(value);
}
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
index 3946a2f..0f3cf57 100644
--- a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -17,6 +17,7 @@
package android.view;
import com.android.layoutlib.bridge.android.BridgeInflater;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -38,6 +39,7 @@
* Recursive method used to descend down the xml hierarchy and instantiate
* views, instantiate their children, and then call onFinishInflate().
*/
+ @LayoutlibDelegate
/*package*/ static void rInflate(LayoutInflater thisInflater,
XmlPullParser parser, View parent, final AttributeSet attrs,
boolean finishInflate) throws XmlPullParserException, IOException {
diff --git a/tools/layoutlib/bridge/src/android/view/View_Delegate.java b/tools/layoutlib/bridge/src/android/view/View_Delegate.java
index ee6694c..8215f7c 100644
--- a/tools/layoutlib/bridge/src/android/view/View_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/view/View_Delegate.java
@@ -16,6 +16,8 @@
package android.view;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
/**
* Delegate used to provide new implementation of a select few methods of {@link View}
*
@@ -25,6 +27,7 @@
*/
public class View_Delegate {
+ @LayoutlibDelegate
/*package*/ static boolean isInEditMode(View thisView) {
return true;
}
diff --git a/tools/layoutlib/bridge/src/com/android/internal/util/XmlUtils_Delegate.java b/tools/layoutlib/bridge/src/com/android/internal/util/XmlUtils_Delegate.java
index 7fa1679..bf998b8 100644
--- a/tools/layoutlib/bridge/src/com/android/internal/util/XmlUtils_Delegate.java
+++ b/tools/layoutlib/bridge/src/com/android/internal/util/XmlUtils_Delegate.java
@@ -16,6 +16,8 @@
package com.android.internal.util;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
/**
* Delegate used to provide new implementation of a select few methods of {@link XmlUtils}
@@ -25,6 +27,8 @@
*
*/
public class XmlUtils_Delegate {
+
+ @LayoutlibDelegate
/*package*/ static final int convertValueToInt(CharSequence charSeq, int defaultValue) {
if (null == charSeq)
return defaultValue;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 90dcc27..acc7379 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -192,6 +192,7 @@
Capability.UNBOUND_RENDERING,
Capability.CUSTOM_BACKGROUND_COLOR,
Capability.RENDER,
+ Capability.LAYOUT_ONLY,
Capability.EMBEDDED_LAYOUT,
Capability.VIEW_MANIPULATION,
Capability.PLAY_ANIMATION,
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 33dd214..7d794bd 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -425,36 +425,72 @@
}
}
- if (defStyleValues == null && defStyleAttr != 0) {
- // get the name from the int.
- String defStyleName = searchAttr(defStyleAttr);
+ if (defStyleValues == null) {
+ if (defStyleAttr != 0) {
+ // get the name from the int.
+ String defStyleName = searchAttr(defStyleAttr);
- if (defaultPropMap != null) {
- defaultPropMap.put("style", defStyleName);
- }
-
- // look for the style in the current theme, and its parent:
- ResourceValue item = mRenderResources.findItemInTheme(defStyleName);
-
- if (item != null) {
- // item is a reference to a style entry. Search for it.
- item = mRenderResources.findResValue(item.getValue(),
- false /*forceFrameworkOnly*/);
-
- if (item instanceof StyleResourceValue) {
- defStyleValues = (StyleResourceValue)item;
+ if (defaultPropMap != null) {
+ defaultPropMap.put("style", defStyleName);
}
- } else {
- Bridge.getLog().error(null,
- String.format(
- "Failed to find style '%s' in current theme", defStyleName),
- null /*data*/);
- }
- }
- if (defStyleRes != 0) {
- // FIXME: See what we need to do with this.
- throw new UnsupportedOperationException();
+ // look for the style in the current theme, and its parent:
+ ResourceValue item = mRenderResources.findItemInTheme(defStyleName);
+
+ if (item != null) {
+ // item is a reference to a style entry. Search for it.
+ item = mRenderResources.findResValue(item.getValue(),
+ false /*forceFrameworkOnly*/);
+
+ if (item instanceof StyleResourceValue) {
+ defStyleValues = (StyleResourceValue)item;
+ }
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Failed to find style '%s' in current theme", defStyleName),
+ null /*data*/);
+ }
+ } else if (defStyleRes != 0) {
+ Pair<ResourceType, String> value = Bridge.resolveResourceId(defStyleRes);
+ if (value == null) {
+ value = mProjectCallback.resolveResourceId(defStyleRes);
+ }
+
+ if (value != null) {
+ if (value.getFirst() == ResourceType.STYLE) {
+ // look for the style in the current theme, and its parent:
+ ResourceValue item = mRenderResources.findItemInTheme(value.getSecond());
+ if (item != null) {
+ if (item instanceof StyleResourceValue) {
+ if (defaultPropMap != null) {
+ defaultPropMap.put("style", item.getName());
+ }
+
+ defStyleValues = (StyleResourceValue)item;
+ }
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Style with id 0x%x (resolved to '%s') does not exist.",
+ defStyleRes, value.getSecond()),
+ null /*data*/);
+ }
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Resouce id 0x%x is not of type STYLE (instead %s)",
+ defStyleRes, value.getFirst().toString()),
+ null /*data*/);
+ }
+ } else {
+ Bridge.getLog().error(null,
+ String.format(
+ "Failed to find style with id 0x%x in current theme",
+ defStyleRes),
+ null /*data*/);
+ }
+ }
}
String namespace = BridgeConstants.NS_RESOURCES;
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
index 734f5ad..c1d7600 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeTypedArray.java
@@ -188,6 +188,10 @@
String s = mResourceData[index].getValue();
+ if (RenderResources.REFERENCE_NULL.equals(s)) {
+ return defValue;
+ }
+
try {
return (s == null) ? defValue : XmlUtils.convertValueToInt(s, defValue);
} catch (NumberFormatException e) {
@@ -301,6 +305,10 @@
return null;
}
+ if (RenderResources.REFERENCE_NULL.equals(value)) {
+ return null;
+ }
+
// let the framework inflate the ColorStateList from the XML file.
File f = new File(value);
if (f.isFile()) {
@@ -337,8 +345,6 @@
Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT, e.getMessage(), e, null /*data*/);
}
- assert false;
-
return null;
}
@@ -408,6 +414,10 @@
return LayoutParams.WRAP_CONTENT;
}
+ if (RenderResources.REFERENCE_NULL.equals(s)) {
+ return defValue;
+ }
+
if (ResourceHelper.stringToFloat(s, mValue)) {
return mValue.getDimension(mBridgeResources.mMetrics);
}
@@ -418,8 +428,6 @@
"\"%1$s\" in attribute \"%2$s\" is not a valid format.",
s, mNames[index]), null /*data*/);
- assert false;
-
return defValue;
}
@@ -480,6 +488,10 @@
return LayoutParams.WRAP_CONTENT;
}
+ if (RenderResources.REFERENCE_NULL.equals(s)) {
+ return defValue;
+ }
+
// FIXME huh?
float f = getDimension(index, defValue);
@@ -488,8 +500,11 @@
if (f == 0) return 0;
if (f > 0) return 1;
- throw new UnsupportedOperationException("Can't convert to dimension: " +
- Integer.toString(index));
+ Bridge.getLog().error(LayoutLog.TAG_RESOURCES_FORMAT,
+ "Can't convert to dimension: " + Integer.toString(index),
+ null, null /*data*/);
+
+ return defValue;
}
/**
@@ -550,8 +565,6 @@
"\"%1$s\" in attribute \"%2$s\" cannont be converted to a fraction.",
value, mNames[index]), null /*data*/);
- assert false;
-
return defValue;
}
@@ -585,6 +598,10 @@
return mContext.getDynamicIdByStyle((StyleResourceValue)resValue);
}
+ if (RenderResources.REFERENCE_NULL.equals(resValue.getValue())) {
+ return defValue;
+ }
+
// if the attribute was a reference to a resource, and not a declaration of an id (@+id),
// then the xml attribute value was "resolved" which leads us to a ResourceValue with a
// valid getType() and getName() returning a resource name.
@@ -663,8 +680,6 @@
"Unable to resolve id \"%1$s\" for attribute \"%2$s\"", value, mNames[index]),
resValue);
- assert false;
-
return defValue;
}
@@ -712,6 +727,10 @@
String value = mResourceData[index].getValue();
if (value != null) {
+ if (RenderResources.REFERENCE_NULL.equals(value)) {
+ return null;
+ }
+
return new CharSequence[] { value };
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
index 04d06e4..9fab51a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/PhoneSystemBar.java
@@ -30,7 +30,7 @@
public class PhoneSystemBar extends CustomBar {
public PhoneSystemBar(Context context, Density density) throws XmlPullParserException {
- super(context, density, "/bars/tablet_system_bar.xml");
+ super(context, density, "/bars/phone_system_bar.xml");
setGravity(mGravity | Gravity.RIGHT);
setBackgroundColor(0xFF000000);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
index 05a258d..ae1217d 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/DelegateManager.java
@@ -16,8 +16,15 @@
package com.android.layoutlib.bridge.impl;
+import com.android.layoutlib.bridge.util.Debug;
+import com.android.layoutlib.bridge.util.SparseWeakArray;
+
import android.util.SparseArray;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.List;
+
/**
* Manages native delegates.
*
@@ -44,15 +51,39 @@
* will do is call {@link #getDelegate(int)} to get the Java object matching the int.
*
* Typical native init methods are returning a new int back to the Java class, so
- * {@link #addDelegate(Object)} does the same.
+ * {@link #addNewDelegate(Object)} does the same.
+ *
+ * The JNI references are counted, so we do the same through a {@link WeakReference}. Because
+ * the Java object needs to count as a reference (even though it only holds an int), we use the
+ * following mechanism:
+ *
+ * - {@link #addNewDelegate(Object)} and {@link #removeJavaReferenceFor(int)} adds and removes
+ * the delegate to/from a list. This list hold the reference and prevents the GC from reclaiming
+ * the delegate.
+ *
+ * - {@link #addNewDelegate(Object)} also adds the delegate to a {@link SparseArray} that holds a
+ * {@link WeakReference} to the delegate. This allows the delegate to be deleted automatically
+ * when nothing references it. This means that any class that holds a delegate (except for the
+ * Java main class) must not use the int but the Delegate class instead. The integers must
+ * only be used in the API between the main Java class and the Delegate.
*
* @param <T> the delegate class to manage
*/
public final class DelegateManager<T> {
-
- private final SparseArray<T> mDelegates = new SparseArray<T>();
+ private final Class<T> mClass;
+ private final SparseWeakArray<T> mDelegates = new SparseWeakArray<T>();
+ /** list used to store delegates when their main object holds a reference to them.
+ * This is to ensure that the WeakReference in the SparseWeakArray doesn't get GC'ed
+ * @see #addNewDelegate(Object)
+ * @see #removeJavaReferenceFor(int)
+ */
+ private final List<T> mJavaReferences = new ArrayList<T>();
private int mDelegateCounter = 0;
+ public DelegateManager(Class<T> theClass) {
+ mClass = theClass;
+ }
+
/**
* Returns the delegate from the given native int.
* <p>
@@ -66,6 +97,14 @@
public T getDelegate(int native_object) {
if (native_object > 0) {
T delegate = mDelegates.get(native_object);
+
+ if (Debug.DEBUG) {
+ if (delegate == null) {
+ System.out.println("Unknown " + mClass.getSimpleName() + " with int " +
+ native_object);
+ }
+ }
+
assert delegate != null;
return delegate;
}
@@ -77,17 +116,31 @@
* @param newDelegate the delegate to add
* @return a unique native int to identify the delegate
*/
- public int addDelegate(T newDelegate) {
+ public int addNewDelegate(T newDelegate) {
int native_object = ++mDelegateCounter;
mDelegates.put(native_object, newDelegate);
+ assert !mJavaReferences.contains(newDelegate);
+ mJavaReferences.add(newDelegate);
+
+ if (Debug.DEBUG) {
+ System.out.println("New " + mClass.getSimpleName() + " with int " + native_object);
+ }
+
return native_object;
}
/**
- * Removes the delegate matching the given native int.
- * @param native_object the native int.
+ * Removes the main reference on the given delegate.
+ * @param native_object the native integer representing the delegate.
*/
- public void removeDelegate(int native_object) {
- mDelegates.remove(native_object);
+ public void removeJavaReferenceFor(int native_object) {
+ T delegate = getDelegate(native_object);
+
+ if (Debug.DEBUG) {
+ System.out.println("Removing main Java ref on " + mClass.getSimpleName() +
+ " with int " + native_object);
+ }
+
+ mJavaReferences.remove(delegate);
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index fedd789..2fd58e4 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -421,57 +421,63 @@
// now do the layout.
mViewRoot.layout(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
- mViewRoot.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
+ if (params.isLayoutOnly()) {
+ // delete the canvas and image to reset them on the next full rendering
+ mImage = null;
+ mCanvas = null;
+ } else {
+ mViewRoot.mAttachInfo.mTreeObserver.dispatchOnPreDraw();
- // draw the views
- // create the BufferedImage into which the layout will be rendered.
- boolean newImage = false;
- if (newRenderSize || mCanvas == null) {
- if (params.getImageFactory() != null) {
- mImage = params.getImageFactory().getImage(
- mMeasuredScreenWidth,
- mMeasuredScreenHeight);
- } else {
- mImage = new BufferedImage(
- mMeasuredScreenWidth,
- mMeasuredScreenHeight,
- BufferedImage.TYPE_INT_ARGB);
- newImage = true;
+ // draw the views
+ // create the BufferedImage into which the layout will be rendered.
+ boolean newImage = false;
+ if (newRenderSize || mCanvas == null) {
+ if (params.getImageFactory() != null) {
+ mImage = params.getImageFactory().getImage(
+ mMeasuredScreenWidth,
+ mMeasuredScreenHeight);
+ } else {
+ mImage = new BufferedImage(
+ mMeasuredScreenWidth,
+ mMeasuredScreenHeight,
+ BufferedImage.TYPE_INT_ARGB);
+ newImage = true;
+ }
+
+ if (params.isBgColorOverridden()) {
+ // since we override the content, it's the same as if it was a new image.
+ newImage = true;
+ Graphics2D gc = mImage.createGraphics();
+ gc.setColor(new Color(params.getOverrideBgColor(), true));
+ gc.setComposite(AlphaComposite.Src);
+ gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
+ gc.dispose();
+ }
+
+ // create an Android bitmap around the BufferedImage
+ Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
+ true /*isMutable*/, params.getDensity());
+
+ // create a Canvas around the Android bitmap
+ mCanvas = new Canvas(bitmap);
+ mCanvas.setDensity(params.getDensity().getDpiValue());
}
- if (params.isBgColorOverridden()) {
- // since we override the content, it's the same as if it was a new image.
- newImage = true;
+ if (freshRender && newImage == false) {
Graphics2D gc = mImage.createGraphics();
- gc.setColor(new Color(params.getOverrideBgColor(), true));
gc.setComposite(AlphaComposite.Src);
- gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
+
+ gc.setColor(new Color(0x00000000, true));
+ gc.fillRect(0, 0,
+ mMeasuredScreenWidth, mMeasuredScreenHeight);
+
+ // done
gc.dispose();
}
- // create an Android bitmap around the BufferedImage
- Bitmap bitmap = Bitmap_Delegate.createBitmap(mImage,
- true /*isMutable*/, params.getDensity());
-
- // create a Canvas around the Android bitmap
- mCanvas = new Canvas(bitmap);
- mCanvas.setDensity(params.getDensity().getDpiValue());
+ mViewRoot.draw(mCanvas);
}
- if (freshRender && newImage == false) {
- Graphics2D gc = mImage.createGraphics();
- gc.setComposite(AlphaComposite.Src);
-
- gc.setColor(new Color(0x00000000, true));
- gc.fillRect(0, 0,
- mMeasuredScreenWidth, mMeasuredScreenHeight);
-
- // done
- gc.dispose();
- }
-
- mViewRoot.draw(mCanvas);
-
mViewInfoList = startVisitingViews(mViewRoot, 0);
// success!
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/Debug.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/Debug.java
new file mode 100644
index 0000000..82eab85
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/Debug.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.util;
+
+public class Debug {
+
+ public final static boolean DEBUG = false;
+
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
new file mode 100644
index 0000000..4d0c9ce
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/util/SparseWeakArray.java
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.util;
+
+
+import com.android.internal.util.ArrayUtils;
+
+import android.util.SparseArray;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * This is a custom {@link SparseArray} that uses {@link WeakReference} around the objects added
+ * to it. When the array is compacted, not only deleted indices but also empty references
+ * are removed, making the array efficient at removing references that were reclaimed.
+ *
+ * The code is taken from {@link SparseArray} directly and adapted to use weak references.
+ *
+ * Because our usage means that we never actually call {@link #remove(int)} or {@link #delete(int)},
+ * we must manually check if there are reclaimed references to trigger an internal compact step
+ * (which is normally only triggered when an item is manually removed).
+ *
+ * SparseArrays map integers to Objects. Unlike a normal array of Objects,
+ * there can be gaps in the indices. It is intended to be more efficient
+ * than using a HashMap to map Integers to Objects.
+ */
+@SuppressWarnings("unchecked")
+public class SparseWeakArray<E> {
+
+ private static final Object DELETED_REF = new Object();
+ private static final WeakReference<?> DELETED = new WeakReference(DELETED_REF);
+ private boolean mGarbage = false;
+
+ /**
+ * Creates a new SparseArray containing no mappings.
+ */
+ public SparseWeakArray() {
+ this(10);
+ }
+
+ /**
+ * Creates a new SparseArray containing no mappings that will not
+ * require any additional memory allocation to store the specified
+ * number of mappings.
+ */
+ public SparseWeakArray(int initialCapacity) {
+ initialCapacity = ArrayUtils.idealIntArraySize(initialCapacity);
+
+ mKeys = new int[initialCapacity];
+ mValues = new WeakReference[initialCapacity];
+ mSize = 0;
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or <code>null</code>
+ * if no such mapping has been made.
+ */
+ public E get(int key) {
+ return get(key, null);
+ }
+
+ /**
+ * Gets the Object mapped from the specified key, or the specified Object
+ * if no such mapping has been made.
+ */
+ public E get(int key, E valueIfKeyNotFound) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i < 0 || mValues[i] == DELETED || mValues[i].get() == null) {
+ return valueIfKeyNotFound;
+ } else {
+ return (E) mValues[i].get();
+ }
+ }
+
+ /**
+ * Removes the mapping from the specified key, if there was any.
+ */
+ public void delete(int key) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ if (mValues[i] != DELETED) {
+ mValues[i] = DELETED;
+ mGarbage = true;
+ }
+ }
+ }
+
+ /**
+ * Alias for {@link #delete(int)}.
+ */
+ public void remove(int key) {
+ delete(key);
+ }
+
+ /**
+ * Removes the mapping at the specified index.
+ */
+ public void removeAt(int index) {
+ if (mValues[index] != DELETED) {
+ mValues[index] = DELETED;
+ mGarbage = true;
+ }
+ }
+
+ private void gc() {
+ int n = mSize;
+ int o = 0;
+ int[] keys = mKeys;
+ WeakReference<?>[] values = mValues;
+
+ for (int i = 0; i < n; i++) {
+ WeakReference<?> val = values[i];
+
+ // Don't keep any non DELETED values, but only the one that still have a valid
+ // reference.
+ if (val != DELETED && val.get() != null) {
+ if (i != o) {
+ keys[o] = keys[i];
+ values[o] = val;
+ }
+
+ o++;
+ }
+ }
+
+ mGarbage = false;
+ mSize = o;
+
+ int newSize = ArrayUtils.idealIntArraySize(mSize);
+ if (newSize < mKeys.length) {
+ int[] nkeys = new int[newSize];
+ WeakReference<?>[] nvalues = new WeakReference[newSize];
+
+ System.arraycopy(mKeys, 0, nkeys, 0, newSize);
+ System.arraycopy(mValues, 0, nvalues, 0, newSize);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+ }
+
+ /**
+ * Adds a mapping from the specified key to the specified value,
+ * replacing the previous mapping from the specified key if there
+ * was one.
+ */
+ public void put(int key, E value) {
+ int i = binarySearch(mKeys, 0, mSize, key);
+
+ if (i >= 0) {
+ mValues[i] = new WeakReference(value);
+ } else {
+ i = ~i;
+
+ if (i < mSize && (mValues[i] == DELETED || mValues[i].get() == null)) {
+ mKeys[i] = key;
+ mValues[i] = new WeakReference(value);
+ return;
+ }
+
+ if (mSize >= mKeys.length && (mGarbage || hasReclaimedRefs())) {
+ gc();
+
+ // Search again because indices may have changed.
+ i = ~binarySearch(mKeys, 0, mSize, key);
+ }
+
+ if (mSize >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(mSize + 1);
+
+ int[] nkeys = new int[n];
+ WeakReference<?>[] nvalues = new WeakReference[n];
+
+ // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ if (mSize - i != 0) {
+ // Log.e("SparseArray", "move " + (mSize - i));
+ System.arraycopy(mKeys, i, mKeys, i + 1, mSize - i);
+ System.arraycopy(mValues, i, mValues, i + 1, mSize - i);
+ }
+
+ mKeys[i] = key;
+ mValues[i] = new WeakReference(value);
+ mSize++;
+ }
+ }
+
+ /**
+ * Returns the number of key-value mappings that this SparseArray
+ * currently stores.
+ */
+ public int size() {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mSize;
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the key from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public int keyAt(int index) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return mKeys[index];
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, returns
+ * the value from the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public E valueAt(int index) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return (E) mValues[index].get();
+ }
+
+ /**
+ * Given an index in the range <code>0...size()-1</code>, sets a new
+ * value for the <code>index</code>th key-value mapping that this
+ * SparseArray stores.
+ */
+ public void setValueAt(int index, E value) {
+ if (mGarbage) {
+ gc();
+ }
+
+ mValues[index] = new WeakReference(value);
+ }
+
+ /**
+ * Returns the index for which {@link #keyAt} would return the
+ * specified key, or a negative number if the specified
+ * key is not mapped.
+ */
+ public int indexOfKey(int key) {
+ if (mGarbage) {
+ gc();
+ }
+
+ return binarySearch(mKeys, 0, mSize, key);
+ }
+
+ /**
+ * Returns an index for which {@link #valueAt} would return the
+ * specified key, or a negative number if no keys map to the
+ * specified value.
+ * Beware that this is a linear search, unlike lookups by key,
+ * and that multiple keys can map to the same value and this will
+ * find only one of them.
+ */
+ public int indexOfValue(E value) {
+ if (mGarbage) {
+ gc();
+ }
+
+ for (int i = 0; i < mSize; i++)
+ if (mValues[i].get() == value)
+ return i;
+
+ return -1;
+ }
+
+ /**
+ * Removes all key-value mappings from this SparseArray.
+ */
+ public void clear() {
+ int n = mSize;
+ WeakReference<?>[] values = mValues;
+
+ for (int i = 0; i < n; i++) {
+ values[i] = null;
+ }
+
+ mSize = 0;
+ mGarbage = false;
+ }
+
+ /**
+ * Puts a key/value pair into the array, optimizing for the case where
+ * the key is greater than all existing keys in the array.
+ */
+ public void append(int key, E value) {
+ if (mSize != 0 && key <= mKeys[mSize - 1]) {
+ put(key, value);
+ return;
+ }
+
+ if (mSize >= mKeys.length && (mGarbage || hasReclaimedRefs())) {
+ gc();
+ }
+
+ int pos = mSize;
+ if (pos >= mKeys.length) {
+ int n = ArrayUtils.idealIntArraySize(pos + 1);
+
+ int[] nkeys = new int[n];
+ WeakReference<?>[] nvalues = new WeakReference[n];
+
+ // Log.e("SparseArray", "grow " + mKeys.length + " to " + n);
+ System.arraycopy(mKeys, 0, nkeys, 0, mKeys.length);
+ System.arraycopy(mValues, 0, nvalues, 0, mValues.length);
+
+ mKeys = nkeys;
+ mValues = nvalues;
+ }
+
+ mKeys[pos] = key;
+ mValues[pos] = new WeakReference(value);
+ mSize = pos + 1;
+ }
+
+ private boolean hasReclaimedRefs() {
+ for (int i = 0 ; i < mSize ; i++) {
+ if (mValues[i].get() == null) { // DELETED.get() never returns null.
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ private static int binarySearch(int[] a, int start, int len, int key) {
+ int high = start + len, low = start - 1, guess;
+
+ while (high - low > 1) {
+ guess = (high + low) / 2;
+
+ if (a[guess] < key)
+ low = guess;
+ else
+ high = guess;
+ }
+
+ if (high == start + len)
+ return ~(start + len);
+ else if (a[high] == key)
+ return high;
+ else
+ return ~high;
+ }
+
+ private int[] mKeys;
+ private WeakReference<?>[] mValues;
+ private int mSize;
+}
diff --git a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
index ab01a394..e6dc646 100644
--- a/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
+++ b/tools/layoutlib/bridge/src/libcore/icu/ICU_Delegate.java
@@ -16,6 +16,8 @@
package libcore.icu;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
import java.util.Locale;
/**
@@ -27,80 +29,101 @@
*/
public class ICU_Delegate {
+ // --- Java delegates
+
+ @LayoutlibDelegate
/*package*/ static String toLowerCase(String s, String localeName) {
return s.toLowerCase();
}
+ @LayoutlibDelegate
/*package*/ static String toUpperCase(String s, String localeName) {
return s.toUpperCase();
}
// --- Native methods accessing ICU's database.
+ @LayoutlibDelegate
/*package*/ static String[] getAvailableBreakIteratorLocalesNative() {
return new String[0];
}
+ @LayoutlibDelegate
/*package*/ static String[] getAvailableCalendarLocalesNative() {
return new String[0];
}
+ @LayoutlibDelegate
/*package*/ static String[] getAvailableCollatorLocalesNative() {
return new String[0];
}
+ @LayoutlibDelegate
/*package*/ static String[] getAvailableDateFormatLocalesNative() {
return new String[0];
}
+ @LayoutlibDelegate
/*package*/ static String[] getAvailableLocalesNative() {
return new String[0];
}
+ @LayoutlibDelegate
/*package*/ static String[] getAvailableNumberFormatLocalesNative() {
return new String[0];
}
+ @LayoutlibDelegate
/*package*/ static String getCurrencyCodeNative(String locale) {
return "";
}
+ @LayoutlibDelegate
/*package*/ static int getCurrencyFractionDigitsNative(String currencyCode) {
return 0;
}
+ @LayoutlibDelegate
/*package*/ static String getCurrencySymbolNative(String locale, String currencyCode) {
return "";
}
+ @LayoutlibDelegate
/*package*/ static String getDisplayCountryNative(String countryCode, String locale) {
return "";
}
+ @LayoutlibDelegate
/*package*/ static String getDisplayLanguageNative(String languageCode, String locale) {
return "";
}
+ @LayoutlibDelegate
/*package*/ static String getDisplayVariantNative(String variantCode, String locale) {
return "";
}
+ @LayoutlibDelegate
/*package*/ static String getISO3CountryNative(String locale) {
return "";
}
+ @LayoutlibDelegate
/*package*/ static String getISO3LanguageNative(String locale) {
return "";
}
+ @LayoutlibDelegate
/*package*/ static String[] getISOLanguagesNative() {
return Locale.getISOLanguages();
}
+ @LayoutlibDelegate
/*package*/ static String[] getISOCountriesNative() {
return Locale.getISOCountries();
}
+ @LayoutlibDelegate
/*package*/ static boolean initLocaleDataImpl(String locale, LocaleData result) {
// Used by Calendar.
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java
deleted file mode 100644
index a068ae2..0000000
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestClassReplacement.java
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- * Copyright (C) 2009 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.Type;
-
-import junit.framework.TestCase;
-
-public class TestClassReplacement extends TestCase {
-
- public void testClassReplacements() {
- // TODO: we want to test all the classes. For now only, no classes pass the test.
-// final String[] classes = CreateInfo.RENAMED_CLASSES;
- final String[] classes = new String[] {
-// "android.graphics.Paint", "android.graphics._Original_Paint",
-// "android.graphics.Canvas", "android.graphics._Original_Canvas",
- };
- final int count = classes.length;
- for (int i = 0 ; i < count ; i += 2) {
- loadAndCompareClasses(classes[i], classes[i+1]);
- }
- }
-
- private void loadAndCompareClasses(String newClassName, String oldClassName) {
- // load the classes
- try {
- Class<?> newClass = TestClassReplacement.class.getClassLoader().loadClass(newClassName);
- Class<?> oldClass = TestClassReplacement.class.getClassLoader().loadClass(oldClassName);
-
- compare(newClass, oldClass);
- } catch (ClassNotFoundException e) {
- fail("Failed to load class: " + e.getMessage());
- }
- }
-
- private void compare(Class<?> newClass, Class<?> oldClass) {
- // first compare the methods.
- Method[] newClassMethods = newClass.getDeclaredMethods();
- Method[] oldClassMethods = oldClass.getDeclaredMethods();
-
- for (Method oldMethod : oldClassMethods) {
- // we ignore anything that starts with native. This is because the class we are looking
- // at has already been modified to remove the native modifiers.
- if (oldMethod.getName().startsWith("native")) {
- continue;
- }
-
- // or static and private
- int privateStatic = Modifier.STATIC | Modifier.PRIVATE;
- if ((oldMethod.getModifiers() & privateStatic) == privateStatic) {
- continue;
- }
-
- boolean found = false;
- for (Method newMethod : newClassMethods) {
-
- if (compareMethods(newClass, newMethod, oldClass, oldMethod)) {
- found = true;
- break;
- }
- }
-
- if (found == false) {
- // compute a full class name that's long but not too long.
- StringBuilder sb = new StringBuilder(oldMethod.getName() + "(");
- Type[] params = oldMethod.getGenericParameterTypes();
- for (int j = 0; j < params.length; j++) {
- if (params[j] instanceof Class) {
- Class theClass = (Class)params[j];
- sb.append(theClass.getName());
- int dimensions = 0;
- while (theClass.isArray()) {
- dimensions++;
- theClass = theClass.getComponentType();
- }
- for (int i = 0; i < dimensions; i++) {
- sb.append("[]");
- }
-
- } else {
- sb.append(params[j].toString());
- }
- if (j < (params.length - 1))
- sb.append(",");
- }
- sb.append(")");
-
- fail(String.format("Missing %1$s.%2$s", newClass.getName(), sb.toString()));
- }
- }
-
- // TODO: check (somehow?) that the methods that were removed from the original class
- // have been put back in the new class!
- // For this we need the original unmodified class (ie renamed, but w/o the methods removed)
- }
-
- private boolean compareMethods(Class<?> newClass, Method newMethod,
- Class<?> oldClass, Method oldMethod) {
- // first check the name of the method
- if (newMethod.getName().equals(oldMethod.getName()) == false) {
- return false;
- }
-
- // check the return value
- Class<?> oldReturnType = oldMethod.getReturnType();
- // if it's the old class, or if it's a inner class of the oldclass, we need to change this.
- oldReturnType = adapt(oldReturnType, newClass, oldClass);
-
- // compare the return types
- Class<?> newReturnType = newMethod.getReturnType();
- if (newReturnType.equals(oldReturnType) == false) {
- return false;
- }
-
- // now check the parameters type.
- Class<?>[] oldParameters = oldMethod.getParameterTypes();
- Class<?>[] newParemeters = newMethod.getParameterTypes();
- if (oldParameters.length != newParemeters.length) {
- return false;
- }
-
- for (int i = 0 ; i < oldParameters.length ; i++) {
- if (newParemeters[i].equals(adapt(oldParameters[i], newClass, oldClass)) == false) {
- return false;
- }
- }
-
- return true;
- }
-
- /**
- * Adapts a class to deal with renamed classes.
- * <p/>For instance if old class is <code>android.graphics._Original_Paint</code> and the
- * new class is <code>android.graphics.Paint</code> and the class to adapt is
- * <code>android.graphics._Original_Paint$Cap</code>, then the method will return a
- * {@link Class} object representing <code>android.graphics.Paint$Cap</code>.
- * <p/>
- * This method will also ensure that all renamed classes contains all the proper inner classes
- * that they should be declaring.
- * @param theClass the class to adapt
- * @param newClass the new class object
- * @param oldClass the old class object
- * @return the adapted class.
- * @throws ClassNotFoundException
- */
- private Class<?> adapt(Class<?> theClass, Class<?> newClass, Class<?> oldClass) {
- // only look for a new class if it's not primitive as Class.forName() would fail otherwise.
- if (theClass.isPrimitive() == false) {
- String n = theClass.getName().replace(oldClass.getName(), newClass.getName());
- try {
- return Class.forName(n);
- } catch (ClassNotFoundException e) {
- fail("Missing class: " + n);
- }
- }
-
- return theClass;
- }
-}
diff --git a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestDelegates.java b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestDelegates.java
index a4140e3..d3218db 100644
--- a/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestDelegates.java
+++ b/tools/layoutlib/bridge/tests/com/android/layoutlib/bridge/TestDelegates.java
@@ -21,6 +21,8 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.List;
import junit.framework.TestCase;
@@ -78,10 +80,15 @@
}
private void compare(Class<?> originalClass, Class<?> delegateClass) throws SecurityException {
- Method[] originalMethods = originalClass.getDeclaredMethods();
+ List<Method> checkedDelegateMethods = new ArrayList<Method>();
+ // loop on the methods of the original class, and for the ones that are annotated
+ // with @LayoutlibDelegate, look for a matching method in the delegate class.
+ // The annotation is automatically added by layoutlib_create when it replace a method
+ // by a call to a delegate
+ Method[] originalMethods = originalClass.getDeclaredMethods();
for (Method originalMethod : originalMethods) {
- // look for methods that were native: they have the LayoutlibDelegate annotation
+ // look for methods that are delegated: they have the LayoutlibDelegate annotation
if (originalMethod.getAnnotation(LayoutlibDelegate.class) == null) {
continue;
}
@@ -114,6 +121,14 @@
Method delegateMethod = delegateClass.getDeclaredMethod(originalMethod.getName(),
parameters);
+ // check that the method has the annotation
+ assertNotNull(
+ String.format(
+ "Delegate method %1$s for class %2$s does not have the @LayoutlibDelegate annotation",
+ delegateMethod.getName(),
+ originalClass.getName()),
+ delegateMethod.getAnnotation(LayoutlibDelegate.class));
+
// check that the method is static
assertTrue(
String.format(
@@ -121,28 +136,62 @@
delegateMethod.getName(),
originalClass.getName()),
(delegateMethod.getModifiers() & Modifier.STATIC) == Modifier.STATIC);
- } catch (NoSuchMethodException e) {
- // compute a full class name that's long but not too long.
- StringBuilder sb = new StringBuilder(originalMethod.getName() + "(");
- for (int j = 0; j < parameters.length; j++) {
- Class<?> theClass = parameters[j];
- sb.append(theClass.getName());
- int dimensions = 0;
- while (theClass.isArray()) {
- dimensions++;
- theClass = theClass.getComponentType();
- }
- for (int i = 0; i < dimensions; i++) {
- sb.append("[]");
- }
- if (j < (parameters.length - 1)) {
- sb.append(",");
- }
- }
- sb.append(")");
- fail(String.format("Missing %1$s.%2$s", delegateClass.getName(), sb.toString()));
+ // add the method as checked.
+ checkedDelegateMethods.add(delegateMethod);
+ } catch (NoSuchMethodException e) {
+ String name = getMethodName(originalMethod, parameters);
+ fail(String.format("Missing %1$s.%2$s", delegateClass.getName(), name));
}
}
+
+ // look for dead (delegate) code.
+ // This looks for all methods in the delegate class, and if they have the
+ // @LayoutlibDelegate annotation, make sure they have been previously found as a
+ // match for a method in the original class.
+ // If not, this means the method is a delegate for a method that either doesn't exist
+ // anymore or is not delegated anymore.
+ Method[] delegateMethods = delegateClass.getDeclaredMethods();
+ for (Method delegateMethod : delegateMethods) {
+ // look for methods that are delegates: they have the LayoutlibDelegate annotation
+ if (delegateMethod.getAnnotation(LayoutlibDelegate.class) == null) {
+ continue;
+ }
+
+ assertTrue(
+ String.format(
+ "Delegate method %1$s.%2$s is not used anymore and must be removed",
+ delegateClass.getName(),
+ getMethodName(delegateMethod)),
+ checkedDelegateMethods.contains(delegateMethod));
+ }
+
+ }
+
+ private String getMethodName(Method method) {
+ return getMethodName(method, method.getParameterTypes());
+ }
+
+ private String getMethodName(Method method, Class<?>[] parameters) {
+ // compute a full class name that's long but not too long.
+ StringBuilder sb = new StringBuilder(method.getName() + "(");
+ for (int j = 0; j < parameters.length; j++) {
+ Class<?> theClass = parameters[j];
+ sb.append(theClass.getName());
+ int dimensions = 0;
+ while (theClass.isArray()) {
+ dimensions++;
+ theClass = theClass.getComponentType();
+ }
+ for (int i = 0; i < dimensions; i++) {
+ sb.append("[]");
+ }
+ if (j < (parameters.length - 1)) {
+ sb.append(",");
+ }
+ }
+ sb.append(")");
+
+ return sb.toString();
}
}