Merge "Manage drawable invalidation automatically for Overlays" into jb-mr2-dev
diff --git a/api/current.txt b/api/current.txt
index ad2a623..73eed6e 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -11589,6 +11589,7 @@
ctor public MediaMuxer(java.lang.String, int) throws java.io.IOException;
method public int addTrack(android.media.MediaFormat);
method public void release();
+ method public void setOrientationHint(int);
method public void start();
method public void stop();
method public void writeSampleData(int, java.nio.ByteBuffer, android.media.MediaCodec.BufferInfo);
diff --git a/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index a1ea81a..d196392 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -23,7 +23,8 @@
#include <sys/ioctl.h>
#include <sys/mman.h>
-#include <binder/IMemory.h>
+#include <binder/ProcessState.h>
+
#include <gui/SurfaceComposerClient.h>
#include <gui/ISurfaceComposer.h>
@@ -89,6 +90,8 @@
int main(int argc, char** argv)
{
+ ProcessState::self()->startThreadPool();
+
const char* pname = argv[0];
bool png = false;
int32_t displayId = DEFAULT_DISPLAY_ID;
diff --git a/core/java/android/security/IKeystoreService.java b/core/java/android/security/IKeystoreService.java
index 651693a..2ae3c64 100644
--- a/core/java/android/security/IKeystoreService.java
+++ b/core/java/android/security/IKeystoreService.java
@@ -148,6 +148,10 @@
for (int i = 0; i < size; i++) {
_result[i] = _reply.readString();
}
+ int _ret = _reply.readInt();
+ if (_ret != 1) {
+ return null;
+ }
} finally {
_reply.recycle();
_data.recycle();
@@ -401,6 +405,25 @@
}
return _result;
}
+
+ @Override
+ public int migrate(String name, int targetUid) throws RemoteException {
+ Parcel _data = Parcel.obtain();
+ Parcel _reply = Parcel.obtain();
+ int _result;
+ try {
+ _data.writeInterfaceToken(DESCRIPTOR);
+ _data.writeString(name);
+ _data.writeInt(targetUid);
+ mRemote.transact(Stub.TRANSACTION_migrate, _data, _reply, 0);
+ _reply.readException();
+ _result = _reply.readInt();
+ } finally {
+ _reply.recycle();
+ _data.recycle();
+ }
+ return _result;
+ }
}
private static final String DESCRIPTOR = "android.security.keystore";
@@ -425,6 +448,7 @@
static final int TRANSACTION_grant = IBinder.FIRST_CALL_TRANSACTION + 17;
static final int TRANSACTION_ungrant = IBinder.FIRST_CALL_TRANSACTION + 18;
static final int TRANSACTION_getmtime = IBinder.FIRST_CALL_TRANSACTION + 19;
+ static final int TRANSACTION_migrate = IBinder.FIRST_CALL_TRANSACTION + 20;
/**
* Cast an IBinder object into an IKeystoreService interface, generating
@@ -509,4 +533,6 @@
public int ungrant(String name, int granteeUid) throws RemoteException;
public long getmtime(String name) throws RemoteException;
+
+ public int migrate(String name, int targetUid) throws RemoteException;
}
diff --git a/core/java/android/text/GraphicsOperations.java b/core/java/android/text/GraphicsOperations.java
index 831ccc5..d426d124 100644
--- a/core/java/android/text/GraphicsOperations.java
+++ b/core/java/android/text/GraphicsOperations.java
@@ -58,13 +58,6 @@
int flags, float[] advances, int advancesIndex, Paint paint);
/**
- * Just like {@link Paint#getTextRunAdvances}.
- * @hide
- */
- float getTextRunAdvances(int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex, Paint paint, int reserved);
-
- /**
* Just like {@link Paint#getTextRunCursor}.
* @hide
*/
diff --git a/core/java/android/text/SpannableStringBuilder.java b/core/java/android/text/SpannableStringBuilder.java
index 0f30d25..8929930 100644
--- a/core/java/android/text/SpannableStringBuilder.java
+++ b/core/java/android/text/SpannableStringBuilder.java
@@ -1226,35 +1226,6 @@
}
/**
- * Don't call this yourself -- exists for Paint to use internally.
- * {@hide}
- */
- public float getTextRunAdvances(int start, int end, int contextStart, int contextEnd, int flags,
- float[] advances, int advancesPos, Paint p, int reserved) {
-
- float ret;
-
- int contextLen = contextEnd - contextStart;
- int len = end - start;
-
- if (end <= mGapStart) {
- ret = p.getTextRunAdvances(mText, start, len, contextStart, contextLen,
- flags, advances, advancesPos, reserved);
- } else if (start >= mGapStart) {
- ret = p.getTextRunAdvances(mText, start + mGapLength, len,
- contextStart + mGapLength, contextLen, flags, advances, advancesPos, reserved);
- } else {
- char[] buf = TextUtils.obtain(contextLen);
- getChars(contextStart, contextEnd, buf, 0);
- ret = p.getTextRunAdvances(buf, start - contextStart, len,
- 0, contextLen, flags, advances, advancesPos, reserved);
- TextUtils.recycle(buf);
- }
-
- return ret;
- }
-
- /**
* Returns the next cursor position in the run. This avoids placing the cursor between
* surrogates, between characters that form conjuncts, between base characters and combining
* marks, or within a reordering cluster.
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1ab9943..5fbb642 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -8881,16 +8881,6 @@
advancesIndex);
}
- public float getTextRunAdvances(int start, int end, int contextStart,
- int contextEnd, int flags, float[] advances, int advancesIndex,
- Paint p, int reserved) {
- int count = end - start;
- int contextCount = contextEnd - contextStart;
- return p.getTextRunAdvances(mChars, start + mStart, count,
- contextStart + mStart, contextCount, flags, advances,
- advancesIndex, reserved);
- }
-
public int getTextRunCursor(int contextStart, int contextEnd, int flags,
int offset, int cursorOpt, Paint p) {
int contextCount = contextEnd - contextStart;
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 29a36de..90161fd 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -566,61 +566,23 @@
return totalAdvance;
}
- static jfloat doTextRunAdvancesICU(JNIEnv *env, SkPaint *paint, const jchar *text,
- jint start, jint count, jint contextCount, jint flags,
- jfloatArray advances, jint advancesIndex) {
- NPE_CHECK_RETURN_ZERO(env, paint);
- NPE_CHECK_RETURN_ZERO(env, text);
-
- if ((start | count | contextCount | advancesIndex) < 0 || contextCount < count) {
- doThrowAIOOBE(env);
- return 0;
- }
- if (count == 0) {
- return 0;
- }
- if (advances) {
- size_t advancesLength = env->GetArrayLength(advances);
- if ((size_t)count > advancesLength) {
- doThrowAIOOBE(env);
- return 0;
- }
- }
-
- jfloat advancesArray[count];
- jfloat totalAdvance = 0;
-
- TextLayout::getTextRunAdvancesICU(paint, text, start, count, contextCount, flags,
- advancesArray, totalAdvance);
-
- if (advances != NULL) {
- env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
- }
- return totalAdvance;
- }
-
- static float getTextRunAdvances___CIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
+ static float getTextRunAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
- jint flags, jfloatArray advances, jint advancesIndex, jint reserved) {
+ jint flags, jfloatArray advances, jint advancesIndex) {
jchar* textArray = env->GetCharArrayElements(text, NULL);
- jfloat result = (reserved == 0) ?
- doTextRunAdvances(env, paint, textArray + contextIndex, index - contextIndex,
- count, contextCount, flags, advances, advancesIndex) :
- doTextRunAdvancesICU(env, paint, textArray + contextIndex, index - contextIndex,
- count, contextCount, flags, advances, advancesIndex);
+ jfloat result = doTextRunAdvances(env, paint, textArray + contextIndex,
+ index - contextIndex, count, contextCount, flags, advances, advancesIndex);
env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
return result;
}
- static float getTextRunAdvances__StringIIIII_FII(JNIEnv* env, jobject clazz, SkPaint* paint,
+ static float getTextRunAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, SkPaint* paint,
jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint flags,
- jfloatArray advances, jint advancesIndex, jint reserved) {
+ jfloatArray advances, jint advancesIndex) {
const jchar* textArray = env->GetStringChars(text, NULL);
- jfloat result = (reserved == 0) ?
- doTextRunAdvances(env, paint, textArray + contextStart, start - contextStart,
- end - start, contextEnd - contextStart, flags, advances, advancesIndex) :
- doTextRunAdvancesICU(env, paint, textArray + contextStart, start - contextStart,
- end - start, contextEnd - contextStart, flags, advances, advancesIndex);
+ jfloat result = doTextRunAdvances(env, paint, textArray + contextStart,
+ start - contextStart, end - start, contextEnd - contextStart, flags,
+ advances, advancesIndex);
env->ReleaseStringChars(text, textArray);
return result;
}
@@ -886,10 +848,10 @@
{"native_breakText","(Ljava/lang/String;ZF[F)I", (void*) SkPaintGlue::breakTextS},
{"native_getTextWidths","(I[CII[F)I", (void*) SkPaintGlue::getTextWidths___CII_F},
{"native_getTextWidths","(ILjava/lang/String;II[F)I", (void*) SkPaintGlue::getTextWidths__StringII_F},
- {"native_getTextRunAdvances","(I[CIIIII[FII)F",
- (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FII},
- {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FII)F",
- (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FII},
+ {"native_getTextRunAdvances","(I[CIIIII[FI)F",
+ (void*) SkPaintGlue::getTextRunAdvances___CIIIII_FI},
+ {"native_getTextRunAdvances","(ILjava/lang/String;IIIII[FI)F",
+ (void*) SkPaintGlue::getTextRunAdvances__StringIIIII_FI},
{"native_getTextGlyphs","(ILjava/lang/String;IIIII[C)I",
diff --git a/core/jni/android/graphics/TextLayout.cpp b/core/jni/android/graphics/TextLayout.cpp
index 2beedad..34dc3e8 100644
--- a/core/jni/android/graphics/TextLayout.cpp
+++ b/core/jni/android/graphics/TextLayout.cpp
@@ -80,14 +80,6 @@
}
}
-void TextLayout::getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
- jint count, jint contextCount, jint dirFlags,
- jfloat* resultAdvances, jfloat& resultTotalAdvance) {
- // Compute advances and return them
- computeAdvancesWithICU(paint, chars, start, count, contextCount, dirFlags,
- resultAdvances, &resultTotalAdvance);
-}
-
void TextLayout::getTextPath(SkPaint *paint, const jchar *text, jsize len,
jint bidiFlags, jfloat x, jfloat y, SkPath *path) {
handleText(paint, text, len, bidiFlags, x, y, path);
@@ -111,73 +103,4 @@
canvas->drawTextOnPathHV(value->getGlyphs(), value->getGlyphsCount() * 2, *path, h_, v_, *paint);
}
-void TextLayout::computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
- size_t start, size_t count, size_t contextCount, int dirFlags,
- jfloat* outAdvances, jfloat* outTotalAdvance) {
- SkAutoSTMalloc<CHAR_BUFFER_SIZE, jchar> tempBuffer(contextCount);
- jchar* buffer = tempBuffer.get();
- SkScalar* scalarArray = (SkScalar*)outAdvances;
-
- // this is where we'd call harfbuzz
- // for now we just use ushape.c
- size_t widths;
- const jchar* text;
- if (dirFlags & 0x1) { // rtl, call arabic shaping in case
- UErrorCode status = U_ZERO_ERROR;
- // Use fixed length since we need to keep start and count valid
- u_shapeArabic(chars, contextCount, buffer, contextCount,
- U_SHAPE_LENGTH_FIXED_SPACES_NEAR |
- U_SHAPE_TEXT_DIRECTION_LOGICAL | U_SHAPE_LETTERS_SHAPE |
- U_SHAPE_X_LAMALEF_SUB_ALTERNATE, &status);
- // we shouldn't fail unless there's an out of memory condition,
- // in which case we're hosed anyway
- for (int i = start, e = i + count; i < e; ++i) {
- if (buffer[i] == UNICODE_NOT_A_CHAR) {
- buffer[i] = UNICODE_ZWSP; // zero-width-space for skia
- }
- }
- text = buffer + start;
- widths = paint->getTextWidths(text, count << 1, scalarArray);
- } else {
- text = chars + start;
- widths = paint->getTextWidths(text, count << 1, scalarArray);
- }
-
- jfloat totalAdvance = 0;
- if (widths < count) {
-#if DEBUG_ADVANCES
- ALOGD("ICU -- count=%d", widths);
-#endif
- // Skia operates on code points, not code units, so surrogate pairs return only
- // one value. Expand the result so we have one value per UTF-16 code unit.
-
- // Note, skia's getTextWidth gets confused if it encounters a surrogate pair,
- // leaving the remaining widths zero. Not nice.
- for (size_t i = 0, p = 0; i < widths; ++i) {
- totalAdvance += outAdvances[p++] = SkScalarToFloat(scalarArray[i]);
- if (p < count &&
- text[p] >= UNICODE_FIRST_LOW_SURROGATE &&
- text[p] < UNICODE_FIRST_PRIVATE_USE &&
- text[p-1] >= UNICODE_FIRST_HIGH_SURROGATE &&
- text[p-1] < UNICODE_FIRST_LOW_SURROGATE) {
- outAdvances[p++] = 0;
- }
-#if DEBUG_ADVANCES
- ALOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
-#endif
- }
- } else {
-#if DEBUG_ADVANCES
- ALOGD("ICU -- count=%d", count);
-#endif
- for (size_t i = 0; i < count; i++) {
- totalAdvance += outAdvances[i] = SkScalarToFloat(scalarArray[i]);
-#if DEBUG_ADVANCES
- ALOGD("icu-adv = %f - total = %f", outAdvances[i], totalAdvance);
-#endif
- }
- }
- *outTotalAdvance = totalAdvance;
-}
-
}
diff --git a/core/jni/android/graphics/TextLayout.h b/core/jni/android/graphics/TextLayout.h
index a0f9402..d58c692 100644
--- a/core/jni/android/graphics/TextLayout.h
+++ b/core/jni/android/graphics/TextLayout.h
@@ -66,10 +66,6 @@
jint count, jint contextCount, jint dirFlags,
jfloat* resultAdvances, jfloat* resultTotalAdvance);
- static void getTextRunAdvancesICU(SkPaint* paint, const jchar* chars, jint start,
- jint count, jint contextCount, jint dirFlags,
- jfloat* resultAdvances, jfloat& resultTotalAdvance);
-
static void getTextPath(SkPaint* paint, const jchar* text, jsize len,
jint bidiFlags, jfloat x, jfloat y, SkPath* path);
@@ -82,9 +78,5 @@
static void handleText(SkPaint* paint, const jchar* text, jsize len,
int bidiFlags, jfloat x, jfloat y, SkPath* path);
-
- static void computeAdvancesWithICU(SkPaint* paint, const UChar* chars,
- size_t start, size_t count, size_t contextCount, int dirFlags,
- jfloat* outAdvances, jfloat* outTotalAdvance);
};
} // namespace android
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index b12fdfc..0a97f39 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -23,428 +23,407 @@
#include "selinux/selinux.h"
#include "selinux/android.h"
#include <errno.h>
+#include <ScopedLocalRef.h>
+#include <ScopedUtfChars.h>
+#include <UniquePtr.h>
namespace android {
- static jboolean isSELinuxDisabled = true;
+struct SecurityContext_Delete {
+ void operator()(security_context_t p) const {
+ freecon(p);
+ }
+};
+typedef UniquePtr<char[], SecurityContext_Delete> Unique_SecurityContext;
- static void throw_NullPointerException(JNIEnv *env, const char* msg) {
- jclass clazz;
- clazz = env->FindClass("java/lang/NullPointerException");
- env->ThrowNew(clazz, msg);
- }
+static jboolean isSELinuxDisabled = true;
- /*
- * Function: isSELinuxEnabled
- * Purpose: checks whether SELinux is enabled/disbaled
- * Parameters: none
- * Return value : true (enabled) or false (disabled)
- * Exceptions: none
- */
- static jboolean isSELinuxEnabled(JNIEnv *env, jobject classz) {
-
+/*
+ * Function: isSELinuxEnabled
+ * Purpose: checks whether SELinux is enabled/disbaled
+ * Parameters: none
+ * Return value : true (enabled) or false (disabled)
+ * Exceptions: none
+ */
+static jboolean isSELinuxEnabled(JNIEnv *env, jobject) {
return !isSELinuxDisabled;
- }
+}
- /*
- * Function: isSELinuxEnforced
- * Purpose: return the current SELinux enforce mode
- * Parameters: none
- * Return value: true (enforcing) or false (permissive)
- * Exceptions: none
- */
- static jboolean isSELinuxEnforced(JNIEnv *env, jobject clazz) {
+/*
+ * Function: isSELinuxEnforced
+ * Purpose: return the current SELinux enforce mode
+ * Parameters: none
+ * Return value: true (enforcing) or false (permissive)
+ * Exceptions: none
+ */
+static jboolean isSELinuxEnforced(JNIEnv *env, jobject) {
return (security_getenforce() == 1) ? true : false;
- }
+}
- /*
- * Function: setSELinuxEnforce
- * Purpose: set the SE Linux enforcing mode
- * Parameters: true (enforcing) or false (permissive)
- * Return value: true (success) or false (fail)
- * Exceptions: none
- */
- static jboolean setSELinuxEnforce(JNIEnv *env, jobject clazz, jboolean value) {
- if (isSELinuxDisabled)
- return false;
+/*
+ * Function: setSELinuxEnforce
+ * Purpose: set the SE Linux enforcing mode
+ * Parameters: true (enforcing) or false (permissive)
+ * Return value: true (success) or false (fail)
+ * Exceptions: none
+ */
+static jboolean setSELinuxEnforce(JNIEnv *env, jobject, jboolean value) {
+ if (isSELinuxDisabled) {
+ return false;
+ }
- int enforce = (value) ? 1 : 0;
+ int enforce = value ? 1 : 0;
return (security_setenforce(enforce) != -1) ? true : false;
- }
+}
- /*
- * Function: getPeerCon
- * Purpose: retrieves security context of peer socket
- * Parameters:
- * fileDescriptor: peer socket file as a FileDescriptor object
- * Returns: jstring representing the security_context of socket or NULL if error
- * Exceptions: NullPointerException if fileDescriptor object is NULL
- */
- static jstring getPeerCon(JNIEnv *env, jobject clazz, jobject fileDescriptor) {
- if (isSELinuxDisabled)
- return NULL;
+/*
+ * Function: getPeerCon
+ * Purpose: retrieves security context of peer socket
+ * Parameters:
+ * fileDescriptor: peer socket file as a FileDescriptor object
+ * Returns: jstring representing the security_context of socket or NULL if error
+ * Exceptions: NullPointerException if fileDescriptor object is NULL
+ */
+static jstring getPeerCon(JNIEnv *env, jobject, jobject fileDescriptor) {
+ if (isSELinuxDisabled) {
+ return NULL;
+ }
if (fileDescriptor == NULL) {
- throw_NullPointerException(env, "Trying to check security context of a null peer socket.");
- return NULL;
+ jniThrowNullPointerException(env,
+ "Trying to check security context of a null peer socket.");
+ return NULL;
}
- security_context_t context = NULL;
- jstring securityString = NULL;
-
int fd = jniGetFDFromFileDescriptor(env, fileDescriptor);
-
if (env->ExceptionOccurred() != NULL) {
- ALOGE("There was an issue with retrieving the file descriptor");
- goto bail;
+ ALOGE("getPeerCon => getFD for %p failed", fileDescriptor);
+ return NULL;
}
- if (getpeercon(fd, &context) == -1)
- goto bail;
+ security_context_t tmp;
+ int ret = getpeercon(fd, &tmp);
+ Unique_SecurityContext context(tmp);
- ALOGV("getPeerCon: Successfully retrived context of peer socket '%s'", context);
-
- securityString = env->NewStringUTF(context);
-
- bail:
- if (context != NULL)
- freecon(context);
-
- return securityString;
- }
-
- /*
- * Function: setFSCreateCon
- * Purpose: set security context used for creating a new file system object
- * Parameters:
- * context: security_context_t representing the new context of a file system object,
- * set to NULL to return to the default policy behavior
- * Returns: true on success, false on error
- * Exception: none
- */
- static jboolean setFSCreateCon(JNIEnv *env, jobject clazz, jstring context) {
- if (isSELinuxDisabled)
- return false;
-
- char * securityContext = NULL;
- const char *constant_securityContext = NULL;
-
- if (context != NULL) {
- constant_securityContext = env->GetStringUTFChars(context, NULL);
-
- // GetStringUTFChars returns const char * yet setfscreatecon needs char *
- securityContext = const_cast<char *>(constant_securityContext);
+ ScopedLocalRef<jstring> contextStr(env, NULL);
+ if (ret != -1) {
+ contextStr.reset(env->NewStringUTF(context.get()));
}
- int ret;
- if ((ret = setfscreatecon(securityContext)) == -1)
- goto bail;
+ ALOGV("getPeerCon(%d) => %s", fd, contextStr.get());
+ return contextStr.release();
+}
- ALOGV("setFSCreateCon: set new security context to '%s' ", context == NULL ? "default", context);
+/*
+ * Function: setFSCreateCon
+ * Purpose: set security context used for creating a new file system object
+ * Parameters:
+ * context: security_context_t representing the new context of a file system object,
+ * set to NULL to return to the default policy behavior
+ * Returns: true on success, false on error
+ * Exception: none
+ */
+static jboolean setFSCreateCon(JNIEnv *env, jobject, jstring contextStr) {
+ if (isSELinuxDisabled) {
+ return false;
+ }
- bail:
- if (constant_securityContext != NULL)
- env->ReleaseStringUTFChars(context, constant_securityContext);
+ UniquePtr<ScopedUtfChars> context;
+ const char* context_c_str = NULL;
+ if (contextStr != NULL) {
+ context.reset(new ScopedUtfChars(env, contextStr));
+ context_c_str = context->c_str();
+ if (context_c_str == NULL) {
+ return false;
+ }
+ }
+
+ int ret = setfscreatecon(const_cast<char *>(context_c_str));
+
+ ALOGV("setFSCreateCon(%s) => %d", context_c_str, ret);
return (ret == 0) ? true : false;
- }
+}
- /*
- * Function: setFileCon
- * Purpose: set the security context of a file object
- * Parameters:
- * path: the location of the file system object
- * con: the new security context of the file system object
- * Returns: true on success, false on error
- * Exception: NullPointerException is thrown if either path or context strign are NULL
- */
- static jboolean setFileCon(JNIEnv *env, jobject clazz, jstring path, jstring con) {
- if (isSELinuxDisabled)
- return false;
-
- if (path == NULL) {
- throw_NullPointerException(env, "Trying to change the security context of a NULL file object.");
- return false;
+/*
+ * Function: setFileCon
+ * Purpose: set the security context of a file object
+ * Parameters:
+ * path: the location of the file system object
+ * context: the new security context of the file system object
+ * Returns: true on success, false on error
+ * Exception: NullPointerException is thrown if either path or context strign are NULL
+ */
+static jboolean setFileCon(JNIEnv *env, jobject, jstring pathStr, jstring contextStr) {
+ if (isSELinuxDisabled) {
+ return false;
}
- if (con == NULL) {
- throw_NullPointerException(env, "Trying to set the security context of a file object with NULL.");
- return false;
+ ScopedUtfChars path(env, pathStr);
+ if (path.c_str() == NULL) {
+ return false;
}
- const char *objectPath = env->GetStringUTFChars(path, NULL);
- const char *constant_con = env->GetStringUTFChars(con, NULL);
+ ScopedUtfChars context(env, contextStr);
+ if (context.c_str() == NULL) {
+ return false;
+ }
// GetStringUTFChars returns const char * yet setfilecon needs char *
- char *newCon = const_cast<char *>(constant_con);
+ char *tmp = const_cast<char *>(context.c_str());
+ int ret = setfilecon(path.c_str(), tmp);
- int ret;
- if ((ret = setfilecon(objectPath, newCon)) == -1)
- goto bail;
-
- ALOGV("setFileCon: Succesfully set security context '%s' for '%s'", newCon, objectPath);
-
- bail:
- env->ReleaseStringUTFChars(path, objectPath);
- env->ReleaseStringUTFChars(con, constant_con);
+ ALOGV("setFileCon(%s, %s) => %d", path.c_str(), context.c_str(), ret);
return (ret == 0) ? true : false;
- }
+}
- /*
- * Function: getFileCon
- * Purpose: retrieves the context associated with the given path in the file system
- * Parameters:
- * path: given path in the file system
- * Returns:
- * string representing the security context string of the file object
- * the string may be NULL if an error occured
- * Exceptions: NullPointerException if the path object is null
- */
- static jstring getFileCon(JNIEnv *env, jobject clazz, jstring path) {
- if (isSELinuxDisabled)
- return NULL;
-
- if (path == NULL) {
- throw_NullPointerException(env, "Trying to check security context of a null path.");
- return NULL;
+/*
+ * Function: getFileCon
+ * Purpose: retrieves the context associated with the given path in the file system
+ * Parameters:
+ * path: given path in the file system
+ * Returns:
+ * string representing the security context string of the file object
+ * the string may be NULL if an error occured
+ * Exceptions: NullPointerException if the path object is null
+ */
+static jstring getFileCon(JNIEnv *env, jobject, jstring pathStr) {
+ if (isSELinuxDisabled) {
+ return NULL;
}
- const char *objectPath = env->GetStringUTFChars(path, NULL);
+ ScopedUtfChars path(env, pathStr);
+ if (path.c_str() == NULL) {
+ return NULL;
+ }
- security_context_t context = NULL;
- jstring securityString = NULL;
+ security_context_t tmp;
+ int ret = getfilecon(path.c_str(), &tmp);
+ Unique_SecurityContext context(tmp);
- if (getfilecon(objectPath, &context) == -1)
- goto bail;
+ ScopedLocalRef<jstring> securityString(env, NULL);
+ if (ret != -1) {
+ securityString.reset(env->NewStringUTF(context.get()));
+ }
- ALOGV("getFileCon: Successfully retrived context '%s' for file '%s'", context, objectPath);
+ ALOGV("getFileCon(%s) => %s", path.c_str(), context.get());
+ return securityString.release();
+}
- securityString = env->NewStringUTF(context);
+/*
+ * Function: getCon
+ * Purpose: Get the context of the current process.
+ * Parameters: none
+ * Returns: a jstring representing the security context of the process,
+ * the jstring may be NULL if there was an error
+ * Exceptions: none
+ */
+static jstring getCon(JNIEnv *env, jobject) {
+ if (isSELinuxDisabled) {
+ return NULL;
+ }
- bail:
- if (context != NULL)
- freecon(context);
+ security_context_t tmp;
+ int ret = getcon(&tmp);
+ Unique_SecurityContext context(tmp);
- env->ReleaseStringUTFChars(path, objectPath);
+ ScopedLocalRef<jstring> securityString(env, NULL);
+ if (ret != -1) {
+ securityString.reset(env->NewStringUTF(context.get()));
+ }
- return securityString;
- }
+ ALOGV("getCon() => %s", context.get());
+ return securityString.release();
+}
- /*
- * Function: getCon
- * Purpose: Get the context of the current process.
- * Parameters: none
- * Returns: a jstring representing the security context of the process,
- * the jstring may be NULL if there was an error
- * Exceptions: none
- */
- static jstring getCon(JNIEnv *env, jobject clazz) {
- if (isSELinuxDisabled)
- return NULL;
+/*
+ * Function: getPidCon
+ * Purpose: Get the context of a process identified by its pid
+ * Parameters:
+ * pid: a jint representing the process
+ * Returns: a jstring representing the security context of the pid,
+ * the jstring may be NULL if there was an error
+ * Exceptions: none
+ */
+static jstring getPidCon(JNIEnv *env, jobject, jint pid) {
+ if (isSELinuxDisabled) {
+ return NULL;
+ }
- security_context_t context = NULL;
- jstring securityString = NULL;
+ security_context_t tmp;
+ int ret = getpidcon(static_cast<pid_t>(pid), &tmp);
+ Unique_SecurityContext context(tmp);
- if (getcon(&context) == -1)
- goto bail;
+ ScopedLocalRef<jstring> securityString(env, NULL);
+ if (ret != -1) {
+ securityString.reset(env->NewStringUTF(context.get()));
+ }
- ALOGV("getCon: Successfully retrieved context '%s'", context);
+ ALOGV("getPidCon(%d) => %s", pid, context.get());
+ return securityString.release();
+}
- securityString = env->NewStringUTF(context);
-
- bail:
- if (context != NULL)
- freecon(context);
-
- return securityString;
- }
-
- /*
- * Function: getPidCon
- * Purpose: Get the context of a process identified by its pid
- * Parameters:
- * pid: a jint representing the process
- * Returns: a jstring representing the security context of the pid,
- * the jstring may be NULL if there was an error
- * Exceptions: none
- */
- static jstring getPidCon(JNIEnv *env, jobject clazz, jint pid) {
- if (isSELinuxDisabled)
- return NULL;
-
- security_context_t context = NULL;
- jstring securityString = NULL;
-
- pid_t checkPid = (pid_t)pid;
-
- if (getpidcon(checkPid, &context) == -1)
- goto bail;
-
- ALOGV("getPidCon: Successfully retrived context '%s' for pid '%d'", context, checkPid);
-
- securityString = env->NewStringUTF(context);
-
- bail:
- if (context != NULL)
- freecon(context);
-
- return securityString;
- }
-
- /*
- * Function: getBooleanNames
- * Purpose: Gets a list of the SELinux boolean names.
- * Parameters: None
- * Returns: an array of strings containing the SELinux boolean names.
- * returns NULL string on error
- * Exceptions: None
- */
- static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv clazz) {
- if (isSELinuxDisabled)
- return NULL;
+/*
+ * Function: getBooleanNames
+ * Purpose: Gets a list of the SELinux boolean names.
+ * Parameters: None
+ * Returns: an array of strings containing the SELinux boolean names.
+ * returns NULL string on error
+ * Exceptions: None
+ */
+static jobjectArray getBooleanNames(JNIEnv *env, JNIEnv) {
+ if (isSELinuxDisabled) {
+ return NULL;
+ }
char **list;
- int i, len, ret;
- jclass stringClass;
- jobjectArray stringArray = NULL;
+ int len;
+ if (security_get_boolean_names(&list, &len) == -1) {
+ return NULL;
+ }
- if (security_get_boolean_names(&list, &len) == -1)
- return NULL;
-
- stringClass = env->FindClass("java/lang/String");
- stringArray = env->NewObjectArray(len, stringClass, env->NewStringUTF(""));
- for (i = 0; i < len; i++) {
- jstring obj;
- obj = env->NewStringUTF(list[i]);
- env->SetObjectArrayElement(stringArray, i, obj);
- env->DeleteLocalRef(obj);
- free(list[i]);
+ jclass stringClass = env->FindClass("java/lang/String");
+ jobjectArray stringArray = env->NewObjectArray(len, stringClass, NULL);
+ for (int i = 0; i < len; i++) {
+ ScopedLocalRef<jstring> obj(env, env->NewStringUTF(list[i]));
+ env->SetObjectArrayElement(stringArray, i, obj.get());
+ free(list[i]);
}
free(list);
return stringArray;
- }
+}
- /*
- * Function: getBooleanValue
- * Purpose: Gets the value for the given SELinux boolean name.
- * Parameters:
- * String: The name of the SELinux boolean.
- * Returns: a boolean: (true) boolean is set or (false) it is not.
- * Exceptions: None
- */
- static jboolean getBooleanValue(JNIEnv *env, jobject clazz, jstring name) {
- if (isSELinuxDisabled)
- return false;
+/*
+ * Function: getBooleanValue
+ * Purpose: Gets the value for the given SELinux boolean name.
+ * Parameters:
+ * String: The name of the SELinux boolean.
+ * Returns: a boolean: (true) boolean is set or (false) it is not.
+ * Exceptions: None
+ */
+static jboolean getBooleanValue(JNIEnv *env, jobject, jstring nameStr) {
+ if (isSELinuxDisabled) {
+ return false;
+ }
- const char *boolean_name;
- int ret;
+ if (nameStr == NULL) {
+ return false;
+ }
- if (name == NULL)
- return false;
- boolean_name = env->GetStringUTFChars(name, NULL);
- ret = security_get_boolean_active(boolean_name);
- env->ReleaseStringUTFChars(name, boolean_name);
+ ScopedUtfChars name(env, nameStr);
+ int ret = security_get_boolean_active(name.c_str());
+
+ ALOGV("getBooleanValue(%s) => %d", name.c_str(), ret);
return (ret == 1) ? true : false;
- }
+}
- /*
- * Function: setBooleanNames
- * Purpose: Sets the value for the given SELinux boolean name.
- * Parameters:
- * String: The name of the SELinux boolean.
- * Boolean: The new value of the SELinux boolean.
- * Returns: a boolean indicating whether or not the operation succeeded.
- * Exceptions: None
- */
- static jboolean setBooleanValue(JNIEnv *env, jobject clazz, jstring name, jboolean value) {
- if (isSELinuxDisabled)
- return false;
+/*
+ * Function: setBooleanNames
+ * Purpose: Sets the value for the given SELinux boolean name.
+ * Parameters:
+ * String: The name of the SELinux boolean.
+ * Boolean: The new value of the SELinux boolean.
+ * Returns: a boolean indicating whether or not the operation succeeded.
+ * Exceptions: None
+ */
+static jboolean setBooleanValue(JNIEnv *env, jobject, jstring nameStr, jboolean value) {
+ if (isSELinuxDisabled) {
+ return false;
+ }
- const char *boolean_name = NULL;
- int ret;
+ if (nameStr == NULL) {
+ return false;
+ }
- if (name == NULL)
- return false;
- boolean_name = env->GetStringUTFChars(name, NULL);
- ret = security_set_boolean(boolean_name, (value) ? 1 : 0);
- env->ReleaseStringUTFChars(name, boolean_name);
- if (ret)
- return false;
+ ScopedUtfChars name(env, nameStr);
+ int ret = security_set_boolean(name.c_str(), value ? 1 : 0);
+ if (ret) {
+ return false;
+ }
- if (security_commit_booleans() == -1)
- return false;
+ if (security_commit_booleans() == -1) {
+ return false;
+ }
return true;
- }
+}
- /*
- * Function: checkSELinuxAccess
- * Purpose: Check permissions between two security contexts.
- * Parameters: scon: subject security context as a string
- * tcon: object security context as a string
- * tclass: object's security class name as a string
- * perm: permission name as a string
- * Returns: boolean: (true) if permission was granted, (false) otherwise
- * Exceptions: None
- */
- static jboolean checkSELinuxAccess(JNIEnv *env, jobject clazz, jstring scon, jstring tcon, jstring tclass, jstring perm) {
- if (isSELinuxDisabled)
- return true;
+/*
+ * Function: checkSELinuxAccess
+ * Purpose: Check permissions between two security contexts.
+ * Parameters: subjectContextStr: subject security context as a string
+ * objectContextStr: object security context as a string
+ * objectClassStr: object's security class name as a string
+ * permissionStr: permission name as a string
+ * Returns: boolean: (true) if permission was granted, (false) otherwise
+ * Exceptions: None
+ */
+static jboolean checkSELinuxAccess(JNIEnv *env, jobject, jstring subjectContextStr,
+ jstring objectContextStr, jstring objectClassStr, jstring permissionStr) {
+ if (isSELinuxDisabled) {
+ return true;
+ }
- int accessGranted = -1;
+ ScopedUtfChars subjectContext(env, subjectContextStr);
+ if (subjectContext.c_str() == NULL) {
+ return false;
+ }
- const char *const_scon, *const_tcon, *mytclass, *myperm;
- char *myscon, *mytcon;
+ ScopedUtfChars objectContext(env, objectContextStr);
+ if (objectContext.c_str() == NULL) {
+ return false;
+ }
- if (scon == NULL || tcon == NULL || tclass == NULL || perm == NULL)
- goto bail;
+ ScopedUtfChars objectClass(env, objectClassStr);
+ if (objectClass.c_str() == NULL) {
+ return false;
+ }
- const_scon = env->GetStringUTFChars(scon, NULL);
- const_tcon = env->GetStringUTFChars(tcon, NULL);
- mytclass = env->GetStringUTFChars(tclass, NULL);
- myperm = env->GetStringUTFChars(perm, NULL);
+ ScopedUtfChars permission(env, permissionStr);
+ if (permission.c_str() == NULL) {
+ return false;
+ }
- // selinux_check_access needs char* for some
- myscon = const_cast<char *>(const_scon);
- mytcon = const_cast<char *>(const_tcon);
+ char *tmp1 = const_cast<char *>(subjectContext.c_str());
+ char *tmp2 = const_cast<char *>(objectContext.c_str());
+ int accessGranted = selinux_check_access(tmp1, tmp2, objectClass.c_str(), permission.c_str(),
+ NULL);
- accessGranted = selinux_check_access(myscon, mytcon, mytclass, myperm, NULL);
+ ALOGV("checkSELinuxAccess(%s, %s, %s, %s) => %d", subjectContext.c_str(), objectContext.c_str(),
+ objectClass.c_str(), permission.c_str(), accessGranted);
- ALOGV("selinux_check_access returned %d", accessGranted);
-
- env->ReleaseStringUTFChars(scon, const_scon);
- env->ReleaseStringUTFChars(tcon, const_tcon);
- env->ReleaseStringUTFChars(tclass, mytclass);
- env->ReleaseStringUTFChars(perm, myperm);
-
- bail:
return (accessGranted == 0) ? true : false;
- }
+}
- /*
- * Function: native_restorecon
- * Purpose: restore default SELinux security context
- * Parameters: pathname: the pathname for the file to be relabeled
- * Returns: boolean: (true) file label successfully restored, (false) otherwise
- * Exceptions: none
- */
- static jboolean native_restorecon(JNIEnv *env, jobject clazz, jstring pathname) {
- if (isSELinuxDisabled)
- return true;
+/*
+ * Function: native_restorecon
+ * Purpose: restore default SELinux security context
+ * Parameters: pathname: the pathname for the file to be relabeled
+ * Returns: boolean: (true) file label successfully restored, (false) otherwise
+ * Exceptions: none
+ */
+static jboolean native_restorecon(JNIEnv *env, jobject, jstring pathnameStr) {
+ if (isSELinuxDisabled) {
+ return true;
+ }
- const char *file = const_cast<char *>(env->GetStringUTFChars(pathname, NULL));
- int ret = selinux_android_restorecon(file);
- env->ReleaseStringUTFChars(pathname, file);
+ ScopedUtfChars pathname(env, pathnameStr);
+ if (pathname.c_str() == NULL) {
+ ALOGV("restorecon(%p) => threw exception", pathname);
+ return false;
+ }
+
+ int ret = selinux_android_restorecon(pathname.c_str());
+ ALOGV("restorecon(%s) => %d", pathname.c_str(), ret);
return (ret == 0);
- }
+}
- /*
- * JNI registration.
- */
- static JNINativeMethod method_table[] = {
-
+/*
+ * JNI registration.
+ */
+static JNINativeMethod method_table[] = {
/* name, signature, funcPtr */
{ "checkSELinuxAccess" , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
{ "getBooleanNames" , "()[Ljava/lang/String;" , (void*)getBooleanNames },
@@ -460,25 +439,25 @@
{ "setFileContext" , "(Ljava/lang/String;Ljava/lang/String;)Z" , (void*)setFileCon },
{ "setFSCreateContext" , "(Ljava/lang/String;)Z" , (void*)setFSCreateCon },
{ "setSELinuxEnforce" , "(Z)Z" , (void*)setSELinuxEnforce},
- };
+};
- static int log_callback(int type, const char *fmt, ...) {
+static int log_callback(int type, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
LOG_PRI_VA(ANDROID_LOG_ERROR, "SELinux", fmt, ap);
va_end(ap);
return 0;
- }
+}
- int register_android_os_SELinux(JNIEnv *env) {
+int register_android_os_SELinux(JNIEnv *env) {
union selinux_callback cb;
cb.func_log = log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
isSELinuxDisabled = (is_selinux_enabled() != 1) ? true : false;
- return AndroidRuntime::registerNativeMethods(
- env, "android/os/SELinux",
- method_table, NELEM(method_table));
- }
+ return AndroidRuntime::registerNativeMethods(env, "android/os/SELinux", method_table,
+ NELEM(method_table));
+}
+
}
diff --git a/core/jni/android_view_GLES20Canvas.cpp b/core/jni/android_view_GLES20Canvas.cpp
index 10c92ba..3a23aa1 100644
--- a/core/jni/android_view_GLES20Canvas.cpp
+++ b/core/jni/android_view_GLES20Canvas.cpp
@@ -869,7 +869,8 @@
static void android_view_GLES20Canvas_drawLayer(JNIEnv* env, jobject clazz,
OpenGLRenderer* renderer, Layer* layer, jfloat x, jfloat y, SkPaint* paint) {
- renderer->drawLayer(layer, x, y, paint);
+ // TODO: don't pass the paint from java
+ renderer->drawLayer(layer, x, y);
}
static jboolean android_view_GLES20Canvas_copyLayer(JNIEnv* env, jobject clazz,
diff --git a/core/res/res/layout/media_controller.xml b/core/res/res/layout/media_controller.xml
index 7575836..24c2866 100644
--- a/core/res/res/layout/media_controller.xml
+++ b/core/res/res/layout/media_controller.xml
@@ -18,7 +18,8 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#CC000000"
- android:orientation="vertical">
+ android:orientation="vertical"
+ android:layoutDirection="ltr">
<LinearLayout
android:layout_width="match_parent"
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 46e6339..596f709 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -259,7 +259,7 @@
<string name="permdesc_getTasks" msgid="7454215995847658102">"앱이 현재 실행 중이거나 최근에 실행된 작업에 대한 정보를 검색할 수 있도록 허용합니다. 이 경우 앱이 기기에서 사용되는 다른 앱에 대한 정보를 검색할 수 있습니다."</string>
<string name="permlab_interactAcrossUsers" msgid="7114255281944211682">"여러 사용자와의 상호작용"</string>
<string name="permdesc_interactAcrossUsers" msgid="364670963623385786">"앱이 기기에서 다양한 사용자에 대한 작업을 수행할 수 있도록 허용합니다. 이 경우 악성 앱이 사용자 간의 보호를 위반할 수 있습니다."</string>
- <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"여러 사용자와의 상호작용을 위한 정식 라이센스"</string>
+ <string name="permlab_interactAcrossUsersFull" msgid="2567734285545074105">"여러 사용자와의 상호작용을 위한 정식 라이선스"</string>
<string name="permdesc_interactAcrossUsersFull" msgid="376841368395502366">"여러 사용자와의 가능한 모든 상호작용을 허용합니다."</string>
<string name="permlab_manageUsers" msgid="1676150911672282428">"사용자 관리"</string>
<string name="permdesc_manageUsers" msgid="8409306667645355638">"앱이 기기에서 검색, 생성 및 삭제를 포함한 사용자 관리를 할 수 있도록 허용합니다."</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 47264b03..5fade4c 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -813,7 +813,7 @@
<string name="lockscreen_glogin_instructions" msgid="3931816256100707784">"Als u wilt ontgrendelen, moet u zich aanmelden bij uw Google-account."</string>
<string name="lockscreen_glogin_username_hint" msgid="8846881424106484447">"Gebruikersnaam (e-mail)"</string>
<string name="lockscreen_glogin_password_hint" msgid="5958028383954738528">"Wachtwoord"</string>
- <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Aanmelden"</string>
+ <string name="lockscreen_glogin_submit_button" msgid="7130893694795786300">"Inloggen"</string>
<string name="lockscreen_glogin_invalid_input" msgid="1364051473347485908">"Gebruikersnaam of wachtwoord ongeldig."</string>
<string name="lockscreen_glogin_account_recovery_hint" msgid="1696924763690379073">"Bent u uw gebruikersnaam of wachtwoord vergeten?"\n"Ga naar "<b>"https://www.google.com/accounts/recovery"</b>"."</string>
<string name="lockscreen_glogin_checking_password" msgid="7114627351286933867">"Controleren…"</string>
@@ -1121,7 +1121,7 @@
<item quantity="other" msgid="7915895323644292768">"Open Wi-Fi-netwerken beschikbaar"</item>
</plurals>
<string name="wifi_available_sign_in" msgid="4029489716605255386">"Aanmelden bij wifi-netwerk"</string>
- <string name="network_available_sign_in" msgid="8495155593358054676">"Aanmelden bij netwerk"</string>
+ <string name="network_available_sign_in" msgid="8495155593358054676">"Inloggen bij netwerk"</string>
<!-- no translation found for network_available_sign_in_detailed (8000081941447976118) -->
<skip />
<string name="wifi_watchdog_network_disabled" msgid="7904214231651546347">"Kan geen verbinding maken met Wi-Fi"</string>
@@ -1447,10 +1447,10 @@
<string name="kg_invalid_puk" msgid="3638289409676051243">"Geef de juiste PUK-code opnieuw op. Bij herhaalde pogingen wordt de simkaart permanent uitgeschakeld."</string>
<string name="kg_invalid_confirm_pin_hint" product="default" msgid="7003469261464593516">"Pincodes komen niet overeen"</string>
<string name="kg_login_too_many_attempts" msgid="6486842094005698475">"Te veel patroonpogingen"</string>
- <string name="kg_login_instructions" msgid="1100551261265506448">"Als u wilt ontgrendelen, moet u zich aanmelden bij uw Google-account."</string>
+ <string name="kg_login_instructions" msgid="1100551261265506448">"Als u wilt ontgrendelen, moet u inloggen op uw Google-account."</string>
<string name="kg_login_username_hint" msgid="5718534272070920364">"Gebruikersnaam (e-mail)"</string>
<string name="kg_login_password_hint" msgid="9057289103827298549">"Wachtwoord"</string>
- <string name="kg_login_submit_button" msgid="5355904582674054702">"Aanmelden"</string>
+ <string name="kg_login_submit_button" msgid="5355904582674054702">"Inloggen"</string>
<string name="kg_login_invalid_input" msgid="5754664119319872197">"Ongeldige gebruikersnaam of wachtwoord."</string>
<string name="kg_login_account_recovery_hint" msgid="5690709132841752974">"Bent u uw gebruikersnaam of wachtwoord vergeten?"\n"Ga naar "<b>"google.com/accounts/recovery"</b>"."</string>
<string name="kg_login_checking_password" msgid="1052685197710252395">"Account controleren…"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index b952bd4..def8ffa 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -428,9 +428,9 @@
<string name="permdesc_readProfile" product="default" msgid="5462475151849888848">"允许该应用读取您设备上存储的个人资料信息,例如您的姓名和联系信息。这意味着该应用可以识别您的身份,并可能将您的个人资料信息发送给他人。"</string>
<string name="permlab_writeProfile" msgid="907793628777397643">"修改您自己的名片"</string>
<string name="permdesc_writeProfile" product="default" msgid="5552084294598465899">"允许该应用更改或添加您设备上存储的个人资料信息,例如您的姓名和联系信息。这意味着该应用可以识别您的身份,并可能将您的个人资料信息发送给他人。"</string>
- <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"读取您的社交视频流"</string>
+ <string name="permlab_readSocialStream" product="default" msgid="1268920956152419170">"读取您的社交信息流"</string>
<string name="permdesc_readSocialStream" product="default" msgid="4255706027172050872">"允许该应用访问并同步您和朋友的社交动态信息。在分享信息时一定要小心,因为此权限可让该应用读取您与社交网络上的朋友之间的交流信息。"</string>
- <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"写入您的社交视频流"</string>
+ <string name="permlab_writeSocialStream" product="default" msgid="3504179222493235645">"写入您的社交信息流"</string>
<string name="permdesc_writeSocialStream" product="default" msgid="3086557552204114849">"允许该应用显示您朋友的社交动态信息。在分享信息时一定要小心,因为此权限可让该应用冒充某个朋友编写消息。请注意:此权限可能不适用于所有社交网络。"</string>
<string name="permlab_readCalendar" msgid="5972727560257612398">"读取日历活动和机密信息"</string>
<string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"允许该应用读取您平板电脑上存储的所有日历活动,包括朋友或同事的活动。此权限可让该应用分享或保存您的日历数据,而不论这些数据是否属于机密或敏感内容。"</string>
@@ -870,9 +870,9 @@
<string name="autofill_address_summary_separator" msgid="7483307893170324129">", "</string>
<string name="autofill_address_summary_format" msgid="4874459455786827344">"$1$2$3"</string>
<string name="autofill_province" msgid="2231806553863422300">"省/直辖市/自治区"</string>
- <string name="autofill_postal_code" msgid="4696430407689377108">"邮政编码"</string>
+ <string name="autofill_postal_code" msgid="4696430407689377108">"邮编"</string>
<string name="autofill_state" msgid="6988894195520044613">"州"</string>
- <string name="autofill_zip_code" msgid="8697544592627322946">"邮政编码"</string>
+ <string name="autofill_zip_code" msgid="8697544592627322946">"邮编"</string>
<string name="autofill_county" msgid="237073771020362891">"郡"</string>
<string name="autofill_island" msgid="4020100875984667025">"岛"</string>
<string name="autofill_district" msgid="8400735073392267672">"地区"</string>
diff --git a/docs/html/google/gcm/gcm.jd b/docs/html/google/gcm/gcm.jd
index 09ce95e..f8ba7b4 100644
--- a/docs/html/google/gcm/gcm.jd
+++ b/docs/html/google/gcm/gcm.jd
@@ -149,7 +149,16 @@
it to the 3rd-party application server, which uses it to identify each device
that has registered to receive messages for a given Android application. In other words,
a registration ID is tied to a particular Android application running on a particular
-device.</td>
+device.
+<br/>
+<br/>
+<strong>Note:</strong> If you use
+<a href="https://developer.android.com/google/backup/index.html">backup and restore</a>,
+you should explicitly avoid backing up registration IDs. When you back up
+a device, apps back up shared prefs indiscriminately. If you don't explicitly
+exclude the GCM registration ID, it could get reused on a new device,
+which would cause delivery errors.
+</td>
</tr>
<tr>
<td><strong>Google User Account</strong></td>
@@ -295,6 +304,13 @@
</li>
</ul>
+<p class="note"><strong>Note:</strong> This section describes how to
+write an app without using the
+<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>.
+For details on writing
+an app that uses the helper libraries (which is the recommended and
+simpler approach), see <a href="gs.html">GCM: Getting Started</a>.
+
<h3 id="manifest">Creating the Manifest</h3>
<p>Every Android application must have an <code>AndroidManifest.xml</code> file (with
@@ -585,6 +601,7 @@
could not run properly. </li>
</ul>
+
<h2 id="server">Role of the 3rd-party Application Server</h2>
<p>Before you can write client Android applications that use the GCM feature, you must
@@ -758,9 +775,14 @@
<pre class="prettyprint">collapse_key=score_update&time_to_live=108&delay_while_idle=1&data.score=4x8&data.time=15:16.2342&registration_id=42
</pre>
- <p class="note"><strong>Note:</strong> If your organization has a firewall that restricts the traffic to or from the Internet, you'll need to configure it to allow connectivity with GCM. The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but it sometimes uses 5229 and 5230.
-GCM doesn't provide specific IPs. It changes IPs frequently. We recommend against using ACLs but if you must use them, take a broad approach such as the method suggested in <a href="http://support.google.com/code/bin/answer.py?hl=en&answer=62464">this support link</a>.
-</p>
+<p class="note"><strong>Note:</strong> If your organization has a firewall
+that restricts the traffic to or
+from the Internet, you need to configure it to allow connectivity with GCM.
+The ports to open are: 5228, 5229, and 5230. GCM typically only uses 5228, but
+it sometimes uses 5229 and 5230. GCM doesn't provide specific IPs, so you should
+allow your server to accept incoming connections from all IP addresses
+contained in the IP blocks listed in Google's ASN of 15169.</p>
+
<h4 id="response">Response format</h4>
@@ -770,7 +792,7 @@
<li>The GCM server rejects the request.</li>
</ul>
-<p>When the messge is processed successfully, the HTTP response has a 200 status and the body contains more information about the status of the message (including possible errors). When the request is rejected,
+<p>When the message is processed successfully, the HTTP response has a 200 status and the body contains more information about the status of the message (including possible errors). When the request is rejected,
the HTTP response contains a non-200 status code (such as 400, 401, or 503).</p>
<p>The following table summarizes the statuses that the HTTP response header might contain. Click the troubleshoot link for advice on how to deal with each type of error.</p>
@@ -825,7 +847,7 @@
<td>Array of objects representing the status of the messages processed. The objects are listed in the same order as the request (i.e., for each registration ID in the request, its result is listed in the same index in the response) and they can have these fields:<br>
<ul>
<li><code>message_id</code>: String representing the message when it was successfully processed.</li>
- <li><code>registration_id</code>: If set, means that GCM processed the message but it has another canonical registration ID for that device, so sender should replace the IDs on future requests (otherwise they might be rejected). This field is never set if there is an error in the request.<br />
+ <li><code>registration_id</code>: If set, means that GCM processed the message but it has another canonical registration ID for that device, so sender should replace the IDs on future requests (otherwise they might be rejected). This field is never set if there is an error in the request.
</li>
<li><code>error</code>: String describing an error that occurred while processing the message for that recipient. The possible values are the same as documented in the above table, plus "Unavailable" (meaning GCM servers were busy and could not process the message for that particular recipient, so it could be retried).</li>
</ul></td>
diff --git a/docs/html/google/gcm/gs.jd b/docs/html/google/gcm/gs.jd
index 37ef684..5d34641 100644
--- a/docs/html/google/gcm/gs.jd
+++ b/docs/html/google/gcm/gs.jd
@@ -86,8 +86,15 @@
<h2 id="libs">Install the Helper Libraries</h2>
<p>To perform the steps described in the following sections, you must first install the
-<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>.
-From the SDK Manager, install <strong>Extras > Google Cloud Messaging for Android Library</strong>. This creates a <code>gcm</code> directory under <code><em>YOUR_SDK_ROOT</em>/extras/google/</code> containing these subdirectories: <code>gcm-client</code>, <code>gcm-server</code>, <code>samples/gcm-demo-client</code>, <code>samples/gcm-demo-server</code>, and <code>samples/gcm-demo-appengine</code>.</p>
+<a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a>. Note that while using the helper libraries is recommended, it is not required. See the <a href="gcm.html#writing_apps">GCM Architectural Overview</a> for a description of how to write apps without using the helper libraries.
+
+<p>To install the helper libraries, choose
+<strong>Extras > Google Cloud Messaging for Android Library</strong>
+from the SDK Manager. This creates a <code>gcm</code> directory under
+<code><em>YOUR_SDK_ROOT</em>/extras/google/</code> containing these
+subdirectories: <code>gcm-client</code>, <code>gcm-server</code>,
+<code>samples/gcm-demo-client</code>, <code>samples/gcm-demo-server</code>,
+and <code>samples/gcm-demo-appengine</code>.</p>
<p class="note"><strong>Note:</strong> If you don't see <strong>Extras > Google Cloud Messaging for Android Library</strong> in the SDK Manager, make sure you are running version 20 or higher. Be sure to restart the SDK Manager after updating it.</p>
diff --git a/docs/html/tools/sdk/ndk/index.jd b/docs/html/tools/sdk/ndk/index.jd
index cb4954b..74caaf4 100644
--- a/docs/html/tools/sdk/ndk/index.jd
+++ b/docs/html/tools/sdk/ndk/index.jd
@@ -1,17 +1,29 @@
ndk=true
page.template=sdk
-ndk.win_download=android-ndk-r8d-windows.zip
-ndk.win_bytes=327014028
-ndk.win_checksum=d78ec3d4ec15ad3b18b9f488a5763c23
+ndk.mac64_download=android-ndk-r8e-darwin-x86_64.tar.bz2
+ndk.mac64_bytes=508419298
+ndk.mac64_checksum=efac96fab20e6ddb1311d6ba5648ce72
-ndk.mac_download=android-ndk-r8d-darwin-x86.tar.bz2
-ndk.mac_bytes=308328942
-ndk.mac_checksum=5cd9ef9fb7e03943ee8c9e147e42e571
+ndk.mac32_download=android-ndk-r8e-darwin-x86.tar.bz2
+ndk.mac32_bytes=496238878
+ndk.mac32_checksum=e17e707464c45c0d5615e4d0ae6a5cf7
-ndk.linux_download=android-ndk-r8d-linux-x86.tar.bz2
-ndk.linux_bytes=254644383
-ndk.linux_checksum=e1fa0379a3feb59f2f0865f1a90bd382
+ndk.linux64_download=android-ndk-r8e-linux-x86_64.tar.bz2
+ndk.linux64_bytes=466853553
+ndk.linux64_checksum=fa812352956067e7a9eefc0274675e9a
+
+ndk.linux32_download=android-ndk-r8e-linux-x86.tar.bz2
+ndk.linux32_bytes=461526099
+ndk.linux32_checksum=26d774b0884bcd98de08eb4de41ab532
+
+ndk.win64_download=android-ndk-r8e-windows-x86_64.zip
+ndk.win64_bytes=461298980
+ndk.win64_checksum=11eb99b3b56fc86d9d231ebff5c41db3
+
+ndk.win32_download=android-ndk-r8e-windows-x86.zip
+ndk.win32_bytes=434701805
+ndk.win32_checksum=fb41ed2bff5610b14a7b6f085ab86213
page.title=Android NDK
@jd:body
@@ -250,6 +262,222 @@
<div class="toggle-content opened">
<p><a href="#" onclick="return toggleContent(this)">
<img src="{@docRoot}assets/images/triangle-opened.png" class="toggle-content-img"
+ alt="">Android NDK, Revision 8e</a> <em>(March 2013)</em>
+ </p>
+
+ <div class="toggle-content-toggleme">
+ <dl>
+ <dt>Important changes:</dt>
+ <dd>
+ <ul>
+ <li>Added 64-bit host toolchain set (package name suffix {@code *-x86_64.*}). For more
+ information, see {@code CHANGES.HTML} and {@code NDK-BUILD.html}.</li>
+ <li>Added Clang 3.2 compiler. GCC 4.6 is still the default. For information on using the
+ Clang compiler, see {@code CHANGES.HTML}.</li>
+ <li>Added static code analyzer for Linux/MacOSX hosts. For information on using the
+ analyzer, see {@code CHANGES.HTML}.</li>
+ <li>Added MCLinker for Linux/MacOSX hosts as an experimental feature. The {@code ld.gold}
+ linker is the default where available, so you must explicitly enable it. For more
+ information, see {@code CHANGES.HTML}.</li>
+ <li>Updated ndk-build to use topological sort for module dependencies, which means the
+ build automatically sorts out the order of libraries specified in
+ {@code LOCAL_STATIC_LIBRARIES}, {@code LOCAL_WHOLE_STATIC_LIBRARIES} and
+ {@code LOCAL_SHARED_LIBRARIES}. For more information, see {@code CHANGES.HTML}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=39378">Issue 39378</a>)</li>
+ </ul>
+ </dd>
+
+ <dt>Important bug fixes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed build script to build all toolchains in {@code -O2}. Toolchains in previous
+ releases were incorrectly built without optimization.</li>
+ <li>Fixed build script which unconditionally builds Clang/llvm for MacOSX in 64-bit.</li>
+ <li>Fixed GCC 4.6/4.7 internal compiler error:
+ {@code gen_thumb_movhi_clobber at config/arm/arm.md:5832}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=52732">Issue 52732</a>)</li>
+ <li>Fixed build problem where GCC/ARM 4.6/4.7 fails to link code using 64-bit atomic
+ built-in functions.
+ (<a href="http://code.google.com/p/android/issues/detail?id=41297">Issue 41297</a>)</li>
+ <li>Fixed GCC 4.7 linker DIV usage mismatch errors.
+ (<a href="http://sourceware.org/ml/binutils/2012-12/msg00202.html">Sourceware Issue</a>)
+ <li>Fixed GCC 4.7 internal compiler error {@code build_data_member_initialization, at
+ cp/semantics.c:5790}.</li>
+ <li>Fixed GCC 4.7 internal compiler error {@code redirect_eh_edge_1, at tree-eh.c:2214}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=52909">Issue 52909</a>)</li>
+ <li>Fixed a GCC 4.7 segfault.
+ (<a href="http://gcc.gnu.org/bugzilla/show_bug.cgi?id=55245">GCC Issue</a>)</li>
+ <li>Fixed {@code <chrono>} clock resolution and enabled {@code steady_clock}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=39680">Issue 39680</a>)</li>
+ <li>Fixed toolchain to enable {@code _GLIBCXX_HAS_GTHREADS} for GCC 4.7 libstdc++.
+ (<a href="http://code.google.com/p/android/issues/detail?id=41770">Issue 41770</a>,
+ <a href="http://code.google.com/p/android/issues/detail?id=41859">Issue 41859</a>)</li>
+ <li>Fixed problem with the X86 MXX/SSE code failing to link due to missing
+ {@code posix_memalign}.
+ (<a href="https://android-review.googlesource.com/#/c/51872">Change 51872</a>)</li>
+ <li>Fixed GCC4.7/X86 segmentation fault in {@code i386.c}, function
+ {@code distance_non_agu_define_in_bb()}.
+ (<a href="https://android-review.googlesource.com/#/c/50383">Change 50383</a>)</li>
+ <li>Fixed GCC4.7/X86 to restore earlier {@code cmov} behavior.
+ (<a href="http://gcc.gnu.org/viewcvs?view=revision&revision=193554">GCC Issue</a>)</li>
+ <li>Fixed handling NULL return value of {@code setlocale()} in libstdc++/GCC4.7.
+ (<a href="http://code.google.com/p/android/issues/detail?id=46718">Issue 46718</a>)
+ <li>Fixed {@code ld.gold} runtime undefined reference to {@code __exidx_start} and
+ {@code __exidx_start_end}.
+ (<a href="https://android-review.googlesource.com/#/c/52134">Change 52134</a>)</li>
+ <li>Fixed Clang 3.1 internal compiler error when using Eigen library.
+ (<a href="http://code.google.com/p/android/issues/detail?id=41246">Issue 41246</a>)</li>
+ <li>Fixed Clang 3.1 internal compiler error including {@code <chrono>} in C++11 mode.
+ (<a href="http://code.google.com/p/android/issues/detail?id=39600">Issue 39600</a>)</li>
+ <li>Fixed Clang 3.1 internal compiler error when generating object code for a method
+ call to a uniform initialized {@code rvalue}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=41387">Issue 41387</a>)</li>
+ <li>Fixed Clang 3.1/X86 stack realignment.
+ (<a href="https://android-review.googlesource.com/#/c/52154">Change 52154</a>)</li>
+ <li>Fixed problem with GNU Debugger (GDB) SIGILL when debugging on Android 4.1.2.
+ (<a href="http://code.google.com/p/android/issues/detail?id=40941">Issue 40941</a>)</li>
+ <li>Fixed problem where GDB cannot set {@code source:line} breakpoints when symbols contain
+ long, indirect file paths.
+ (<a href="http://code.google.com/p/android/issues/detail?id=42448">Issue 42448</a>)</li>
+ <li>Fixed GDB {@code read_program_header} for MIPS PIE executables.
+ (<a href="https://android-review.googlesource.com/#/c/49592">Change 49592</a>)</li>
+ <li>Fixed {@code STLport} segmentation fault in {@code uncaught_exception()}.
+ (<a href="https://android-review.googlesource.com/#/c/50236">Change 50236</a>)</li>
+ <li>Fixed {@code STLport} bus error in exception handling due to unaligned access of
+ {@code DW_EH_PE_udata2}, {@code DW_EH_PE_udata4}, and {@code DW_EH_PE_udata8}.</li>
+ <li>Fixed Gabi++ infinite recursion problem with {@code nothrow new[]} operator.
+ (<a href="http://code.google.com/p/android/issues/detail?id=52833">Issue 52833</a>)</li>
+ <li>Fixed Gabi++ wrong offset to exception handler pointer.
+ (<a href="https://android-review.googlesource.com/#/c/53446">Change 53446</a>)</li>
+ <li>Removed Gabi++ redundant free on exception object
+ (<a href="https://android-review.googlesource.com/#/c/53447">Change 53447</a>)</li>
+ </ul>
+ </dd>
+
+ <dt>Other bug fixes:</dt>
+ <dd>
+ <ul>
+ <li>Fixed NDK headers:
+ <ul>
+ <li>Removed redundant definitions of {@code size_t}, {@code ssize_t}, and
+ {@code ptrdiff_t}.</li>
+ <li>Fixed MIPS and ARM {@code fenv.h} header.</li>
+ <li>Fixed {@code stddef.h} to not redefine {@code offsetof} since it already exists
+ in the toolchain.</li>
+ <li>Fixed {@code elf.h} to contain {@code Elf32_auxv_t} and {@code Elf64_auxv_t}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=38441">Issue 38441</a>)
+ </li>
+ <li>Fixed the {@code #ifdef} C++ definitions in the
+ {@code OpenSLES_AndroidConfiguration.h} header file.
+ (<a href="http://code.google.com/p/android/issues/detail?id=53163">Issue 53163</a>)
+ </li>
+ </ul>
+ </li>
+ <li>Fixed {@code STLport} to abort after out of memory error instead of silently exiting.
+ </li>
+ <li>Fixed system and Gabi++ headers to be able to compile with API level 8 and lower.</li>
+ <li>Fixed {@code cpufeatures} to not parse {@code /proc/self/auxv}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=43055">Issue 43055</a>)</li>
+ <li>Fixed {@code ld.gold} to not depend on host libstdc++ and on Windows platforms,
+ to not depend on the {@code libgcc_sjlj_1.dll} library.</li>
+ <li>Fixed Clang 3.1 which emits inconsistent register list in {@code .vsave} and fails
+ assembler.
+ (<a href="https://android-review.googlesource.com/#/c/49930">Change 49930</a>)</li>
+ <li>Fixed Clang 3.1 to be able to compile libgabi++ and pass the {@code test-stlport}
+ tests for MIPS build targets.
+ (<a href="https://android-review.googlesource.com/#/c/51961">Change 51961</a>)</li>
+ <li>Fixed Clang 3.1 to only enable exception by default for C++, not for C.</li>
+ <li>Fixed several issues in Clang 3.1 to pass most GNU exception tests.</li>
+ <li>Fixed scripts {@code clang} and {@code clang++} in standalone NDK compiler to detect
+ {@code -cc1} and to not specify {@code -target} when found.</li>
+ <li>Fixed {@code ndk-build} to observe {@code NDK_APP_OUT} set in {@code Application.mk}.
+ </li>
+ <li>Fixed X86 {@code libc.so} and {@code lib.a} which were missing the {@code sigsetjmp}
+ and {@code siglongjmp} functions already declared in {@code setjmp.h}.
+ (<a href="http://code.google.com/p/android/issues/detail?id=19851">Issue 19851</a>)</li>
+ <li>Patched GCC 4.4.3/4.6/4.7 libstdc++ to work with Clang in C++ 11.
+ (<a href="http://clang.llvm.org/cxx_status.html">Clang Issue</a>)</li>
+ <li>Fixed cygwin path in argument passed to {@code HOST_AWK}.</li>
+ <li>Fixed {@code ndk-build} script warning in windows when running from project's JNI
+ directory.
+ (<a href="http://code.google.com/p/android/issues/detail?id=40192">Issue 40192</a>)</li>
+ <li>Fixed problem where the {@code ndk-build} script does not build if makefile has
+ trailing whitespace in the {@code LOCAL_PATH} definition.
+ (<a href="http://code.google.com/p/android/issues/detail?id=42841">Issue 42841</a>)</li>
+ </ul>
+ </dd>
+
+ <dt>Other changes:</dt>
+ <dd>
+ <ul>
+ <li>Enabled threading support in GCC/MIPS toolchain.</li>
+ <li>Updated GCC exception handling helpers {@code __cxa_begin_cleanup} and
+ {@code __cxa_type_match} to have <em>default</em> visibility from the previous
+ <em>hidden</em> visibility in GNU libstdc++. For more information, see
+ {@code CHANGES.HTML}.</li>
+ <li>Updated build scripts so that Gabi++ and STLport static libraries are now built with
+ hidden visibility except for exception handling helpers.</li>
+ <li>Updated build so that {@code STLport} is built for ARM in Thumb mode.</li>
+ <li>Added support for {@code std::set_new_handler} in Gabi++.
+ (<a href="http://code.google.com/p/android/issues/detail?id=52805">Issue 52805</a>)</li>
+ <li>Enabled {@code FUTEX} system call in GNU libstdc++.</li>
+ <li>Updated {@code ndk-build} so that it no longer copies prebuilt static library to
+ a project's {@code obj/local/<abi>/} directory.
+ (<a href="http://code.google.com/p/android/issues/detail?id=40302">Issue 40302</a>)</li>
+ <li>Removed {@code __ARM_ARCH_5*__} from ARM {@code toolchains/*/setup.mk} script.
+ (<a href="http://code.google.com/p/android/issues/detail?id=21132">Issue 21132</a>)</li>
+ <li>Built additional GNU libstdc++ libraries in thumb for ARM.</li>
+ <li>Enabled MIPS floating-point {@code madd/msub/nmadd/nmsub/recip/rsqrt}
+ instructions with 32-bit FPU.</li>
+ <li>Enabled graphite loop optimizer in GCC 4.6 and 4.7 to allow more optimizations:
+ {@code -fgraphite}, {@code -fgraphite-identity}, {@code -floop-block}, {@code -floop-flatten},
+ {@code -floop-interchange}, {@code -floop-strip-mine}, {@code -floop-parallelize-all},
+ and {@code -ftree-loop-linear}.
+ (<a href="http://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html">info</a>)</li>
+ <li>Enabled {@code polly} for Clang 3.1 on Linux and Max OS X 32-bit hosts which analyzes
+ and optimizes memory access. (<a href="http://polly.llvm.org">info</a>)</li>
+ <li>Enabled {@code -flto} in GCC 4.7, 4.6, Clang 3.2 and Clang 3.1 on linux (Clang LTO
+ via LLVMgold.so). MIPS compiler targets are not supported because {@code ld.gold}
+ is not available.</li>
+ <li>Enabled {@code --plugin} and {@code --plugin-opt} for {@code ld.gold} in GCC 4.6/4.7.
+ </li>
+ <li>Enabled {@code --text-reorder} for {@code ld.gold} in GCC 4.7.</li>
+ <li>Configured GNU libstdc++ with {@code _GLIBCXX_USE_C99_MATH} which undefines the
+ {@code isinf} script in the bionic header. For more information, see
+ {@code CHANGES.html}.</li>
+ <li>Added {@code APP_LDFLAGS} to the build scripts. For more information, see
+ {@code ANDROID-MK.html}.</li>
+ <li>Updated build scripts to allow {@code NDK_LOG=0} to disable the {@code NDK_LOG}.</li>
+ <li>Updated build scripts to allow {@code NDK_HOST_32BIT=0} to disable the host developer
+ environment 32-bit toolchain.</li>
+ <li>Changed the default GCC/X86 flags {@code -march=} and {@code -mtune=} from
+ {@code pentiumpro} and {@code generic} to {@code i686} and {@code atom}.</li>
+ <li>Enhanced toolchain build scripts:
+ <ul>
+ <li>Fixed a race condition in {@code build-gcc.sh} for the {@code mingw} build type
+ which was preventing a significant amount of parallel build processing.</li>
+ <li>Updated {@code build-gabi++.sh} and {@code build-stlport.sh} so they can now run
+ from the NDK package.
+ (<a href="http://code.google.com/p/android/issues/detail?id=52835">Issue 52835</a>)
+ </li>
+ <li>Fixed {@code run-tests.sh} in the {@code MSys} utilities collection.</li>
+ <li>Improved 64-bit host toolchain and Canadian Cross build support.</li>
+ <li>Updated {@code build-mingw64-toolchain.sh} script to more recent version.</li>
+ <li>Added option to build {@code libgnustl_static.a} and {@code stlport_static.a}
+ without hidden visibility.</li>
+ </ul>
+ </li>
+ </ul>
+
+ </dd>
+ </dl>
+ </div>
+</div>
+
+
+<div class="toggle-content closed">
+ <p><a href="#" onclick="return toggleContent(this)">
+ <img src="{@docRoot}assets/images/triangle-closed.png" class="toggle-content-img"
alt="">Android NDK, Revision 8d</a> <em>(December 2012)</em>
</p>
@@ -769,7 +997,7 @@
<dd>
<ul>
<li>Added GCC 4.6 toolchain ({@code binutils} 2.21 with {@code gold} and GDB 7.3.x) to
-co-exist with the original GCC 4.4.3 toolchain ({@code binutils} 2.19 and GDB 6.6).</p>
+co-exist with the original GCC 4.4.3 toolchain ({@code binutils} 2.19 and GDB 6.6).
<ul>
<li>GCC 4.6 is now the default toolchain. You may set {@code
NDK_TOOLCHAIN_VERSION=4.4.3} in {@code Application.mk} to select the original one.</li>
@@ -816,8 +1044,9 @@
following options:
<pre>
LOCAL_DISABLE_NO_EXECUTE=true # disable "--noexecstack" and "-z noexecstack"
-DISABLE_RELRO=true # disable "-z relro" and "-z now"</li>
+DISABLE_RELRO=true # disable "-z relro" and "-z now"
</pre>
+ </li>
</ol>
<p>See {@code docs/ANDROID-MK.html} for more details.</p>
</li>
@@ -826,7 +1055,7 @@
<li>Added branding for Android executables with the {@code .note.ABI-tag} section (in
{@code crtbegin_static/dynamic.o}) so that debugging tools can act accordingly. The structure
-member and values are defined as follows:</p>
+member and values are defined as follows:
<pre>
static const struct {
int32_t namesz; /* = 4, sizeof ("GNU") */
@@ -1621,10 +1850,11 @@
<li>Fixed a bug that caused the build to fail if <code>LOCAL_ARM_NEON</code> was set to
true (typo in <code>build/core/build-binary.mk</code>).</li>
- <li>Fixed a bug that prevented the compilation of </code>.s</code> assembly files
+ <li>Fixed a bug that prevented the compilation of <code>.s</code> assembly files
(<code>.S</code> files were okay).</li>
</ul>
</dd>
+ </dl>
</div>
</div>
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 216dc6c..d5cee3a 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1717,20 +1717,6 @@
public float getTextRunAdvances(char[] chars, int index, int count,
int contextIndex, int contextCount, int flags, float[] advances,
int advancesIndex) {
- return getTextRunAdvances(chars, index, count, contextIndex, contextCount, flags,
- advances, advancesIndex, 0 /* use Harfbuzz*/);
- }
-
- /**
- * Convenience overload that takes a char array instead of a
- * String.
- *
- * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int, int)
- * @hide
- */
- public float getTextRunAdvances(char[] chars, int index, int count,
- int contextIndex, int contextCount, int flags, float[] advances,
- int advancesIndex, int reserved) {
if (chars == null) {
throw new IllegalArgumentException("text cannot be null");
@@ -1752,13 +1738,13 @@
}
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, chars, index, count,
- contextIndex, contextCount, flags, advances, advancesIndex, reserved);
+ contextIndex, contextCount, flags, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float res = native_getTextRunAdvances(mNativePaint, chars, index, count,
- contextIndex, contextCount, flags, advances, advancesIndex, reserved);
+ contextIndex, contextCount, flags, advances, advancesIndex);
setTextSize(oldSize);
if (advances != null) {
@@ -1779,20 +1765,6 @@
public float getTextRunAdvances(CharSequence text, int start, int end,
int contextStart, int contextEnd, int flags, float[] advances,
int advancesIndex) {
- return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags,
- advances, advancesIndex, 0 /* use Harfbuzz */);
- }
-
- /**
- * Convenience overload that takes a CharSequence instead of a
- * String.
- *
- * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int)
- * @hide
- */
- public float getTextRunAdvances(CharSequence text, int start, int end,
- int contextStart, int contextEnd, int flags, float[] advances,
- int advancesIndex, int reserved) {
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
@@ -1807,12 +1779,12 @@
if (text instanceof String) {
return getTextRunAdvances((String) text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex, reserved);
+ contextStart, contextEnd, flags, advances, advancesIndex);
}
if (text instanceof SpannedString ||
text instanceof SpannableString) {
return getTextRunAdvances(text.toString(), start, end,
- contextStart, contextEnd, flags, advances, advancesIndex, reserved);
+ contextStart, contextEnd, flags, advances, advancesIndex);
}
if (text instanceof GraphicsOperations) {
return ((GraphicsOperations) text).getTextRunAdvances(start, end,
@@ -1827,7 +1799,7 @@
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
float result = getTextRunAdvances(buf, start - contextStart, len,
- 0, contextLen, flags, advances, advancesIndex, reserved);
+ 0, contextLen, flags, advances, advancesIndex);
TemporaryBuffer.recycle(buf);
return result;
}
@@ -1876,55 +1848,6 @@
*/
public float getTextRunAdvances(String text, int start, int end, int contextStart,
int contextEnd, int flags, float[] advances, int advancesIndex) {
- return getTextRunAdvances(text, start, end, contextStart, contextEnd, flags,
- advances, advancesIndex, 0 /* use Harfbuzz*/);
- }
-
- /**
- * Returns the total advance width for the characters in the run
- * between start and end, and if advances is not null, the advance
- * assigned to each of these characters (java chars).
- *
- * <p>The trailing surrogate in a valid surrogate pair is assigned
- * an advance of 0. Thus the number of returned advances is
- * always equal to count, not to the number of unicode codepoints
- * represented by the run.
- *
- * <p>In the case of conjuncts or combining marks, the total
- * advance is assigned to the first logical character, and the
- * following characters are assigned an advance of 0.
- *
- * <p>This generates the sum of the advances of glyphs for
- * characters in a reordered cluster as the width of the first
- * logical character in the cluster, and 0 for the widths of all
- * other characters in the cluster. In effect, such clusters are
- * treated like conjuncts.
- *
- * <p>The shaping bounds limit the amount of context available
- * outside start and end that can be used for shaping analysis.
- * These bounds typically reflect changes in bidi level or font
- * metrics across which shaping does not occur.
- *
- * @param text the text to measure. Cannot be null.
- * @param start the index of the first character to measure
- * @param end the index past the last character to measure
- * @param contextStart the index of the first character to use for shaping context,
- * must be <= start
- * @param contextEnd the index past the last character to use for shaping context,
- * must be >= end
- * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
- * or {@link #DIRECTION_RTL}
- * @param advances array to receive the advances, must have room for all advances,
- * can be null if only total advance is needed
- * @param advancesIndex the position in advances at which to put the
- * advance corresponding to the character at start
- * @param reserved int reserved value
- * @return the total advance
- *
- * @hide
- */
- public float getTextRunAdvances(String text, int start, int end, int contextStart,
- int contextEnd, int flags, float[] advances, int advancesIndex, int reserved) {
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
@@ -1946,13 +1869,13 @@
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex, reserved);
+ contextStart, contextEnd, flags, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex, reserved);
+ contextStart, contextEnd, flags, advances, advancesIndex);
setTextSize(oldSize);
if (advances != null) {
@@ -2227,10 +2150,10 @@
private static native float native_getTextRunAdvances(int native_object,
char[] text, int index, int count, int contextIndex, int contextCount,
- int flags, float[] advances, int advancesIndex, int reserved);
+ int flags, float[] advances, int advancesIndex);
private static native float native_getTextRunAdvances(int native_object,
String text, int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex, int reserved);
+ int flags, float[] advances, int advancesIndex);
private native int native_getTextRunCursor(int native_object, char[] text,
int contextStart, int contextLength, int flags, int offset, int cursorOpt);
diff --git a/keystore/java/android/security/AndroidKeyStore.java b/keystore/java/android/security/AndroidKeyStore.java
index 65d7b8f..8a9826b 100644
--- a/keystore/java/android/security/AndroidKeyStore.java
+++ b/keystore/java/android/security/AndroidKeyStore.java
@@ -453,17 +453,19 @@
* convention.
*/
final String[] certAliases = mKeyStore.saw(Credentials.USER_CERTIFICATE);
- for (String alias : certAliases) {
- final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
- if (certBytes == null) {
- continue;
- }
+ if (certAliases != null) {
+ for (String alias : certAliases) {
+ final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
+ if (certBytes == null) {
+ continue;
+ }
- final Certificate c = toCertificate(certBytes);
- nonCaEntries.add(alias);
+ final Certificate c = toCertificate(certBytes);
+ nonCaEntries.add(alias);
- if (cert.equals(c)) {
- return alias;
+ if (cert.equals(c)) {
+ return alias;
+ }
}
}
@@ -472,19 +474,22 @@
* PrivateKeyEntry we looked at above.
*/
final String[] caAliases = mKeyStore.saw(Credentials.CA_CERTIFICATE);
- for (String alias : caAliases) {
- if (nonCaEntries.contains(alias)) {
- continue;
- }
+ if (certAliases != null) {
+ for (String alias : caAliases) {
+ if (nonCaEntries.contains(alias)) {
+ continue;
+ }
- final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
- if (certBytes == null) {
- continue;
- }
+ final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
+ if (certBytes == null) {
+ continue;
+ }
- final Certificate c = toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias));
- if (cert.equals(c)) {
- return alias;
+ final Certificate c =
+ toCertificate(mKeyStore.get(Credentials.CA_CERTIFICATE + alias));
+ if (cert.equals(c)) {
+ return alias;
+ }
}
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index 4b69317..4dc0beb 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -87,9 +87,22 @@
}
}
- public boolean put(String key, byte[] value) {
+ public boolean put(String key, byte[] value, int uid) {
try {
- return mBinder.insert(key, value, -1) == NO_ERROR;
+ return mBinder.insert(key, value, uid) == NO_ERROR;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return false;
+ }
+ }
+
+ public boolean put(String key, byte[] value) {
+ return put(key, value, -1);
+ }
+
+ public boolean delete(String key, int uid) {
+ try {
+ return mBinder.del(key, uid) == NO_ERROR;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return false;
@@ -97,8 +110,12 @@
}
public boolean delete(String key) {
+ return delete(key, -1);
+ }
+
+ public boolean contains(String key, int uid) {
try {
- return mBinder.del(key, -1) == NO_ERROR;
+ return mBinder.exist(key, uid) == NO_ERROR;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return false;
@@ -106,23 +123,22 @@
}
public boolean contains(String key) {
- try {
- return mBinder.exist(key, -1) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
+ return contains(key, -1);
}
- public String[] saw(String prefix) {
+ public String[] saw(String prefix, int uid) {
try {
- return mBinder.saw(prefix, -1);
+ return mBinder.saw(prefix, uid);
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return null;
}
}
+ public String[] saw(String prefix) {
+ return saw(prefix, -1);
+ }
+
public boolean reset() {
try {
return mBinder.reset() == NO_ERROR;
@@ -169,9 +185,22 @@
}
}
- public boolean generate(String key) {
+ public boolean generate(String key, int uid) {
try {
- return mBinder.generate(key, -1) == NO_ERROR;
+ return mBinder.generate(key, uid) == NO_ERROR;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return false;
+ }
+ }
+
+ public boolean generate(String key) {
+ return generate(key, -1);
+ }
+
+ public boolean importKey(String keyName, byte[] key, int uid) {
+ try {
+ return mBinder.import_key(keyName, key, uid) == NO_ERROR;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return false;
@@ -179,12 +208,7 @@
}
public boolean importKey(String keyName, byte[] key) {
- try {
- return mBinder.import_key(keyName, key, -1) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
+ return importKey(keyName, key, -1);
}
public byte[] getPubkey(String key) {
@@ -196,15 +220,19 @@
}
}
- public boolean delKey(String key) {
+ public boolean delKey(String key, int uid) {
try {
- return mBinder.del_key(key, -1) == NO_ERROR;
+ return mBinder.del_key(key, uid) == NO_ERROR;
} catch (RemoteException e) {
Log.w(TAG, "Cannot connect to keystore", e);
return false;
}
}
+ public boolean delKey(String key) {
+ return delKey(key, -1);
+ }
+
public byte[] sign(String key, byte[] data) {
try {
return mBinder.sign(key, data);
@@ -259,6 +287,15 @@
}
}
+ public boolean migrate(String key, int uid) {
+ try {
+ return mBinder.migrate(key, uid) == NO_ERROR;
+ } catch (RemoteException e) {
+ Log.w(TAG, "Cannot connect to keystore", e);
+ return false;
+ }
+ }
+
public int getLastError() {
return mError;
}
diff --git a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
index cd031b4..69007c4 100644
--- a/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
+++ b/keystore/tests/src/android/security/AndroidKeyPairGeneratorTest.java
@@ -67,7 +67,9 @@
assertTrue(mAndroidKeyStore.password("1111"));
assertTrue(mAndroidKeyStore.isUnlocked());
- assertEquals(0, mAndroidKeyStore.saw("").length);
+ String[] aliases = mAndroidKeyStore.saw("");
+ assertNotNull(aliases);
+ assertEquals(0, aliases.length);
mGenerator = java.security.KeyPairGenerator.getInstance(AndroidKeyPairGenerator.NAME);
}
diff --git a/keystore/tests/src/android/security/KeyStoreTest.java b/keystore/tests/src/android/security/KeyStoreTest.java
index 07a2d7b..8f8ee92 100644
--- a/keystore/tests/src/android/security/KeyStoreTest.java
+++ b/keystore/tests/src/android/security/KeyStoreTest.java
@@ -17,6 +17,7 @@
package android.security;
import android.app.Activity;
+import android.os.Process;
import android.security.KeyStore;
import android.test.ActivityUnitTestCase;
import android.test.AssertionFailedError;
@@ -128,7 +129,7 @@
super.tearDown();
}
- public void teststate() throws Exception {
+ public void testState() throws Exception {
assertEquals(KeyStore.State.UNINITIALIZED, mKeyStore.state());
}
@@ -154,6 +155,24 @@
assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
}
+ public void testPut_grantedUid_Wifi() throws Exception {
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ mKeyStore.password(TEST_PASSWD);
+ assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
+ assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ }
+
+ public void testPut_ungrantedUid_Bluetooth() throws Exception {
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ mKeyStore.password(TEST_PASSWD);
+ assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ }
+
public void testI18n() throws Exception {
assertFalse(mKeyStore.put(TEST_I18N_KEY, TEST_I18N_VALUE));
assertFalse(mKeyStore.contains(TEST_I18N_KEY));
@@ -167,22 +186,64 @@
mKeyStore.password(TEST_PASSWD);
assertFalse(mKeyStore.delete(TEST_KEYNAME));
- mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE);
+ assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
assertTrue(Arrays.equals(TEST_KEYVALUE, mKeyStore.get(TEST_KEYNAME)));
assertTrue(mKeyStore.delete(TEST_KEYNAME));
assertNull(mKeyStore.get(TEST_KEYNAME));
}
+ public void testDelete_grantedUid_Wifi() throws Exception {
+ assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
+ mKeyStore.password(TEST_PASSWD);
+ assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
+
+ assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
+ assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ assertTrue(mKeyStore.delete(TEST_KEYNAME, Process.WIFI_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ }
+
+ public void testDelete_ungrantedUid_Bluetooth() throws Exception {
+ assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ mKeyStore.password(TEST_PASSWD);
+ assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
+
+ assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.delete(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ }
+
public void testContains() throws Exception {
assertFalse(mKeyStore.contains(TEST_KEYNAME));
- mKeyStore.password(TEST_PASSWD);
+ assertTrue(mKeyStore.password(TEST_PASSWD));
assertFalse(mKeyStore.contains(TEST_KEYNAME));
- mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE);
+ assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE));
assertTrue(mKeyStore.contains(TEST_KEYNAME));
}
+ public void testContains_grantedUid_Wifi() throws Exception {
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+
+ assertTrue(mKeyStore.password(TEST_PASSWD));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+
+ assertTrue(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.WIFI_UID));
+ assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ }
+
+ public void testContains_grantedUid_Bluetooth() throws Exception {
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+
+ assertTrue(mKeyStore.password(TEST_PASSWD));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+
+ assertFalse(mKeyStore.put(TEST_KEYNAME, TEST_KEYVALUE, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ }
+
public void testSaw() throws Exception {
String[] emptyResult = mKeyStore.saw(TEST_KEYNAME);
assertNotNull(emptyResult);
@@ -198,6 +259,48 @@
new HashSet(Arrays.asList(results)));
}
+ public void testSaw_ungrantedUid_Bluetooth() throws Exception {
+ String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
+ assertNull(results1);
+
+ mKeyStore.password(TEST_PASSWD);
+ mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE);
+ mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE);
+
+ String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.BLUETOOTH_UID);
+ assertNull(results2);
+ }
+
+ public void testSaw_grantedUid_Wifi() throws Exception {
+ String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID);
+ assertNotNull(results1);
+ assertEquals(0, results1.length);
+
+ mKeyStore.password(TEST_PASSWD);
+ mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.WIFI_UID);
+ mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.WIFI_UID);
+
+ String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.WIFI_UID);
+ assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
+ TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
+ new HashSet(Arrays.asList(results2)));
+ }
+
+ public void testSaw_grantedUid_Vpn() throws Exception {
+ String[] results1 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID);
+ assertNotNull(results1);
+ assertEquals(0, results1.length);
+
+ mKeyStore.password(TEST_PASSWD);
+ mKeyStore.put(TEST_KEYNAME1, TEST_KEYVALUE, Process.VPN_UID);
+ mKeyStore.put(TEST_KEYNAME2, TEST_KEYVALUE, Process.VPN_UID);
+
+ String[] results2 = mKeyStore.saw(TEST_KEYNAME, Process.VPN_UID);
+ assertEquals(new HashSet(Arrays.asList(TEST_KEYNAME1.substring(TEST_KEYNAME.length()),
+ TEST_KEYNAME2.substring(TEST_KEYNAME.length()))),
+ new HashSet(Arrays.asList(results2)));
+ }
+
public void testLock() throws Exception {
assertFalse(mKeyStore.lock());
@@ -239,17 +342,57 @@
}
public void testGenerate_Success() throws Exception {
- mKeyStore.password(TEST_PASSWD);
+ assertTrue(mKeyStore.password(TEST_PASSWD));
assertTrue("Should be able to generate key when unlocked",
mKeyStore.generate(TEST_KEYNAME));
+ assertTrue(mKeyStore.contains(TEST_KEYNAME));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ }
+
+ public void testGenerate_grantedUid_Wifi_Success() throws Exception {
+ assertTrue(mKeyStore.password(TEST_PASSWD));
+
+ assertTrue("Should be able to generate key when unlocked",
+ mKeyStore.generate(TEST_KEYNAME, Process.WIFI_UID));
+ assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME));
+ }
+
+ public void testGenerate_ungrantedUid_Bluetooth_Failure() throws Exception {
+ assertTrue(mKeyStore.password(TEST_PASSWD));
+
+ assertFalse(mKeyStore.generate(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME));
}
public void testImport_Success() throws Exception {
- mKeyStore.password(TEST_PASSWD);
+ assertTrue(mKeyStore.password(TEST_PASSWD));
assertTrue("Should be able to import key when unlocked",
mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES));
+ assertTrue(mKeyStore.contains(TEST_KEYNAME));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ }
+
+ public void testImport_grantedUid_Wifi_Success() throws Exception {
+ assertTrue(mKeyStore.password(TEST_PASSWD));
+
+ assertTrue("Should be able to import key when unlocked",
+ mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.WIFI_UID));
+ assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME));
+ }
+
+ public void testImport_ungrantedUid_Bluetooth_Failure() throws Exception {
+ assertTrue(mKeyStore.password(TEST_PASSWD));
+
+ assertFalse(mKeyStore.importKey(TEST_KEYNAME, PRIVKEY_BYTES, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME));
}
public void testImport_Failure_BadEncoding() throws Exception {
@@ -257,12 +400,15 @@
assertFalse("Invalid DER-encoded key should not be imported",
mKeyStore.importKey(TEST_KEYNAME, TEST_DATA));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
}
public void testSign_Success() throws Exception {
mKeyStore.password(TEST_PASSWD);
assertTrue(mKeyStore.generate(TEST_KEYNAME));
+ assertTrue(mKeyStore.contains(TEST_KEYNAME));
final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
assertNotNull("Signature should not be null", signature);
@@ -272,6 +418,7 @@
mKeyStore.password(TEST_PASSWD);
assertTrue(mKeyStore.generate(TEST_KEYNAME));
+ assertTrue(mKeyStore.contains(TEST_KEYNAME));
final byte[] signature = mKeyStore.sign(TEST_KEYNAME, TEST_DATA);
assertNotNull("Signature should not be null", signature);
@@ -406,6 +553,38 @@
mKeyStore.ungrant(TEST_KEYNAME, 0));
}
+ public void testMigrate_grantedUid_Wifi_Success() throws Exception {
+ assertTrue(mKeyStore.password(TEST_PASSWD));
+
+ assertFalse(mKeyStore.contains(TEST_KEYNAME));
+
+ assertTrue(mKeyStore.generate(TEST_KEYNAME));
+
+ assertTrue(mKeyStore.contains(TEST_KEYNAME));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+
+ assertTrue(mKeyStore.migrate(TEST_KEYNAME, Process.WIFI_UID));
+
+ assertFalse(mKeyStore.contains(TEST_KEYNAME));
+ assertTrue(mKeyStore.contains(TEST_KEYNAME, Process.WIFI_UID));
+ }
+
+ public void testMigrate_ungrantedUid_Bluetooth_Failure() throws Exception {
+ assertTrue(mKeyStore.password(TEST_PASSWD));
+
+ assertFalse(mKeyStore.contains(TEST_KEYNAME));
+
+ assertTrue(mKeyStore.generate(TEST_KEYNAME));
+
+ assertTrue(mKeyStore.contains(TEST_KEYNAME));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+
+ assertFalse(mKeyStore.migrate(TEST_KEYNAME, Process.BLUETOOTH_UID));
+
+ assertTrue(mKeyStore.contains(TEST_KEYNAME));
+ assertFalse(mKeyStore.contains(TEST_KEYNAME, Process.BLUETOOTH_UID));
+ }
+
/**
* The amount of time to allow before and after expected time for variance
* in timing tests.
diff --git a/libs/hwui/DeferredDisplayList.cpp b/libs/hwui/DeferredDisplayList.cpp
index 5c5bf45..1ace42f 100644
--- a/libs/hwui/DeferredDisplayList.cpp
+++ b/libs/hwui/DeferredDisplayList.cpp
@@ -80,7 +80,7 @@
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
renderer.eventMark(strlen(op->name()), op->name());
#endif
- status |= op->applyDraw(renderer, dirty, 0, op->state.mMultipliedAlpha);
+ status |= op->applyDraw(renderer, dirty, 0);
logBuffer.writeCommand(0, op->name());
}
return status;
diff --git a/libs/hwui/DisplayList.cpp b/libs/hwui/DisplayList.cpp
index 4944fe8..257c875 100644
--- a/libs/hwui/DisplayList.cpp
+++ b/libs/hwui/DisplayList.cpp
@@ -233,7 +233,6 @@
mBottom = 0;
mClipChildren = true;
mAlpha = 1;
- mMultipliedAlpha = 255;
mHasOverlappingRendering = true;
mTranslationX = 0;
mTranslationY = 0;
@@ -362,7 +361,7 @@
}
ALOGD("%*sSaveLayerAlpha %.2f, %.2f, %.2f, %.2f, %d, 0x%x", level * 2, "",
(float) 0, (float) 0, (float) mRight - mLeft, (float) mBottom - mTop,
- mMultipliedAlpha, flags);
+ (int)(mAlpha * 255), flags);
}
}
if (mClipChildren && !mCaching) {
@@ -400,9 +399,9 @@
renderer.concatMatrix(mTransformMatrix);
}
}
- if (mAlpha < 1 && !mCaching) {
- if (!mHasOverlappingRendering) {
- renderer.setAlpha(mAlpha);
+ if (mAlpha < 1) {
+ if (mCaching || !mHasOverlappingRendering) {
+ renderer.scaleAlpha(mAlpha);
} else {
// TODO: should be able to store the size of a DL at record time and not
// have to pass it into this call. In fact, this information might be in the
@@ -412,7 +411,7 @@
saveFlags |= SkCanvas::kClipToLayer_SaveFlag;
}
handler(mSaveLayerOp->reinit(0, 0, mRight - mLeft, mBottom - mTop,
- mMultipliedAlpha, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT);
+ mAlpha * 255, SkXfermode::kSrcOver_Mode, saveFlags), PROPERTY_SAVECOUNT);
}
}
if (mClipChildren && !mCaching) {
@@ -423,40 +422,38 @@
class DeferOperationHandler {
public:
- DeferOperationHandler(DeferStateStruct& deferStruct, int multipliedAlpha, int level)
- : mDeferStruct(deferStruct), mMultipliedAlpha(multipliedAlpha), mLevel(level) {}
+ DeferOperationHandler(DeferStateStruct& deferStruct, int level)
+ : mDeferStruct(deferStruct), mLevel(level) {}
inline void operator()(DisplayListOp* operation, int saveCount) {
- operation->defer(mDeferStruct, saveCount, mLevel, mMultipliedAlpha);
+ operation->defer(mDeferStruct, saveCount, mLevel);
}
private:
DeferStateStruct& mDeferStruct;
- const int mMultipliedAlpha;
const int mLevel;
};
void DisplayList::defer(DeferStateStruct& deferStruct, const int level) {
- DeferOperationHandler handler(deferStruct, mCaching ? mMultipliedAlpha : -1, level);
+ DeferOperationHandler handler(deferStruct, level);
iterate<DeferOperationHandler>(deferStruct.mRenderer, handler, level);
}
class ReplayOperationHandler {
public:
- ReplayOperationHandler(ReplayStateStruct& replayStruct, int multipliedAlpha, int level)
- : mReplayStruct(replayStruct), mMultipliedAlpha(multipliedAlpha), mLevel(level) {}
+ ReplayOperationHandler(ReplayStateStruct& replayStruct, int level)
+ : mReplayStruct(replayStruct), mLevel(level) {}
inline void operator()(DisplayListOp* operation, int saveCount) {
#if DEBUG_DISPLAY_LIST_OPS_AS_EVENTS
replayStruct.mRenderer.eventMark(operation->name());
#endif
- operation->replay(mReplayStruct, saveCount, mLevel, mMultipliedAlpha);
+ operation->replay(mReplayStruct, saveCount, mLevel);
}
private:
ReplayStateStruct& mReplayStruct;
- const int mMultipliedAlpha;
const int mLevel;
};
void DisplayList::replay(ReplayStateStruct& replayStruct, const int level) {
- ReplayOperationHandler handler(replayStruct, mCaching ? mMultipliedAlpha : -1, level);
+ ReplayOperationHandler handler(replayStruct, level);
replayStruct.mRenderer.startMark(mName.string());
iterate<ReplayOperationHandler>(replayStruct.mRenderer, handler, level);
diff --git a/libs/hwui/DisplayList.h b/libs/hwui/DisplayList.h
index 5392587..84f20ab 100644
--- a/libs/hwui/DisplayList.h
+++ b/libs/hwui/DisplayList.h
@@ -164,7 +164,6 @@
alpha = fminf(1.0f, fmaxf(0.0f, alpha));
if (alpha != mAlpha) {
mAlpha = alpha;
- mMultipliedAlpha = (int) (255 * alpha);
}
}
@@ -501,7 +500,6 @@
// View properties
bool mClipChildren;
float mAlpha;
- int mMultipliedAlpha;
bool mHasOverlappingRendering;
float mTranslationX, mTranslationY;
float mRotation, mRotationX, mRotationY;
diff --git a/libs/hwui/DisplayListOp.h b/libs/hwui/DisplayListOp.h
index 9988bb8..4561c61 100644
--- a/libs/hwui/DisplayListOp.h
+++ b/libs/hwui/DisplayListOp.h
@@ -78,11 +78,9 @@
kOpLogFlag_JSON = 0x2 // TODO: add?
};
- virtual void defer(DeferStateStruct& deferStruct, int saveCount,
- int level, int multipliedAlpha) = 0;
+ virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) = 0;
- virtual void replay(ReplayStateStruct& replayStruct, int saveCount,
- int level, int multipliedAlpha) = 0;
+ virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) = 0;
virtual void output(int level, uint32_t logFlags = 0) = 0;
@@ -106,8 +104,7 @@
virtual ~StateOp() {}
- virtual void defer(DeferStateStruct& deferStruct, int saveCount,
- int level, int multipliedAlpha) {
+ virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
// default behavior only affects immediate, deferrable state, issue directly to renderer
applyState(deferStruct.mRenderer, saveCount);
}
@@ -116,8 +113,7 @@
* State operations are applied directly to the renderer, but can cause the deferred drawing op
* list to flush
*/
- virtual void replay(ReplayStateStruct& replayStruct, int saveCount,
- int level, int multipliedAlpha) {
+ virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
applyState(replayStruct.mRenderer, saveCount);
}
@@ -129,14 +125,12 @@
DrawOp(SkPaint* paint)
: mPaint(paint), mQuickRejected(false) {}
- virtual void defer(DeferStateStruct& deferStruct, int saveCount,
- int level, int multipliedAlpha) {
+ virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
if (mQuickRejected &&
CC_LIKELY(deferStruct.mReplayFlags & DisplayList::kReplayFlag_ClipChildren)) {
return;
}
- state.mMultipliedAlpha = multipliedAlpha;
if (!getLocalBounds(state.mBounds)) {
// empty bounds signify bounds can't be calculated
state.mBounds.setEmpty();
@@ -145,19 +139,16 @@
deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
}
- virtual void replay(ReplayStateStruct& replayStruct, int saveCount,
- int level, int multipliedAlpha) {
+ virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
if (mQuickRejected &&
CC_LIKELY(replayStruct.mReplayFlags & DisplayList::kReplayFlag_ClipChildren)) {
return;
}
- replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty,
- level, multipliedAlpha);
+ replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty, level);
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) = 0;
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) = 0;
virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
}
@@ -177,8 +168,8 @@
float strokeWidthOutset() { return mPaint->getStrokeWidth() * 0.5f; }
protected:
- SkPaint* getPaint(OpenGLRenderer& renderer, bool alwaysCopy = false) {
- return renderer.filterPaint(mPaint, alwaysCopy);
+ SkPaint* getPaint(OpenGLRenderer& renderer) {
+ return renderer.filterPaint(mPaint);
}
SkPaint* mPaint; // should be accessed via getPaint() when applying
@@ -227,8 +218,7 @@
SaveOp(int flags)
: mFlags(flags) {}
- virtual void defer(DeferStateStruct& deferStruct, int saveCount,
- int level, int multipliedAlpha) {
+ virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
int newSaveCount = deferStruct.mRenderer.save(mFlags);
deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
}
@@ -260,8 +250,7 @@
RestoreToCountOp(int count)
: mCount(count) {}
- virtual void defer(DeferStateStruct& deferStruct, int saveCount,
- int level, int multipliedAlpha) {
+ virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer, saveCount + mCount);
deferStruct.mRenderer.restoreToCount(saveCount + mCount);
}
@@ -293,8 +282,7 @@
int alpha, SkXfermode::Mode mode, int flags)
: mArea(left, top, right, bottom), mAlpha(alpha), mMode(mode), mFlags(flags) {}
- virtual void defer(DeferStateStruct& deferStruct, int saveCount,
- int level, int multipliedAlpha) {
+ virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
// NOTE: don't bother with actual saveLayer, instead issuing it at flush time
int newSaveCount = deferStruct.mRenderer.save(mFlags);
deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount);
@@ -453,8 +441,7 @@
public:
ClipOp(SkRegion::Op op) : mOp(op) {}
- virtual void defer(DeferStateStruct& deferStruct, int saveCount,
- int level, int multipliedAlpha) {
+ virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
// NOTE: must defer op BEFORE applying state, since it may read clip
deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
@@ -689,16 +676,9 @@
paint),
mBitmap(bitmap) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
- bool makeCopy = multipliedAlpha >= 0 && multipliedAlpha < 255;
- SkPaint* paint = getPaint(renderer, makeCopy);
- if (makeCopy) {
- // The paint is safe to modify since we're working on a copy
- paint->setAlpha(multipliedAlpha);
- }
- status_t ret = renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top, paint);
- return ret;
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+ return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
+ getPaint(renderer));
}
virtual void output(int level, uint32_t logFlags) {
@@ -723,8 +703,7 @@
transform.mapRect(mLocalBounds);
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
}
@@ -749,8 +728,7 @@
: DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
getPaint(renderer));
@@ -776,8 +754,7 @@
DrawBitmapDataOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
: DrawBitmapOp(bitmap, left, top, paint) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
mLocalBounds.top, getPaint(renderer));
}
@@ -800,8 +777,7 @@
mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
mVertices(vertices), mColors(colors) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
mVertices, mColors, getPaint(renderer));
}
@@ -834,8 +810,7 @@
mColors(colors), mxDivsCount(width), myDivsCount(height),
mNumColors(numColors), mAlpha(alpha), mMode(mode) {};
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
// NOTE: not calling the virtual method, which takes a paint
return renderer.drawPatch(mBitmap, mxDivs, myDivs, mColors,
mxDivsCount, myDivsCount, mNumColors,
@@ -869,8 +844,7 @@
DrawColorOp(int color, SkXfermode::Mode mode)
: DrawOp(0), mColor(color), mMode(mode) {};
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawColor(mColor, mMode);
}
@@ -913,8 +887,7 @@
DrawRectOp(float left, float top, float right, float bottom, SkPaint* paint)
: DrawStrokableOp(left, top, right, bottom, paint) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
}
@@ -932,8 +905,7 @@
: DrawBoundedOp(rects, count, paint),
mRects(rects), mCount(count) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawRects(mRects, mCount, getPaint(renderer));
}
@@ -958,8 +930,7 @@
float rx, float ry, SkPaint* paint)
: DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
}
@@ -981,8 +952,7 @@
: DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
mX(x), mY(y), mRadius(radius) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
}
@@ -1003,8 +973,7 @@
DrawOvalOp(float left, float top, float right, float bottom, SkPaint* paint)
: DrawStrokableOp(left, top, right, bottom, paint) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
}
@@ -1023,8 +992,7 @@
: DrawStrokableOp(left, top, right, bottom, paint),
mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
mLocalBounds.right, mLocalBounds.bottom,
mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
@@ -1055,8 +1023,7 @@
mLocalBounds.set(left, top, left + width, top + height);
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawPath(mPath, getPaint(renderer));
}
@@ -1086,8 +1053,7 @@
mLocalBounds.outset(strokeWidthOutset());
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawLines(mPoints, mCount, getPaint(renderer));
}
@@ -1113,8 +1079,7 @@
DrawPointsOp(float* points, int count, SkPaint* paint)
: DrawLinesOp(points, count, paint) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
}
@@ -1160,8 +1125,7 @@
/* TODO: inherit from DrawBounded and init mLocalBounds */
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
mHOffset, mVOffset, getPaint(renderer));
}
@@ -1182,8 +1146,7 @@
/* TODO: inherit from DrawBounded and init mLocalBounds */
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
}
@@ -1231,8 +1194,7 @@
}
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
mPositions, getPaint(renderer), mLength);
}
@@ -1269,8 +1231,7 @@
DrawFunctorOp(Functor* functor)
: DrawOp(0), mFunctor(functor) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
renderer.startMark("GL functor");
status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
renderer.endMark();
@@ -1293,22 +1254,21 @@
: DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
mDisplayList(displayList), mFlags(flags) {}
- virtual void defer(DeferStateStruct& deferStruct, int saveCount,
- int level, int multipliedAlpha) {
+ virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
if (mDisplayList && mDisplayList->isRenderable()) {
mDisplayList->defer(deferStruct, level + 1);
}
}
-
- virtual void replay(ReplayStateStruct& replayStruct, int saveCount,
- int level, int multipliedAlpha) {
+virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
if (mDisplayList && mDisplayList->isRenderable()) {
mDisplayList->replay(replayStruct, level + 1);
}
}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) { return DrawGlInfo::kStatusDone; }
+ // NOT USED since replay() is overridden
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+ return DrawGlInfo::kStatusDone;
+ }
virtual void output(int level, uint32_t logFlags) {
OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
@@ -1326,22 +1286,11 @@
class DrawLayerOp : public DrawOp {
public:
- DrawLayerOp(Layer* layer, float x, float y, SkPaint* paint)
- : DrawOp(paint), mLayer(layer), mX(x), mY(y) {}
+ DrawLayerOp(Layer* layer, float x, float y)
+ : DrawOp(0), mLayer(layer), mX(x), mY(y) {}
- virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level,
- int multipliedAlpha) {
- int oldAlpha = -1;
-
- if (multipliedAlpha >= 0 && multipliedAlpha < 255) {
- oldAlpha = mLayer->getAlpha();
- mLayer->setAlpha(multipliedAlpha);
- }
- status_t ret = renderer.drawLayer(mLayer, mX, mY, getPaint(renderer));
- if (oldAlpha >= 0) {
- mLayer->setAlpha(oldAlpha);
- }
- return ret;
+ virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
+ return renderer.drawLayer(mLayer, mX, mY);
}
virtual void output(int level, uint32_t logFlags) {
diff --git a/libs/hwui/DisplayListRenderer.cpp b/libs/hwui/DisplayListRenderer.cpp
index 8b5b54c..07daa3b 100644
--- a/libs/hwui/DisplayListRenderer.cpp
+++ b/libs/hwui/DisplayListRenderer.cpp
@@ -247,12 +247,11 @@
return DrawGlInfo::kStatusDone;
}
-status_t DisplayListRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
+status_t DisplayListRenderer::drawLayer(Layer* layer, float x, float y) {
mLayers.add(layer);
mCaches.resourceCache.incrementRefcount(layer);
- paint = refPaint(paint);
- addDrawOp(new (alloc()) DrawLayerOp(layer, x, y, paint));
+ addDrawOp(new (alloc()) DrawLayerOp(layer, x, y));
return DrawGlInfo::kStatusDone;
}
diff --git a/libs/hwui/DisplayListRenderer.h b/libs/hwui/DisplayListRenderer.h
index 73b9b66..50e552f 100644
--- a/libs/hwui/DisplayListRenderer.h
+++ b/libs/hwui/DisplayListRenderer.h
@@ -94,7 +94,7 @@
virtual bool clipRegion(SkRegion* region, SkRegion::Op op);
virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t flags);
- virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
+ virtual status_t drawLayer(Layer* layer, float x, float y);
virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index e31f6f6..8030d66 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -2827,7 +2827,7 @@
return DrawGlInfo::kStatusDrew;
}
-status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y, SkPaint* paint) {
+status_t OpenGLRenderer::drawLayer(Layer* layer, float x, float y) {
if (!layer) {
return DrawGlInfo::kStatusDone;
}
@@ -2865,7 +2865,7 @@
if (layer->region.isRect()) {
composeLayerRect(layer, layer->regionRect);
} else if (layer->mesh) {
- const float a = layer->getAlpha() / 255.0f;
+ const float a = layer->getAlpha() / 255.0f * mSnapshot->alpha;
setupDraw();
setupDrawWithTexture();
setupDrawColor(a, a, a, a);
@@ -2972,12 +2972,8 @@
mDrawModifiers.mPaintFilterSetBits = setBits & SkPaint::kAllFlags;
}
-SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint, bool alwaysCopy) {
+SkPaint* OpenGLRenderer::filterPaint(SkPaint* paint) {
if (CC_LIKELY(!mDrawModifiers.mHasDrawFilter || !paint)) {
- if (CC_UNLIKELY(alwaysCopy)) {
- mFilteredPaint = *paint;
- return &mFilteredPaint;
- }
return paint;
}
diff --git a/libs/hwui/OpenGLRenderer.h b/libs/hwui/OpenGLRenderer.h
index 3aa9975..fc7c597 100644
--- a/libs/hwui/OpenGLRenderer.h
+++ b/libs/hwui/OpenGLRenderer.h
@@ -72,7 +72,6 @@
struct DeferredDisplayState {
Rect mBounds; // local bounds, mapped with matrix to be in screen space coordinates, clipped.
- int mMultipliedAlpha; // -1 if invalid (because caching not set)
// the below are set and used by the OpenGLRenderer at record and deferred playback
Rect mClip;
@@ -226,7 +225,7 @@
virtual status_t drawDisplayList(DisplayList* displayList, Rect& dirty, int32_t replayFlags);
virtual void outputDisplayList(DisplayList* displayList);
- virtual status_t drawLayer(Layer* layer, float x, float y, SkPaint* paint);
+ virtual status_t drawLayer(Layer* layer, float x, float y);
virtual status_t drawBitmap(SkBitmap* bitmap, float left, float top, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint);
virtual status_t drawBitmap(SkBitmap* bitmap, float srcLeft, float srcTop,
@@ -272,7 +271,7 @@
virtual void resetPaintFilter();
virtual void setupPaintFilter(int clearBits, int setBits);
- SkPaint* filterPaint(SkPaint* paint, bool alwaysCopy = false);
+ SkPaint* filterPaint(SkPaint* paint);
void resetDrawModifiers();
bool storeDisplayState(DeferredDisplayState& state, int stateDeferFlags);
@@ -293,11 +292,11 @@
}
/**
- * Sets the alpha on the current snapshot. This alpha value will be modulated
+ * Scales the alpha on the current snapshot. This alpha value will be modulated
* with other alpha values when drawing primitives.
*/
- void setAlpha(float alpha) {
- mSnapshot->alpha = alpha;
+ void scaleAlpha(float alpha) {
+ mSnapshot->alpha *= alpha;
}
/**
diff --git a/media/java/android/media/MediaDrm.java b/media/java/android/media/MediaDrm.java
new file mode 100644
index 0000000..4561d3f
--- /dev/null
+++ b/media/java/android/media/MediaDrm.java
@@ -0,0 +1,366 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+import android.media.MediaDrmException;
+import java.lang.ref.WeakReference;
+import java.util.UUID;
+import java.util.HashMap;
+import java.util.List;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.Bundle;
+import android.util.Log;
+
+/**
+ * MediaDrm class can be used in conjunction with {@link android.media.MediaCrypto}
+ * to obtain licenses for decoding encrypted media data.
+ *
+ * Crypto schemes are assigned 16 byte UUIDs,
+ * the method {@link #isCryptoSchemeSupported} can be used to query if a given
+ * scheme is supported on the device.
+ *
+ * <a name="Callbacks"></a>
+ * <h3>Callbacks</h3>
+ * <p>Applications may want to register for informational events in order
+ * to be informed of some internal state update during playback or streaming.
+ * Registration for these events is done via a call to
+ * {@link #setOnEventListener(OnInfoListener)}setOnInfoListener,
+ * In order to receive the respective callback
+ * associated with this listener, applications are required to create
+ * MediaDrm objects on a thread with its own Looper running (main UI
+ * thread by default has a Looper running).
+ *
+ * @hide -- don't expose yet
+ */
+public final class MediaDrm {
+
+ private final static String TAG = "MediaDrm";
+
+ private EventHandler mEventHandler;
+ private OnEventListener mOnEventListener;
+
+ private int mNativeContext;
+
+ /**
+ * Query if the given scheme identified by its UUID is supported on
+ * this device.
+ * @param uuid The UUID of the crypto scheme.
+ */
+ public static final boolean isCryptoSchemeSupported(UUID uuid) {
+ return isCryptoSchemeSupportedNative(getByteArrayFromUUID(uuid));
+ }
+
+ private static final byte[] getByteArrayFromUUID(UUID uuid) {
+ long msb = uuid.getMostSignificantBits();
+ long lsb = uuid.getLeastSignificantBits();
+
+ byte[] uuidBytes = new byte[16];
+ for (int i = 0; i < 8; ++i) {
+ uuidBytes[i] = (byte)(msb >>> (8 * (7 - i)));
+ uuidBytes[8 + i] = (byte)(lsb >>> (8 * (7 - i)));
+ }
+
+ return uuidBytes;
+ }
+
+ private static final native boolean isCryptoSchemeSupportedNative(byte[] uuid);
+
+ /**
+ * Instantiate a MediaDrm object using opaque, crypto scheme specific
+ * data.
+ * @param uuid The UUID of the crypto scheme.
+ */
+ public MediaDrm(UUID uuid) throws MediaDrmException {
+ Looper looper;
+ if ((looper = Looper.myLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else if ((looper = Looper.getMainLooper()) != null) {
+ mEventHandler = new EventHandler(this, looper);
+ } else {
+ mEventHandler = null;
+ }
+
+ /* Native setup requires a weak reference to our object.
+ * It's easier to create it here than in C++.
+ */
+ native_setup(new WeakReference<MediaDrm>(this),
+ getByteArrayFromUUID(uuid));
+ }
+
+ /**
+ * Register a callback to be invoked when an event occurs
+ *
+ * @param listener the callback that will be run
+ */
+ public void setOnEventListener(OnEventListener listener)
+ {
+ mOnEventListener = listener;
+ }
+
+ /**
+ * Interface definition for a callback to be invoked when a drm event
+ * occurs.
+ */
+ public interface OnEventListener
+ {
+ /**
+ * Called when an event occurs that requires the app to be notified
+ *
+ * @param md the MediaDrm object on which the event occurred
+ * @param sessionId the DRM session ID on which the event occurred
+ * @param event indicates the event type
+ * @param extra an secondary error code
+ * @param data optional byte array of data that may be associated with the event
+ */
+ void onEvent(MediaDrm md, byte[] sessionId, int event, int extra, byte[] data);
+ }
+
+ /* Do not change these values without updating their counterparts
+ * in include/media/mediadrm.h!
+ */
+ private static final int DRM_EVENT = 200;
+
+ private class EventHandler extends Handler
+ {
+ private MediaDrm mMediaDrm;
+
+ public EventHandler(MediaDrm md, Looper looper) {
+ super(looper);
+ mMediaDrm = md;
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ if (mMediaDrm.mNativeContext == 0) {
+ Log.w(TAG, "MediaDrm went away with unhandled events");
+ return;
+ }
+ switch(msg.what) {
+
+ case DRM_EVENT:
+ Log.i(TAG, "Drm event (" + msg.arg1 + "," + msg.arg2 + ")");
+
+ if (mOnEventListener != null) {
+ Bundle bundle = msg.getData();
+ byte[] sessionId = bundle.getByteArray("sessionId");
+ byte[] data = bundle.getByteArray("data");
+ mOnEventListener.onEvent(mMediaDrm, sessionId, msg.arg1, msg.arg2, data);
+ }
+ return;
+
+ default:
+ Log.e(TAG, "Unknown message type " + msg.what);
+ return;
+ }
+ }
+ }
+
+ /*
+ * Called from native code when an interesting event happens. This method
+ * just uses the EventHandler system to post the event back to the main app thread.
+ * We use a weak reference to the original MediaPlayer object so that the native
+ * code is safe from the object disappearing from underneath it. (This is
+ * the cookie passed to native_setup().)
+ */
+ private static void postEventFromNative(Object mediadrm_ref,
+ int what, int arg1, int arg2, Object obj)
+ {
+ MediaDrm md = (MediaDrm)((WeakReference)mediadrm_ref).get();
+ if (md == null) {
+ return;
+ }
+ if (md.mEventHandler != null) {
+ Message m = md.mEventHandler.obtainMessage(what, arg1, arg2, obj);
+ md.mEventHandler.sendMessage(m);
+ }
+ }
+
+ /**
+ * Open a new session with the MediaDrm object. A session ID is returned.
+ */
+ public native byte[] openSession() throws MediaDrmException;
+
+ /**
+ * Close a session on the MediaDrm object.
+ */
+ public native void closeSession(byte[] sessionId) throws MediaDrmException;
+
+ public static final int MEDIA_DRM_LICENSE_TYPE_STREAMING = 1;
+ public static final int MEDIA_DRM_LICENSE_TYPE_OFFLINE = 2;
+
+ public final class LicenseRequest {
+ public LicenseRequest() {}
+ public byte[] data;
+ public String defaultUrl;
+ };
+
+ /**
+ * A license request/response exchange occurs between the app and a License
+ * Server to obtain the keys required to decrypt the content. getLicenseRequest()
+ * is used to obtain an opaque license request byte array that is delivered to the
+ * license server. The opaque license request byte array is returned in
+ * LicenseReqeust.data. The recommended URL to deliver the license request to is
+ * returned in LicenseRequest.defaultUrl
+ *
+ * @param sessonId the session ID for the drm session
+ * @param init container-specific data, its meaning is interpreted based on the
+ * mime type provided in the mimeType parameter. It could contain, for example,
+ * the content ID, key ID or other data obtained from the content metadata that is
+ * required in generating the license request.
+ * @param mimeType identifies the mime type of the content
+ * @param licenseType specifes if the license is for streaming or offline content
+ * @param optionalParameters are included in the license server request message to
+ * allow a client application to provide additional message parameters to the server.
+ */
+ public native LicenseRequest getLicenseRequest( byte[] sessionId, byte[] init,
+ String mimeType, int licenseType,
+ HashMap<String, String> optionalParameters )
+ throws MediaDrmException;
+
+ /**
+ * After a license response is received by the app, it is provided to the DRM plugin
+ * using provideLicenseResponse.
+ *
+ * @param sessionId the session ID for the DRM session
+ * @param response the byte array response from the server
+ */
+ public native void provideLicenseResponse( byte[] sessionId, byte[] response )
+ throws MediaDrmException;
+
+ /**
+ * Remove the keys associated with a license for a session
+ * @param sessionId the session ID for the DRM session
+ */
+ public native void removeLicense( byte[] sessionId ) throws MediaDrmException;
+
+ /**
+ * Request an informative description of the license for the session. The status is
+ * in the form of {name, value} pairs. Since DRM license policies vary by vendor,
+ * the specific status field names are determined by each DRM vendor. Refer to your
+ * DRM provider documentation for definitions of the field names for a particular
+ * DrmEngine.
+ *
+ * @param sessionId the session ID for the DRM session
+ */
+ public native HashMap<String, String> queryLicenseStatus( byte[] sessionId )
+ throws MediaDrmException;
+
+ public final class ProvisionRequest {
+ public ProvisionRequest() {}
+ public byte[] data;
+ public String defaultUrl;
+ }
+
+ /**
+ * A provision request/response exchange occurs between the app and a provisioning
+ * server to retrieve a device certificate. getProvisionRequest is used to obtain
+ * an opaque license request byte array that is delivered to the provisioning server.
+ * The opaque provision request byte array is returned in ProvisionRequest.data
+ * The recommended URL to deliver the license request to is returned in
+ * ProvisionRequest.defaultUrl.
+ */
+ public native ProvisionRequest getProvisionRequest() throws MediaDrmException;
+
+ /**
+ * After a provision response is received by the app, it is provided to the DRM
+ * plugin using this method.
+ *
+ * @param response the opaque provisioning response byte array to provide to the
+ * DrmEngine.
+ */
+ public native void provideProvisionResponse( byte[] response )
+ throws MediaDrmException;
+
+ /**
+ * A means of enforcing the contractual requirement for a concurrent stream limit
+ * per subscriber across devices is provided via SecureStop. SecureStop is a means
+ * of securely monitoring the lifetime of sessions. Since playback on a device can
+ * be interrupted due to reboot, power failure, etc. a means of persisting the
+ * lifetime information on the device is needed.
+ *
+ * A signed version of the sessionID is written to persistent storage on the device
+ * when each MediaCrypto object is created. The sessionID is signed by the device
+ * private key to prevent tampering.
+ *
+ * In the normal case, playback will be completed, the session destroyed and the
+ * Secure Stops will be queried. The App queries secure stops and forwards the
+ * secure stop message to the server which verifies the signature and notifies the
+ * server side database that the session destruction has been confirmed. The persisted
+ * record on the client is only removed after positive confirmation that the server
+ * received the message using releaseSecureStops().
+ */
+ public native List<byte[]> getSecureStops() throws MediaDrmException;
+
+
+ /**
+ * Process the SecureStop server response message ssRelease. After authenticating
+ * the message, remove the SecureStops identiied in the response.
+ *
+ * @param ssRelease the server response indicating which secure stops to release
+ */
+ public native void releaseSecureStops( byte[] ssRelease )
+ throws MediaDrmException;
+
+
+ /**
+ * Read a Drm plugin property value, given the property name string. There are several
+ * forms of property access functions, depending on the data type returned.
+ *
+ * Standard fields names are:
+ * vendor String - identifies the maker of the plugin
+ * version String - identifies the version of the plugin
+ * description String - describes the plugin
+ * deviceUniqueId byte[] - The device unique identifier is established during device
+ * provisioning and provides a means of uniquely identifying
+ * each device
+ */
+ public native String getPropertyString( String propertyName )
+ throws MediaDrmException;
+
+ public native byte[] getPropertyByteArray( String propertyName )
+ throws MediaDrmException;
+
+ /**
+ * Write a Drm plugin property value. There are several forms of property setting
+ * functions, depending on the data type being set.
+ */
+ public native void setPropertyString( String propertyName, String value )
+ throws MediaDrmException;
+
+ public native void setPropertyByteArray( String propertyName, byte[] value )
+ throws MediaDrmException;
+
+ @Override
+ protected void finalize() {
+ native_finalize();
+ }
+
+ public native final void release();
+ private static native final void native_init();
+
+ private native final void native_setup(Object mediadrm_this, byte[] uuid)
+ throws MediaDrmException;
+
+ private native final void native_finalize();
+
+ static {
+ System.loadLibrary("media_jni");
+ native_init();
+ }
+}
diff --git a/media/java/android/media/MediaDrmException.java b/media/java/android/media/MediaDrmException.java
new file mode 100644
index 0000000..6f81f90
--- /dev/null
+++ b/media/java/android/media/MediaDrmException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.media;
+
+/**
+ * Exception thrown if MediaDrm object could not be instantiated for
+ * whatever reason.
+ *
+ * @hide -- don't expose yet
+ */
+public final class MediaDrmException extends Exception {
+ public MediaDrmException(String detailMessage) {
+ super(detailMessage);
+ }
+}
diff --git a/media/java/android/media/MediaMuxer.java b/media/java/android/media/MediaMuxer.java
index c3cc1e6..1f5ca35 100644
--- a/media/java/android/media/MediaMuxer.java
+++ b/media/java/android/media/MediaMuxer.java
@@ -91,6 +91,8 @@
private static native void nativeStop(int nativeObject);
private static native int nativeAddTrack(int nativeObject, String[] keys,
Object[] values);
+ private static native void nativeSetOrientationHint(int nativeObject,
+ int degrees);
private static native void nativeWriteSampleData(int nativeObject,
int trackIndex, ByteBuffer byteBuf,
int offset, int size, long presentationTimeUs, int flags);
@@ -109,7 +111,7 @@
private int mNativeObject;
/**
- * Constructor
+ * Constructor.
* Creates a media muxer that writes to the specified path.
* @param path The path of the output media file.
* @param format The format of the output media file.
@@ -139,6 +141,31 @@
}
/**
+ * Sets the orientation hint for output video playback.
+ * <p>This method should be called before {@link #start}. Calling this
+ * method will not rotate the video frame when muxer is generating the file,
+ * but add a composition matrix containing the rotation angle in the output
+ * video if the output format is
+ * {@link OutputFormat#MUXER_OUTPUT_MPEG_4} so that a video player can
+ * choose the proper orientation for playback. Note that some video players
+ * may choose to ignore the composition matrix in a video during playback.
+ * By default, the rotation degree is 0.</p>
+ * @param degrees the angle to be rotated clockwise in degrees.
+ * The supported angles are 0, 90, 180, and 270 degrees.
+ */
+ public void setOrientationHint(int degrees) {
+ if (degrees != 0 && degrees != 90 && degrees != 180 && degrees != 270) {
+ throw new IllegalArgumentException("Unsupported angle: " + degrees);
+ }
+ if (mState == MUXER_STATE_INITIALIZED) {
+ nativeSetOrientationHint(mNativeObject, degrees);
+ } else {
+ throw new IllegalStateException("Can't set rotation degrees due" +
+ " to wrong state.");
+ }
+ }
+
+ /**
* Starts the muxer.
* <p>Make sure this is called after {@link #addTrack} and before
* {@link #writeSampleData}.</p>
diff --git a/media/jni/Android.mk b/media/jni/Android.mk
index ac8fb743..6873060 100644
--- a/media/jni/Android.mk
+++ b/media/jni/Android.mk
@@ -5,6 +5,7 @@
android_media_MediaCrypto.cpp \
android_media_MediaCodec.cpp \
android_media_MediaCodecList.cpp \
+ android_media_MediaDrm.cpp \
android_media_MediaExtractor.cpp \
android_media_MediaMuxer.cpp \
android_media_MediaPlayer.cpp \
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
new file mode 100644
index 0000000..9938f76
--- /dev/null
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -0,0 +1,817 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "MediaDrm-JNI"
+#include <utils/Log.h>
+
+#include "android_media_MediaDrm.h"
+
+#include "android_runtime/AndroidRuntime.h"
+#include "jni.h"
+#include "JNIHelp.h"
+
+#include <binder/IServiceManager.h>
+#include <media/IDrm.h>
+#include <media/IMediaPlayerService.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+namespace android {
+
+#define FIND_CLASS(var, className) \
+ var = env->FindClass(className); \
+ LOG_FATAL_IF(! var, "Unable to find class " className);
+
+#define GET_FIELD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find field " fieldName);
+
+#define GET_METHOD_ID(var, clazz, fieldName, fieldDescriptor) \
+ var = env->GetMethodID(clazz, fieldName, fieldDescriptor); \
+ LOG_FATAL_IF(! var, "Unable to find method " fieldName);
+
+struct RequestFields {
+ jfieldID data;
+ jfieldID defaultUrl;
+};
+
+struct ArrayListFields {
+ jmethodID init;
+ jmethodID add;
+};
+
+struct HashmapFields {
+ jmethodID init;
+ jmethodID get;
+ jmethodID put;
+ jmethodID entrySet;
+};
+
+struct SetFields {
+ jmethodID iterator;
+};
+
+struct IteratorFields {
+ jmethodID next;
+ jmethodID hasNext;
+};
+
+struct EntryFields {
+ jmethodID getKey;
+ jmethodID getValue;
+};
+
+struct fields_t {
+ jfieldID context;
+ RequestFields licenseRequest;
+ RequestFields provisionRequest;
+ ArrayListFields arraylist;
+ HashmapFields hashmap;
+ SetFields set;
+ IteratorFields iterator;
+ EntryFields entry;
+};
+
+static fields_t gFields;
+
+static bool throwExceptionAsNecessary(
+ JNIEnv *env, status_t err, const char *msg = NULL) {
+
+ if (err == BAD_VALUE) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", msg);
+ return true;
+ } else if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalStateException", msg);
+ return true;
+ }
+ return false;
+}
+
+static sp<IDrm> GetDrm(JNIEnv *env, jobject thiz) {
+ JDrm *jdrm = (JDrm *)env->GetIntField(thiz, gFields.context);
+ return jdrm ? jdrm->getDrm() : NULL;
+}
+
+JDrm::JDrm(
+ JNIEnv *env, jobject thiz, const uint8_t uuid[16]) {
+ mObject = env->NewWeakGlobalRef(thiz);
+ mDrm = MakeDrm(uuid);
+}
+
+JDrm::~JDrm() {
+ mDrm.clear();
+
+ JNIEnv *env = AndroidRuntime::getJNIEnv();
+
+ env->DeleteWeakGlobalRef(mObject);
+ mObject = NULL;
+}
+
+// static
+sp<IDrm> JDrm::MakeDrm() {
+ sp<IServiceManager> sm = defaultServiceManager();
+
+ sp<IBinder> binder =
+ sm->getService(String16("media.player"));
+
+ sp<IMediaPlayerService> service =
+ interface_cast<IMediaPlayerService>(binder);
+
+ if (service == NULL) {
+ return NULL;
+ }
+
+ sp<IDrm> drm = service->makeDrm();
+
+ if (drm == NULL || (drm->initCheck() != OK && drm->initCheck() != NO_INIT)) {
+ return NULL;
+ }
+
+ return drm;
+}
+
+// static
+sp<IDrm> JDrm::MakeDrm(const uint8_t uuid[16]) {
+ sp<IDrm> drm = MakeDrm();
+
+ if (drm == NULL) {
+ return NULL;
+ }
+
+ status_t err = drm->createPlugin(uuid);
+
+ if (err != OK) {
+ return NULL;
+ }
+
+ return drm;
+}
+
+// static
+bool JDrm::IsCryptoSchemeSupported(const uint8_t uuid[16]) {
+ sp<IDrm> drm = MakeDrm();
+
+ if (drm == NULL) {
+ return false;
+ }
+
+ return drm->isCryptoSchemeSupported(uuid);
+}
+
+status_t JDrm::initCheck() const {
+ return mDrm == NULL ? NO_INIT : OK;
+}
+
+// JNI conversion utilities
+static Vector<uint8_t> JByteArrayToVector(JNIEnv *env, jbyteArray const &byteArray) {
+ Vector<uint8_t> vector;
+ size_t length = env->GetArrayLength(byteArray);
+ vector.insertAt((size_t)0, length);
+ env->GetByteArrayRegion(byteArray, 0, length, (jbyte *)vector.editArray());
+ return vector;
+}
+
+static jbyteArray VectorToJByteArray(JNIEnv *env, Vector<uint8_t> const &vector) {
+ size_t length = vector.size();
+ jbyteArray result = env->NewByteArray(length);
+ if (result != NULL) {
+ env->SetByteArrayRegion(result, 0, length, (jbyte *)vector.array());
+ }
+ return result;
+}
+
+static String8 JStringToString8(JNIEnv *env, jstring const &jstr) {
+ jboolean isCopy;
+ String8 result;
+
+ const char *s = env->GetStringUTFChars(jstr, &isCopy);
+ if (s) {
+ result = s;
+ env->ReleaseStringUTFChars(jstr, s);
+ }
+ return result;
+}
+/*
+ import java.util.HashMap;
+ import java.util.Set;
+ import java.Map.Entry;
+ import jav.util.Iterator;
+
+ HashMap<k, v> hm;
+ Set<Entry<k, v> > s = hm.entrySet();
+ Iterator i = s.iterator();
+ Entry e = s.next();
+*/
+
+static KeyedVector<String8, String8> HashMapToKeyedVector(JNIEnv *env, jobject &hashMap) {
+ jclass clazz;
+ FIND_CLASS(clazz, "java/lang/String");
+ KeyedVector<String8, String8> keyedVector;
+
+ jobject entrySet = env->CallObjectMethod(hashMap, gFields.hashmap.entrySet);
+ if (entrySet) {
+ jobject iterator = env->CallObjectMethod(entrySet, gFields.set.iterator);
+ if (iterator) {
+ jboolean hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
+ while (hasNext) {
+ jobject entry = env->CallObjectMethod(iterator, gFields.iterator.next);
+ if (entry) {
+ jobject obj = env->CallObjectMethod(entry, gFields.entry.getKey);
+ if (!env->IsInstanceOf(obj, clazz)) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ jstring jkey = static_cast<jstring>(obj);
+
+ obj = env->CallObjectMethod(entry, gFields.entry.getValue);
+ if (!env->IsInstanceOf(obj, clazz)) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ }
+ jstring jvalue = static_cast<jstring>(obj);
+
+ String8 key = JStringToString8(env, jkey);
+ String8 value = JStringToString8(env, jvalue);
+ keyedVector.add(key, value);
+
+ env->DeleteLocalRef(jkey);
+ env->DeleteLocalRef(jvalue);
+ hasNext = env->CallBooleanMethod(iterator, gFields.iterator.hasNext);
+ }
+ env->DeleteLocalRef(entry);
+ }
+ env->DeleteLocalRef(iterator);
+ }
+ env->DeleteLocalRef(entrySet);
+ }
+ return keyedVector;
+}
+
+static jobject KeyedVectorToHashMap (JNIEnv *env, KeyedVector<String8, String8> const &map) {
+ jclass clazz;
+ FIND_CLASS(clazz, "java/util/HashMap");
+ jobject hashMap = env->NewObject(clazz, gFields.hashmap.init);
+ for (size_t i = 0; i < map.size(); ++i) {
+ jstring jkey = env->NewStringUTF(map.keyAt(i).string());
+ jstring jvalue = env->NewStringUTF(map.valueAt(i).string());
+ env->CallObjectMethod(hashMap, gFields.hashmap.put, jkey, jvalue);
+ env->DeleteLocalRef(jkey);
+ env->DeleteLocalRef(jvalue);
+ }
+ return hashMap;
+}
+
+static jobject ListOfVectorsToArrayListOfByteArray(JNIEnv *env,
+ List<Vector<uint8_t> > list) {
+ jclass clazz;
+ FIND_CLASS(clazz, "java/util/ArrayList");
+ jobject arrayList = env->NewObject(clazz, gFields.arraylist.init);
+ List<Vector<uint8_t> >::iterator iter = list.begin();
+ while (iter != list.end()) {
+ jbyteArray byteArray = VectorToJByteArray(env, *iter);
+ env->CallBooleanMethod(arrayList, gFields.arraylist.add, byteArray);
+ env->DeleteLocalRef(byteArray);
+ iter++;
+ }
+
+ return arrayList;
+}
+
+} // namespace android
+
+using namespace android;
+
+static sp<JDrm> setDrm(
+ JNIEnv *env, jobject thiz, const sp<JDrm> &drm) {
+ sp<JDrm> old = (JDrm *)env->GetIntField(thiz, gFields.context);
+ if (drm != NULL) {
+ drm->incStrong(thiz);
+ }
+ if (old != NULL) {
+ old->decStrong(thiz);
+ }
+ env->SetIntField(thiz, gFields.context, (int)drm.get());
+
+ return old;
+}
+
+static bool CheckSession(JNIEnv *env, const sp<IDrm> &drm, jbyteArray const &jsessionId)
+{
+ if (drm == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return false;
+ }
+
+ if (jsessionId == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return false;
+ }
+ return true;
+}
+
+static void android_media_MediaDrm_release(JNIEnv *env, jobject thiz) {
+ setDrm(env, thiz, NULL);
+}
+
+static void android_media_MediaDrm_native_init(JNIEnv *env) {
+ jclass clazz;
+ FIND_CLASS(clazz, "android/media/MediaDrm");
+ GET_FIELD_ID(gFields.context, clazz, "mNativeContext", "I");
+
+ FIND_CLASS(clazz, "android/media/MediaDrm$LicenseRequest");
+ GET_FIELD_ID(gFields.licenseRequest.data, clazz, "data", "[B");
+ GET_FIELD_ID(gFields.licenseRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+
+ FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
+ GET_FIELD_ID(gFields.provisionRequest.data, clazz, "data", "[B");
+ GET_FIELD_ID(gFields.provisionRequest.defaultUrl, clazz, "defaultUrl", "Ljava/lang/String;");
+
+ FIND_CLASS(clazz, "java/util/ArrayList");
+ GET_METHOD_ID(gFields.arraylist.init, clazz, "<init>", "()V");
+ GET_METHOD_ID(gFields.arraylist.add, clazz, "add", "(Ljava/lang/Object;)Z");
+
+ FIND_CLASS(clazz, "java/util/HashMap");
+ GET_METHOD_ID(gFields.hashmap.init, clazz, "<init>", "()V");
+ GET_METHOD_ID(gFields.hashmap.get, clazz, "get", "(Ljava/lang/Object;)Ljava/lang/Object;");
+ GET_METHOD_ID(gFields.hashmap.put, clazz, "put",
+ "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+ GET_METHOD_ID(gFields.hashmap.entrySet, clazz, "entrySet", "()Ljava/util/Set;");
+
+ FIND_CLASS(clazz, "java/util/Set");
+ GET_METHOD_ID(gFields.set.iterator, clazz, "iterator", "()Ljava/util/Iterator;");
+
+ FIND_CLASS(clazz, "java/util/Iterator");
+ GET_METHOD_ID(gFields.iterator.next, clazz, "next", "()Ljava/lang/Object;");
+ GET_METHOD_ID(gFields.iterator.hasNext, clazz, "hasNext", "()Z");
+
+ FIND_CLASS(clazz, "java/util/Map$Entry");
+ GET_METHOD_ID(gFields.entry.getKey, clazz, "getKey", "()Ljava/lang/Object;");
+ GET_METHOD_ID(gFields.entry.getValue, clazz, "getValue", "()Ljava/lang/Object;");
+}
+
+static void android_media_MediaDrm_native_setup(
+ JNIEnv *env, jobject thiz,
+ jobject weak_this, jbyteArray uuidObj) {
+
+ if (uuidObj == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
+
+ if (uuid.size() != 16) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ sp<JDrm> drm = new JDrm(env, thiz, uuid.array());
+
+ status_t err = drm->initCheck();
+
+ if (err != OK) {
+ jniThrowException(
+ env,
+ "android/media/MediaDrmException",
+ "Failed to instantiate drm object.");
+ return;
+ }
+
+ setDrm(env, thiz, drm);
+}
+
+static void android_media_MediaDrm_native_finalize(
+ JNIEnv *env, jobject thiz) {
+ android_media_MediaDrm_release(env, thiz);
+}
+
+static jboolean android_media_MediaDrm_isCryptoSchemeSupportedNative(
+ JNIEnv *env, jobject thiz, jbyteArray uuidObj) {
+
+ if (uuidObj == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return false;
+ }
+
+ Vector<uint8_t> uuid = JByteArrayToVector(env, uuidObj);
+
+ if (uuid.size() != 16) {
+ jniThrowException(
+ env,
+ "java/lang/IllegalArgumentException",
+ NULL);
+ return false;
+ }
+
+ return JDrm::IsCryptoSchemeSupported(uuid.array());
+}
+
+static jbyteArray android_media_MediaDrm_openSession(
+ JNIEnv *env, jobject thiz) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (drm == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ Vector<uint8_t> sessionId;
+ status_t err = drm->openSession(sessionId);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to open session")) {
+ return NULL;
+ }
+
+ return VectorToJByteArray(env, sessionId);
+}
+
+static void android_media_MediaDrm_closeSession(
+ JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+ status_t err = drm->closeSession(sessionId);
+
+ throwExceptionAsNecessary(env, err, "Failed to close session");
+}
+
+static jobject android_media_MediaDrm_getLicenseRequest(
+ JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jinitData,
+ jstring jmimeType, jint jlicenseType, jobject joptParams) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return NULL;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+ Vector<uint8_t> initData;
+ if (jinitData != NULL) {
+ initData = JByteArrayToVector(env, jinitData);
+ }
+
+ String8 mimeType;
+ if (jmimeType != NULL) {
+ mimeType = JStringToString8(env, jmimeType);
+ }
+
+ DrmPlugin::LicenseType licenseType = (DrmPlugin::LicenseType)jlicenseType;
+
+ KeyedVector<String8, String8> optParams;
+ if (joptParams != NULL) {
+ optParams = HashMapToKeyedVector(env, joptParams);
+ }
+
+ Vector<uint8_t> request;
+ String8 defaultUrl;
+
+ status_t err = drm->getLicenseRequest(sessionId, initData, mimeType,
+ licenseType, optParams, request, defaultUrl);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to get license request")) {
+ return NULL;
+ }
+
+ // Fill out return obj
+ jclass clazz;
+ FIND_CLASS(clazz, "android/media/MediaDrm$LicenseRequest");
+
+ jobject licenseObj = NULL;
+
+ if (clazz) {
+ licenseObj = env->AllocObject(clazz);
+ jbyteArray jrequest = VectorToJByteArray(env, request);
+ env->SetObjectField(licenseObj, gFields.licenseRequest.data, jrequest);
+
+ jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
+ env->SetObjectField(licenseObj, gFields.licenseRequest.defaultUrl, jdefaultUrl);
+ }
+
+ return licenseObj;
+}
+
+static void android_media_MediaDrm_provideLicenseResponse(
+ JNIEnv *env, jobject thiz, jbyteArray jsessionId, jbyteArray jresponse) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+ if (jresponse == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+ Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
+
+ status_t err = drm->provideLicenseResponse(sessionId, response);
+
+ throwExceptionAsNecessary(env, err, "Failed to handle license response");
+}
+
+static void android_media_MediaDrm_removeLicense(
+ JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return;
+ }
+
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+ status_t err = drm->removeLicense(sessionId);
+
+ throwExceptionAsNecessary(env, err, "Failed to remove license");
+}
+
+static jobject android_media_MediaDrm_queryLicenseStatus(
+ JNIEnv *env, jobject thiz, jbyteArray jsessionId) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (!CheckSession(env, drm, jsessionId)) {
+ return NULL;
+ }
+ Vector<uint8_t> sessionId(JByteArrayToVector(env, jsessionId));
+
+ KeyedVector<String8, String8> infoMap;
+
+ status_t err = drm->queryLicenseStatus(sessionId, infoMap);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to query license")) {
+ return NULL;
+ }
+
+ return KeyedVectorToHashMap(env, infoMap);
+}
+
+static jobject android_media_MediaDrm_getProvisionRequest(
+ JNIEnv *env, jobject thiz) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (drm == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ Vector<uint8_t> request;
+ String8 defaultUrl;
+
+ status_t err = drm->getProvisionRequest(request, defaultUrl);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to get provision request")) {
+ return NULL;
+ }
+
+ // Fill out return obj
+ jclass clazz;
+ FIND_CLASS(clazz, "android/media/MediaDrm$ProvisionRequest");
+
+ jobject provisionObj = NULL;
+
+ if (clazz) {
+ provisionObj = env->AllocObject(clazz);
+ jbyteArray jrequest = VectorToJByteArray(env, request);
+ env->SetObjectField(provisionObj, gFields.provisionRequest.data, jrequest);
+
+ jstring jdefaultUrl = env->NewStringUTF(defaultUrl.string());
+ env->SetObjectField(provisionObj, gFields.provisionRequest.defaultUrl, jdefaultUrl);
+ }
+
+ return provisionObj;
+}
+
+static void android_media_MediaDrm_provideProvisionResponse(
+ JNIEnv *env, jobject thiz, jbyteArray jresponse) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (drm == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (jresponse == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ Vector<uint8_t> response(JByteArrayToVector(env, jresponse));
+
+ status_t err = drm->provideProvisionResponse(response);
+
+ throwExceptionAsNecessary(env, err, "Failed to handle provision response");
+}
+
+static jobject android_media_MediaDrm_getSecureStops(
+ JNIEnv *env, jobject thiz) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (drm == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ List<Vector<uint8_t> > secureStops;
+
+ status_t err = drm->getSecureStops(secureStops);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to get secure stops")) {
+ return NULL;
+ }
+
+ return ListOfVectorsToArrayListOfByteArray(env, secureStops);
+}
+
+static void android_media_MediaDrm_releaseSecureStops(
+ JNIEnv *env, jobject thiz, jbyteArray jssRelease) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (drm == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ Vector<uint8_t> ssRelease(JByteArrayToVector(env, jssRelease));
+
+ status_t err = drm->releaseSecureStops(ssRelease);
+
+ throwExceptionAsNecessary(env, err, "Failed to release secure stops");
+}
+
+static jstring android_media_MediaDrm_getPropertyString(
+ JNIEnv *env, jobject thiz, jstring jname) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (drm == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ if (jname == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return NULL;
+ }
+
+ String8 name = JStringToString8(env, jname);
+ String8 value;
+
+ status_t err = drm->getPropertyString(name, value);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
+ return NULL;
+ }
+
+ return env->NewStringUTF(value.string());
+}
+
+static jbyteArray android_media_MediaDrm_getPropertyByteArray(
+ JNIEnv *env, jobject thiz, jstring jname) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (drm == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return NULL;
+ }
+
+ if (jname == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return NULL;
+ }
+
+ String8 name = JStringToString8(env, jname);
+ Vector<uint8_t> value;
+
+ status_t err = drm->getPropertyByteArray(name, value);
+
+ if (throwExceptionAsNecessary(env, err, "Failed to get property")) {
+ return NULL;
+ }
+
+ return VectorToJByteArray(env, value);
+}
+
+static void android_media_MediaDrm_setPropertyString(
+ JNIEnv *env, jobject thiz, jstring jname, jstring jvalue) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (drm == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (jname == NULL || jvalue == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ String8 name = JStringToString8(env, jname);
+ String8 value = JStringToString8(env, jvalue);
+
+ status_t err = drm->setPropertyString(name, value);
+
+ throwExceptionAsNecessary(env, err, "Failed to set property");
+}
+
+static void android_media_MediaDrm_setPropertyByteArray(
+ JNIEnv *env, jobject thiz, jstring jname, jbyteArray jvalue) {
+ sp<IDrm> drm = GetDrm(env, thiz);
+
+ if (drm == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ return;
+ }
+
+ if (jname == NULL || jvalue == NULL) {
+ jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ return;
+ }
+
+ String8 name = JStringToString8(env, jname);
+ Vector<uint8_t> value = JByteArrayToVector(env, jvalue);
+
+ status_t err = drm->setPropertyByteArray(name, value);
+
+ throwExceptionAsNecessary(env, err, "Failed to set property");
+}
+
+
+static JNINativeMethod gMethods[] = {
+ { "release", "()V", (void *)android_media_MediaDrm_release },
+ { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
+
+ { "native_setup", "(Ljava/lang/Object;[B)V",
+ (void *)android_media_MediaDrm_native_setup },
+
+ { "native_finalize", "()V",
+ (void *)android_media_MediaDrm_native_finalize },
+
+ { "isCryptoSchemeSupportedNative", "([B)Z",
+ (void *)android_media_MediaDrm_isCryptoSchemeSupportedNative },
+
+ { "openSession", "()[B",
+ (void *)android_media_MediaDrm_openSession },
+
+ { "closeSession", "([B)V",
+ (void *)android_media_MediaDrm_closeSession },
+
+ { "getLicenseRequest", "([B[BLjava/lang/String;ILjava/util/HashMap;)"
+ "Landroid/media/MediaDrm$LicenseRequest;",
+ (void *)android_media_MediaDrm_getLicenseRequest },
+
+ { "provideLicenseResponse", "([B[B)V",
+ (void *)android_media_MediaDrm_provideLicenseResponse },
+
+ { "removeLicense", "([B)V",
+ (void *)android_media_MediaDrm_removeLicense },
+
+ { "queryLicenseStatus", "([B)Ljava/util/HashMap;",
+ (void *)android_media_MediaDrm_queryLicenseStatus },
+
+ { "getProvisionRequest", "()Landroid/media/MediaDrm$ProvisionRequest;",
+ (void *)android_media_MediaDrm_getProvisionRequest },
+
+ { "provideProvisionResponse", "([B)V",
+ (void *)android_media_MediaDrm_provideProvisionResponse },
+
+ { "getSecureStops", "()Ljava/util/List;",
+ (void *)android_media_MediaDrm_getSecureStops },
+
+ { "releaseSecureStops", "([B)V",
+ (void *)android_media_MediaDrm_releaseSecureStops },
+
+ { "getPropertyString", "(Ljava/lang/String;)Ljava/lang/String;",
+ (void *)android_media_MediaDrm_getPropertyString },
+
+ { "getPropertyByteArray", "(Ljava/lang/String;)[B",
+ (void *)android_media_MediaDrm_getPropertyByteArray },
+
+ { "setPropertyString", "(Ljava/lang/String;Ljava/lang/String;)V",
+ (void *)android_media_MediaDrm_setPropertyString },
+
+ { "setPropertyByteArray", "(Ljava/lang/String;[B)V",
+ (void *)android_media_MediaDrm_setPropertyByteArray },
+};
+
+int register_android_media_Drm(JNIEnv *env) {
+ return AndroidRuntime::registerNativeMethods(env,
+ "android/media/MediaDrm", gMethods, NELEM(gMethods));
+}
+
diff --git a/media/jni/android_media_MediaDrm.h b/media/jni/android_media_MediaDrm.h
new file mode 100644
index 0000000..01067c4
--- /dev/null
+++ b/media/jni/android_media_MediaDrm.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2013, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _ANDROID_MEDIA_DRM_H_
+#define _ANDROID_MEDIA_DRM_H_
+
+#include "jni.h"
+
+#include <media/stagefright/foundation/ABase.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+
+namespace android {
+
+struct IDrm;
+
+struct JDrm : public RefBase {
+ static bool IsCryptoSchemeSupported(const uint8_t uuid[16]);
+
+ JDrm(JNIEnv *env, jobject thiz, const uint8_t uuid[16]);
+
+ status_t initCheck() const;
+
+ sp<IDrm> getDrm() { return mDrm; }
+
+protected:
+ virtual ~JDrm();
+
+private:
+ jweak mObject;
+ sp<IDrm> mDrm;
+
+ static sp<IDrm> MakeDrm();
+ static sp<IDrm> MakeDrm(const uint8_t uuid[16]);
+
+ DISALLOW_EVIL_CONSTRUCTORS(JDrm);
+};
+
+} // namespace android
+
+#endif // _ANDROID_MEDIA_DRM_H_
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index 30ebb00..7517e85 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -146,6 +146,24 @@
return int(muxer.get());
}
+static void android_media_MediaMuxer_setOrientationHint(
+ JNIEnv *env, jclass clazz, jint nativeObject, jint degrees) {
+ sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
+ if (muxer == NULL) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Muxer was not set up correctly");
+ return;
+ }
+ status_t err = muxer->setOrientationHint(degrees);
+
+ if (err != OK) {
+ jniThrowException(env, "java/lang/IllegalStateException",
+ "Failed to set orientation hint");
+ return;
+ }
+
+}
+
static void android_media_MediaMuxer_start(JNIEnv *env, jclass clazz,
jint nativeObject) {
sp<MediaMuxer> muxer(reinterpret_cast<MediaMuxer *>(nativeObject));
@@ -195,6 +213,9 @@
{ "nativeAddTrack", "(I[Ljava/lang/String;[Ljava/lang/Object;)I",
(void *)android_media_MediaMuxer_addTrack },
+ { "nativeSetOrientationHint", "(II)V",
+ (void *)android_media_MediaMuxer_setOrientationHint},
+
{ "nativeStart", "(I)V", (void *)android_media_MediaMuxer_start},
{ "nativeWriteSampleData", "(IILjava/nio/ByteBuffer;IIJI)V",
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index e9f6a1e..c5098ce 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -879,6 +879,7 @@
}
extern int register_android_media_Crypto(JNIEnv *env);
+extern int register_android_media_Drm(JNIEnv *env);
extern int register_android_media_MediaCodec(JNIEnv *env);
extern int register_android_media_MediaExtractor(JNIEnv *env);
extern int register_android_media_MediaCodecList(JNIEnv *env);
@@ -979,6 +980,11 @@
goto bail;
}
+ if (register_android_media_Drm(env) < 0) {
+ ALOGE("ERROR: MediaDrm native registration failed");
+ goto bail;
+ }
+
/* success -- return valid version number */
result = JNI_VERSION_1_4;
diff --git a/packages/Shell/src/com/android/shell/BugreportReceiver.java b/packages/Shell/src/com/android/shell/BugreportReceiver.java
index de04909..7a659ee 100644
--- a/packages/Shell/src/com/android/shell/BugreportReceiver.java
+++ b/packages/Shell/src/com/android/shell/BugreportReceiver.java
@@ -87,6 +87,7 @@
final Notification.Builder builder = new Notification.Builder(context);
builder.setSmallIcon(com.android.internal.R.drawable.stat_sys_adb);
builder.setContentTitle(context.getString(R.string.bugreport_finished_title));
+ builder.setTicker(context.getString(R.string.bugreport_finished_title));
builder.setContentText(context.getString(R.string.bugreport_finished_text));
builder.setContentIntent(PendingIntent.getActivity(
context, 0, notifIntent, PendingIntent.FLAG_CANCEL_CURRENT));
diff --git a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
index b51b333..b06166d 100644
--- a/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout-land/status_bar_recent_panel.xml
@@ -41,7 +41,8 @@
android:fadingEdge="horizontal"
android:scrollbars="none"
android:layout_gravity="right"
- android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length">
+ android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length"
+ android:fitsSystemWindows="true">
<LinearLayout android:id="@+id/recents_linear_layout"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/layout/status_bar_recent_panel.xml b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
index 4bbe277..305aaf2 100644
--- a/packages/SystemUI/res/layout/status_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/status_bar_recent_panel.xml
@@ -45,7 +45,8 @@
android:fadingEdgeLength="@dimen/status_bar_recents_scroll_fading_edge_length"
android:layout_gravity="bottom|start"
android:clipToPadding="false"
- android:clipChildren="false">
+ android:clipChildren="false"
+ android:fitsSystemWindows="true">
<LinearLayout android:id="@+id/recents_linear_layout"
android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/system_bar_recent_panel.xml b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
index aed8a8c..3d15d9b 100644
--- a/packages/SystemUI/res/layout/system_bar_recent_panel.xml
+++ b/packages/SystemUI/res/layout/system_bar_recent_panel.xml
@@ -49,7 +49,8 @@
android:fadingEdgeLength="20dip"
android:layout_gravity="bottom|start"
android:clipToPadding="false"
- android:clipChildren="false">
+ android:clipChildren="false"
+ android:fitsSystemWindows="true">
<LinearLayout android:id="@+id/recents_linear_layout"
android:layout_width="wrap_content"
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
index 676326a..c325937 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsActivity.java
@@ -177,6 +177,7 @@
setContentView(R.layout.status_bar_recent_panel);
mRecentsPanel = (RecentsPanelView) findViewById(R.id.recents_root);
mRecentsPanel.setOnTouchListener(new TouchOutsideListener(mRecentsPanel));
+ mRecentsPanel.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);
final RecentTasksLoader recentTasksLoader = RecentTasksLoader.getInstance(this);
recentTasksLoader.setRecentsPanel(mRecentsPanel, mRecentsPanel);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 3330301..217b7fd 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -256,7 +256,7 @@
mPerformanceHelper.drawCallback(canvas,
left, right, top, bottom, mScrollX, mScrollY,
0, 0,
- getLeftFadingEdgeStrength(), getRightFadingEdgeStrength());
+ getLeftFadingEdgeStrength(), getRightFadingEdgeStrength(), mPaddingTop);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
index 71cc1e4..f17766b 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
@@ -38,6 +38,10 @@
private int mFadingEdgeLength;
private boolean mIsVertical;
private boolean mSoftwareRendered = false;
+ private Paint mBlackPaint;
+ private Paint mFadePaint;
+ private Matrix mFadeMatrix;
+ private LinearGradient mFade;
public static RecentsScrollViewPerformanceHelper create(Context context,
AttributeSet attrs, View scrollView, boolean isVertical) {
@@ -81,18 +85,19 @@
public void drawCallback(Canvas canvas,
int left, int right, int top, int bottom, int scrollX, int scrollY,
float topFadingEdgeStrength, float bottomFadingEdgeStrength,
- float leftFadingEdgeStrength, float rightFadingEdgeStrength) {
+ float leftFadingEdgeStrength, float rightFadingEdgeStrength, int mPaddingTop) {
if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
|| USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
- Paint p = new Paint();
- Matrix matrix = new Matrix();
- // use use a height of 1, and then wack the matrix each time we
- // actually use it.
- Shader fade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
- // PULL OUT THIS CONSTANT
-
- p.setShader(fade);
+ if (mFadePaint == null) {
+ mFadePaint = new Paint();
+ mFadeMatrix = new Matrix();
+ // use use a height of 1, and then wack the matrix each time we
+ // actually use it.
+ mFade = new LinearGradient(0, 0, 0, 1, 0xCC000000, 0, Shader.TileMode.CLAMP);
+ // PULL OUT THIS CONSTANT
+ mFadePaint.setShader(mFade);
+ }
// draw the fade effect
boolean drawTop = false;
@@ -134,34 +139,41 @@
}
if (drawTop) {
- matrix.setScale(1, fadeHeight * topFadeStrength);
- matrix.postTranslate(left, top);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(left, top, right, top + length, p);
+ mFadeMatrix.setScale(1, fadeHeight * topFadeStrength);
+ mFadeMatrix.postTranslate(left, top);
+ mFade.setLocalMatrix(mFadeMatrix);
+ canvas.drawRect(left, top, right, top + length, mFadePaint);
+
+ if (mBlackPaint == null) {
+ // Draw under the status bar at the top
+ mBlackPaint = new Paint();
+ mBlackPaint.setColor(0xFF000000);
+ }
+ canvas.drawRect(left, top - mPaddingTop, right, top, mBlackPaint);
}
if (drawBottom) {
- matrix.setScale(1, fadeHeight * bottomFadeStrength);
- matrix.postRotate(180);
- matrix.postTranslate(left, bottom);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(left, bottom - length, right, bottom, p);
+ mFadeMatrix.setScale(1, fadeHeight * bottomFadeStrength);
+ mFadeMatrix.postRotate(180);
+ mFadeMatrix.postTranslate(left, bottom);
+ mFade.setLocalMatrix(mFadeMatrix);
+ canvas.drawRect(left, bottom - length, right, bottom, mFadePaint);
}
if (drawLeft) {
- matrix.setScale(1, fadeHeight * leftFadeStrength);
- matrix.postRotate(-90);
- matrix.postTranslate(left, top);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(left, top, left + length, bottom, p);
+ mFadeMatrix.setScale(1, fadeHeight * leftFadeStrength);
+ mFadeMatrix.postRotate(-90);
+ mFadeMatrix.postTranslate(left, top);
+ mFade.setLocalMatrix(mFadeMatrix);
+ canvas.drawRect(left, top, left + length, bottom, mFadePaint);
}
if (drawRight) {
- matrix.setScale(1, fadeHeight * rightFadeStrength);
- matrix.postRotate(90);
- matrix.postTranslate(right, top);
- fade.setLocalMatrix(matrix);
- canvas.drawRect(right - length, top, right, bottom, p);
+ mFadeMatrix.setScale(1, fadeHeight * rightFadeStrength);
+ mFadeMatrix.postRotate(90);
+ mFadeMatrix.postTranslate(right, top);
+ mFade.setLocalMatrix(mFadeMatrix);
+ canvas.drawRect(right - length, top, right, bottom, mFadePaint);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index b3adbaf..403c643f 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -21,6 +21,7 @@
import android.content.res.Configuration;
import android.database.DataSetObserver;
import android.graphics.Canvas;
+import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.FloatMath;
@@ -68,7 +69,7 @@
}
private int scrollPositionOfMostRecent() {
- return mLinearLayout.getHeight() - getHeight();
+ return mLinearLayout.getHeight() - getHeight() + mPaddingTop;
}
private void addToRecycledViews(View v) {
@@ -265,7 +266,7 @@
mPerformanceHelper.drawCallback(canvas,
left, right, top, bottom, mScrollX, mScrollY,
getTopFadingEdgeStrength(), getBottomFadingEdgeStrength(),
- 0, 0);
+ 0, 0, mPaddingTop);
}
}
diff --git a/tests/BiDiTests/res/layout/canvas.xml b/tests/BiDiTests/res/layout/canvas.xml
deleted file mode 100644
index 0319a83..0000000
--- a/tests/BiDiTests/res/layout/canvas.xml
+++ /dev/null
@@ -1,40 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2011 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-
-<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:id="@+id/canvas"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent">
-
- <LinearLayout android:orientation="vertical"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
-
- <SeekBar android:id="@+id/seekbar"
- android:layout_height="wrap_content"
- android:layout_width="match_parent"
- />
-
- <view class="com.android.bidi.BiDiTestView"
- android:id="@+id/testview"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="#FF0000"
- />
-
- </LinearLayout>
-
-</FrameLayout>
\ No newline at end of file
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
index 209597e..b88a885 100644
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
+++ b/tests/BiDiTests/src/com/android/bidi/BiDiTestActivity.java
@@ -101,7 +101,6 @@
addItem(result, "Basic", BiDiTestBasic.class, R.id.basic);
- addItem(result, "Canvas", BiDiTestCanvas.class, R.id.canvas);
addItem(result, "Canvas2", BiDiTestCanvas2.class, R.id.canvas2);
addItem(result, "TextView LTR", BiDiTestTextViewLtr.class, R.id.textview_ltr);
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
deleted file mode 100644
index 33ed731..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestCanvas.java
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * 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.bidi;
-
-import android.app.Fragment;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.SeekBar;
-
-import static com.android.bidi.BiDiTestConstants.FONT_MAX_SIZE;
-import static com.android.bidi.BiDiTestConstants.FONT_MIN_SIZE;
-
-public class BiDiTestCanvas extends Fragment {
-
- static final int INIT_TEXT_SIZE = (FONT_MAX_SIZE - FONT_MIN_SIZE) / 2;
-
- private BiDiTestView testView;
- private SeekBar textSizeSeekBar;
- private View currentView;
-
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- currentView = inflater.inflate(R.layout.canvas, container, false);
- return currentView;
- }
-
- @Override
- public void onViewCreated(View view, Bundle savedInstanceState) {
- super.onViewCreated(view, savedInstanceState);
-
- testView = (BiDiTestView) currentView.findViewById(R.id.testview);
- testView.setCurrentTextSize(INIT_TEXT_SIZE);
-
- textSizeSeekBar = (SeekBar) currentView.findViewById(R.id.seekbar);
- textSizeSeekBar.setProgress(INIT_TEXT_SIZE);
- textSizeSeekBar.setMax(FONT_MAX_SIZE - FONT_MIN_SIZE);
-
- textSizeSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
- public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
- testView.setCurrentTextSize(FONT_MIN_SIZE + progress);
- }
-
- public void onStartTrackingTouch(SeekBar seekBar) {
- }
-
- public void onStopTrackingTouch(SeekBar seekBar) {
- }
- });
- }
-}
diff --git a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java b/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
deleted file mode 100644
index 0b1974a..0000000
--- a/tests/BiDiTests/src/com/android/bidi/BiDiTestView.java
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * 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.bidi;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.text.TextPaint;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.view.View;
-
-public class BiDiTestView extends View {
-
- private static final String TAG = "BiDiTestView";
-
- private static final int BORDER_PADDING = 4;
- private static final int TEXT_PADDING = 16;
- private static final int TEXT_SIZE = 16;
- private static final int ORIGIN = 80;
-
- private static final float DEFAULT_ITALIC_SKEW_X = -0.25f;
-
- private Rect rect = new Rect();
-
- private String NORMAL_TEXT;
- private String NORMAL_LONG_TEXT;
- private String NORMAL_LONG_TEXT_2;
- private String NORMAL_LONG_TEXT_3;
- private String ITALIC_TEXT;
- private String BOLD_TEXT;
- private String BOLD_ITALIC_TEXT;
- private String ARABIC_TEXT;
- private String CHINESE_TEXT;
- private String MIXED_TEXT_1;
- private String HEBREW_TEXT;
- private String RTL_TEXT;
- private String THAI_TEXT;
-
- private int currentTextSize;
-
- public BiDiTestView(Context context) {
- super(context);
- init(context);
- }
-
- public BiDiTestView(Context context, AttributeSet attrs) {
- super(context, attrs);
- init(context);
- }
-
- public BiDiTestView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- init(context);
- }
-
- private void init(Context context) {
- NORMAL_TEXT = context.getString(R.string.normal_text);
- NORMAL_LONG_TEXT = context.getString(R.string.normal_long_text);
- NORMAL_LONG_TEXT_2 = context.getString(R.string.normal_long_text_2);
- NORMAL_LONG_TEXT_3 = context.getString(R.string.normal_long_text_3);
- ITALIC_TEXT = context.getString(R.string.italic_text);
- BOLD_TEXT = context.getString(R.string.bold_text);
- BOLD_ITALIC_TEXT = context.getString(R.string.bold_italic_text);
- ARABIC_TEXT = context.getString(R.string.arabic_text);
- CHINESE_TEXT = context.getString(R.string.chinese_text);
- MIXED_TEXT_1 = context.getString(R.string.mixed_text_1);
- HEBREW_TEXT = context.getString(R.string.hebrew_text);
- RTL_TEXT = context.getString(R.string.rtl);
- THAI_TEXT = context.getString(R.string.pointer_location);
- }
-
- public void setCurrentTextSize(int size) {
- currentTextSize = size;
- invalidate();
- }
-
- @Override
- public void onDraw(Canvas canvas) {
- drawInsideRect(canvas, new Paint(), Color.BLACK);
-
- int deltaX = 0;
-
- deltaX = testString(canvas, NORMAL_TEXT, ORIGIN, ORIGIN,
- false, false, Paint.DIRECTION_LTR, currentTextSize);
-
- deltaX += testString(canvas, ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
- true, false, Paint.DIRECTION_LTR, currentTextSize);
-
- deltaX += testString(canvas, BOLD_TEXT, ORIGIN + deltaX, ORIGIN,
- false, true, Paint.DIRECTION_LTR, currentTextSize);
-
- deltaX += testString(canvas, BOLD_ITALIC_TEXT, ORIGIN + deltaX, ORIGIN,
- true, true, Paint.DIRECTION_LTR, currentTextSize);
-
- // Test with a long string
- deltaX = testString(canvas, NORMAL_LONG_TEXT, ORIGIN, ORIGIN + 2 * currentTextSize,
- false, false, Paint.DIRECTION_LTR, currentTextSize);
-
- // Test with a long string
- deltaX = testString(canvas, NORMAL_LONG_TEXT_2, ORIGIN, ORIGIN + 4 * currentTextSize,
- false, false, Paint.DIRECTION_LTR, currentTextSize);
-
- // Test with a long string
- deltaX = testString(canvas, NORMAL_LONG_TEXT_3, ORIGIN, ORIGIN + 6 * currentTextSize,
- false, false, Paint.DIRECTION_LTR, currentTextSize);
-
- // Test Arabic ligature
- deltaX = testString(canvas, ARABIC_TEXT, ORIGIN, ORIGIN + 8 * currentTextSize,
- false, false, Paint.DIRECTION_RTL, currentTextSize);
-
- // Test Chinese
- deltaX = testString(canvas, CHINESE_TEXT, ORIGIN, ORIGIN + 10 * currentTextSize,
- false, false, Paint.DIRECTION_LTR, currentTextSize);
-
- // Test Mixed (English and Arabic)
- deltaX = testString(canvas, MIXED_TEXT_1, ORIGIN, ORIGIN + 12 * currentTextSize,
- false, false, Paint.DIRECTION_LTR, currentTextSize);
-
- // Test Hebrew
- deltaX = testString(canvas, RTL_TEXT, ORIGIN, ORIGIN + 14 * currentTextSize,
- false, false, Paint.DIRECTION_RTL, currentTextSize);
-
- // Test Thai
- deltaX = testString(canvas, THAI_TEXT, ORIGIN, ORIGIN + 16 * currentTextSize,
- false, false, Paint.DIRECTION_LTR, currentTextSize);
- }
-
- private int testString(Canvas canvas, String text, int x, int y,
- boolean isItalic, boolean isBold, int dir, int textSize) {
-
- TextPaint paint = new TextPaint();
- paint.setAntiAlias(true);
-
- // Set paint properties
- boolean oldFakeBold = paint.isFakeBoldText();
- paint.setFakeBoldText(isBold);
-
- float oldTextSkewX = paint.getTextSkewX();
- if (isItalic) {
- paint.setTextSkewX(DEFAULT_ITALIC_SKEW_X);
- }
-
- paint.setTextSize(textSize);
- paint.setColor(Color.WHITE);
- canvas.drawText(text, x, y, paint);
-
- int length = text.length();
- float[] advances = new float[length];
- float textWidthHB = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0);
- setPaintDir(paint, dir);
- float textWidthICU = paint.getTextRunAdvances(text, 0, length, 0, length, dir, advances, 0,
- 1 /* use ICU */);
-
- logAdvances(text, textWidthHB, textWidthICU, advances);
- drawMetricsAroundText(canvas, x, y, textWidthHB, textWidthICU, textSize, Color.RED, Color.GREEN);
-
- // Restore old paint properties
- paint.setFakeBoldText(oldFakeBold);
- paint.setTextSkewX(oldTextSkewX);
-
- return (int) Math.ceil(textWidthHB) + TEXT_PADDING;
- }
-
- private void setPaintDir(Paint paint, int dir) {
- Log.v(TAG, "Setting Paint dir=" + dir);
- paint.setBidiFlags(dir);
- }
-
- private void drawInsideRect(Canvas canvas, Paint paint, int color) {
- paint.setColor(color);
- int width = getWidth();
- int height = getHeight();
- rect.set(BORDER_PADDING, BORDER_PADDING, width - BORDER_PADDING, height - BORDER_PADDING);
- canvas.drawRect(rect, paint);
- }
-
- private void drawMetricsAroundText(Canvas canvas, int x, int y, float textWidthHB,
- float textWidthICU, int textSize, int color, int colorICU) {
- Paint paint = new Paint();
- paint.setColor(color);
- canvas.drawLine(x, y - textSize, x, y + 8, paint);
- canvas.drawLine(x, y + 8, x + textWidthHB, y + 8, paint);
- canvas.drawLine(x + textWidthHB, y - textSize, x + textWidthHB, y + 8, paint);
- paint.setColor(colorICU);
- canvas.drawLine(x + textWidthICU, y - textSize, x + textWidthICU, y + 8, paint);
- }
-
- private void logAdvances(String text, float textWidth, float textWidthICU, float[] advances) {
- Log.v(TAG, "Advances for text: " + text + " total= " + textWidth + " - totalICU= " + textWidthICU);
-// int length = advances.length;
-// for(int n=0; n<length; n++){
-// Log.v(TAG, "adv[" + n + "]=" + advances[n]);
-// }
- }
-}