Merge "TIF: Make TvContract URI consistent" into lmp-dev
diff --git a/core/res/res/raw/color_fade_frag.frag b/core/res/res/raw/color_fade_frag.frag
new file mode 100644
index 0000000..a66a5a7
--- /dev/null
+++ b/core/res/res/raw/color_fade_frag.frag
@@ -0,0 +1,42 @@
+#extension GL_OES_EGL_image_external : require
+
+precision mediump float;
+uniform samplerExternalOES texUnit;
+uniform float opacity;
+uniform float saturation;
+uniform float gamma;
+varying vec2 UV;
+
+vec3 rgb2hsl(vec3 rgb)
+{
+ float e = 1.0e-7;
+
+ vec4 p = rgb.g < rgb.b ? vec4(rgb.bg, -1.0, 2.0 / 3.0) : vec4(rgb.gb, 0.0, -1.0 / 3.0);
+ vec4 q = rgb.r < p.x ? vec4(p.xyw, rgb.r) : vec4(rgb.r, p.yzx);
+
+ float v = q.x;
+ float c = v - min(q.w, q.y);
+ float h = abs((q.w - q.y) / (6.0 * c + e) + q.z);
+ float l = v - c * 0.5;
+ float s = c / (1.0 - abs(2.0 * l - 1.0) + e);
+ return clamp(vec3(h, s, l), 0.0, 1.0);
+}
+
+vec3 hsl2rgb(vec3 hsl)
+{
+ vec3 h = vec3(hsl.x * 6.0);
+ vec3 p = abs(h - vec3(3.0, 2.0, 4.0));
+ vec3 q = 2.0 - p;
+
+ vec3 rgb = clamp(vec3(p.x - 1.0, q.yz), 0.0, 1.0);
+ float c = (1.0 - abs(2.0 * hsl.z - 1.0)) * hsl.y;
+ return (rgb - vec3(0.5)) * c + hsl.z;
+}
+
+void main()
+{
+ vec4 color = texture2D(texUnit, UV);
+ vec3 hsl = rgb2hsl(color.xyz);
+ vec3 rgb = pow(hsl2rgb(vec3(hsl.x, hsl.y * saturation, hsl.z * opacity)), vec3(gamma));
+ gl_FragColor = vec4(rgb, 1.0);
+}
diff --git a/core/res/res/raw/color_fade_vert.vert b/core/res/res/raw/color_fade_vert.vert
new file mode 100644
index 0000000..d17437f
--- /dev/null
+++ b/core/res/res/raw/color_fade_vert.vert
@@ -0,0 +1,13 @@
+uniform mat4 proj_matrix;
+uniform mat4 tex_matrix;
+uniform float scale;
+attribute vec2 position;
+attribute vec2 uv;
+varying vec2 UV;
+
+void main()
+{
+ vec4 transformed_uv = tex_matrix * vec4(uv.x, uv.y, 1.0, 1.0);
+ UV = transformed_uv.st / transformed_uv.q;
+ gl_Position = vec4(scale, scale, 1.0, 1.0) * (proj_matrix * vec4(position.x, position.y, 0.0, 1.0));
+}
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 110ddb1..250711e 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1266,6 +1266,8 @@
<java-symbol type="xml" name="default_zen_mode_config" />
<java-symbol type="xml" name="tv_content_rating_systems" />
+ <java-symbol type="raw" name="color_fade_vert" />
+ <java-symbol type="raw" name="color_fade_frag" />
<java-symbol type="raw" name="accessibility_gestures" />
<java-symbol type="raw" name="incognito_mode_start_page" />
<java-symbol type="raw" name="loaderror" />
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index d033f76..f1e1099 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -58,12 +58,17 @@
EVENT_SET_CALLBACK = 2,
};
-struct CryptoErrorCodes {
+static struct CryptoErrorCodes {
jint cryptoErrorNoKey;
jint cryptoErrorKeyExpired;
jint cryptoErrorResourceBusy;
} gCryptoErrorCodes;
+static struct CodecActionCodes {
+ jint codecActionTransient;
+ jint codecActionRecoverable;
+} gCodecActionCodes;
+
struct fields_t {
jfieldID context;
jmethodID postEventFromNativeID;
@@ -101,10 +106,11 @@
PRIORITY_FOREGROUND);
if (nameIsType) {
- mCodec = MediaCodec::CreateByType(mLooper, name, encoder);
+ mCodec = MediaCodec::CreateByType(mLooper, name, encoder, &mInitStatus);
} else {
- mCodec = MediaCodec::CreateByComponentName(mLooper, name);
+ mCodec = MediaCodec::CreateByComponentName(mLooper, name, &mInitStatus);
}
+ CHECK((mCodec != NULL) != (mInitStatus != OK));
}
void JMediaCodec::cacheJavaObjects(JNIEnv *env) {
@@ -147,7 +153,7 @@
}
status_t JMediaCodec::initCheck() const {
- return mCodec != NULL ? OK : NO_INIT;
+ return mInitStatus;
}
void JMediaCodec::registerSelf() {
@@ -158,6 +164,7 @@
if (mCodec != NULL) {
mCodec->release();
mCodec.clear();
+ mInitStatus = NO_INIT;
}
if (mLooper != NULL) {
@@ -554,6 +561,34 @@
}
}
+static jthrowable createCodecException(
+ JNIEnv *env, status_t err, int32_t actionCode, const char *msg = NULL) {
+ ScopedLocalRef<jclass> clazz(
+ env, env->FindClass("android/media/MediaCodec$CodecException"));
+ CHECK(clazz.get() != NULL);
+
+ const jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
+ CHECK(ctor != NULL);
+
+ ScopedLocalRef<jstring> msgObj(
+ env, env->NewStringUTF(msg != NULL ? msg : String8::format("Error %#x", err)));
+
+ // translate action code to Java equivalent
+ switch (actionCode) {
+ case ACTION_CODE_TRANSIENT:
+ actionCode = gCodecActionCodes.codecActionTransient;
+ break;
+ case ACTION_CODE_RECOVERABLE:
+ actionCode = gCodecActionCodes.codecActionRecoverable;
+ break;
+ default:
+ actionCode = 0; // everything else is fatal
+ break;
+ }
+
+ return (jthrowable)env->NewObject(clazz.get(), ctor, err, actionCode, msgObj.get());
+}
+
void JMediaCodec::handleCallback(const sp<AMessage> &msg) {
int32_t arg1, arg2 = 0;
jobject obj = NULL;
@@ -605,19 +640,8 @@
CHECK(msg->findInt32("err", &err));
CHECK(msg->findInt32("actionCode", &actionCode));
- // use Integer object to pass the action code
- ScopedLocalRef<jclass> clazz(
- env, env->FindClass("android/media/MediaCodec$CodecException"));
- jmethodID ctor = env->GetMethodID(clazz.get(), "<init>", "(IILjava/lang/String;)V");
-
- AString str;
- const char *detail = "Unknown error";
- if (msg->findString("detail", &str)) {
- detail = str.c_str();
- }
- jstring msgObj = env->NewStringUTF(detail);
-
- obj = env->NewObject(clazz.get(), ctor, err, actionCode, msgObj);
+ // note that DRM errors could conceivably alias into a CodecException
+ obj = (jobject)createCodecException(env, err, actionCode);
if (obj == NULL) {
if (env->ExceptionCheck()) {
@@ -705,6 +729,11 @@
setMediaCodec(env, thiz, NULL);
}
+static void throwCodecException(JNIEnv *env, status_t err, int32_t actionCode, const char *msg) {
+ jthrowable exception = createCodecException(env, err, actionCode, msg);
+ env->Throw(exception);
+}
+
static void throwCryptoException(JNIEnv *env, status_t err, const char *msg) {
ScopedLocalRef<jclass> clazz(
env, env->FindClass("android/media/MediaCodec$CryptoException"));
@@ -716,7 +745,7 @@
jstring msgObj = env->NewStringUTF(msg != NULL ? msg : "Unknown Error");
- /* translate OS errors to Java API CryptoException errorCodes */
+ /* translate OS errors to Java API CryptoException errorCodes (which are positive) */
switch (err) {
case ERROR_DRM_NO_LICENSE:
err = gCryptoErrorCodes.cryptoErrorNoKey;
@@ -727,7 +756,7 @@
case ERROR_DRM_RESOURCE_BUSY:
err = gCryptoErrorCodes.cryptoErrorResourceBusy;
break;
- default:
+ default: /* Other negative DRM error codes go out as is. */
break;
}
@@ -738,13 +767,8 @@
}
static jint throwExceptionAsNecessary(
- JNIEnv *env, status_t err, const char *msg = NULL) {
- if (err >= ERROR_DRM_VENDOR_MIN && err <= ERROR_DRM_VENDOR_MAX) {
- // We'll throw our custom MediaCodec.CryptoException
- throwCryptoException(env, err, msg);
- return 0;
- }
-
+ JNIEnv *env, status_t err, int32_t actionCode = ACTION_CODE_FATAL,
+ const char *msg = NULL) {
switch (err) {
case OK:
return 0;
@@ -758,20 +782,18 @@
case INFO_OUTPUT_BUFFERS_CHANGED:
return DEQUEUE_INFO_OUTPUT_BUFFERS_CHANGED;
- case ERROR_DRM_NO_LICENSE:
- case ERROR_DRM_LICENSE_EXPIRED:
- case ERROR_DRM_RESOURCE_BUSY:
- throwCryptoException(env, err, msg);
- break;
+ case INVALID_OPERATION:
+ jniThrowException(env, "java/lang/IllegalStateException", msg);
+ return 0;
default:
- {
- jniThrowException(env, "java/lang/IllegalStateException", msg);
- break;
- }
+ if (isCryptoError(err)) {
+ throwCryptoException(env, err, msg);
+ return 0;
+ }
+ throwCodecException(env, err, actionCode, msg);
+ return 0;
}
-
- return 0;
}
static void android_media_MediaCodec_native_setCallback(
@@ -781,7 +803,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -800,7 +822,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -842,7 +864,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -865,13 +887,13 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", "no codec found");
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
status_t err = codec->start();
- throwExceptionAsNecessary(env, err, "start failed");
+ throwExceptionAsNecessary(env, err, ACTION_CODE_FATAL, "start failed");
}
static void android_media_MediaCodec_stop(JNIEnv *env, jobject thiz) {
@@ -880,7 +902,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -895,8 +917,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- // should never be here
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -904,7 +925,10 @@
if (err != OK) {
// treat all errors as fatal for now, though resource not available
// errors could be treated as transient.
- err = 0x80000000;
+ // we also should avoid sending INVALID_OPERATION here due to
+ // the transitory nature of reset(), it should not inadvertently
+ // trigger an IllegalStateException.
+ err = UNKNOWN_ERROR;
}
throwExceptionAsNecessary(env, err);
}
@@ -915,7 +939,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -937,7 +961,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -947,7 +971,7 @@
index, offset, size, timestampUs, flags, &errorDetailMsg);
throwExceptionAsNecessary(
- env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
+ env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
}
static void android_media_MediaCodec_queueSecureInputBuffer(
@@ -963,7 +987,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1005,7 +1029,7 @@
err = -ERANGE;
// subSamples array may silently overflow if number of samples are too large. Use
// INT32_MAX as maximum allocation size may be less than SIZE_MAX on some platforms
- } else if ( CC_UNLIKELY(numSubSamples >= INT32_MAX / sizeof(*subSamples)) ) {
+ } else if ( CC_UNLIKELY(numSubSamples >= (signed)(INT32_MAX / sizeof(*subSamples))) ) {
err = -EINVAL;
} else {
jboolean isCopy;
@@ -1089,7 +1113,7 @@
subSamples = NULL;
throwExceptionAsNecessary(
- env, err, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
+ env, err, ACTION_CODE_FATAL, errorDetailMsg.empty() ? NULL : errorDetailMsg.c_str());
}
static jint android_media_MediaCodec_dequeueInputBuffer(
@@ -1099,7 +1123,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return -1;
}
@@ -1120,7 +1144,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return 0;
}
@@ -1143,7 +1167,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1158,7 +1182,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1174,7 +1198,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -1197,7 +1221,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -1220,7 +1244,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -1246,7 +1270,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -1272,7 +1296,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -1298,7 +1322,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return NULL;
}
@@ -1321,7 +1345,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1340,7 +1364,7 @@
sp<JMediaCodec> codec = getMediaCodec(env, thiz);
if (codec == NULL) {
- jniThrowException(env, "java/lang/IllegalStateException", NULL);
+ throwExceptionAsNecessary(env, INVALID_OPERATION);
return;
}
@@ -1409,13 +1433,25 @@
CHECK(field != NULL);
gCryptoErrorCodes.cryptoErrorResourceBusy =
env->GetStaticIntField(clazz.get(), field);
+
+ clazz.reset(env->FindClass("android/media/MediaCodec$CodecException"));
+ CHECK(clazz.get() != NULL);
+ field = env->GetStaticFieldID(clazz.get(), "ACTION_TRANSIENT", "I");
+ CHECK(field != NULL);
+ gCodecActionCodes.codecActionTransient =
+ env->GetStaticIntField(clazz.get(), field);
+
+ field = env->GetStaticFieldID(clazz.get(), "ACTION_RECOVERABLE", "I");
+ CHECK(field != NULL);
+ gCodecActionCodes.codecActionRecoverable =
+ env->GetStaticIntField(clazz.get(), field);
}
static void android_media_MediaCodec_native_setup(
JNIEnv *env, jobject thiz,
jstring name, jboolean nameIsType, jboolean encoder) {
if (name == NULL) {
- jniThrowException(env, "java/lang/IllegalArgumentException", NULL);
+ jniThrowException(env, "java/lang/NullPointerException", NULL);
return;
}
@@ -1427,19 +1463,23 @@
sp<JMediaCodec> codec = new JMediaCodec(env, thiz, tmp, nameIsType, encoder);
- status_t err = codec->initCheck();
-
- env->ReleaseStringUTFChars(name, tmp);
- tmp = NULL;
-
- if (err != OK) {
- jniThrowException(
- env,
- "java/io/IOException",
- "Failed to allocate component instance");
+ const status_t err = codec->initCheck();
+ if (err == NAME_NOT_FOUND) {
+ // fail and do not try again.
+ jniThrowException(env, "java/lang/IllegalArgumentException",
+ String8::format("Failed to initialize %s, error %#x", tmp, err));
+ env->ReleaseStringUTFChars(name, tmp);
+ return;
+ } else if (err != OK) {
+ // believed possible to try again
+ jniThrowException(env, "java/io/IOException",
+ String8::format("Failed to find matching codec %s, error %#x", tmp, err));
+ env->ReleaseStringUTFChars(name, tmp);
return;
}
+ env->ReleaseStringUTFChars(name, tmp);
+
codec->registerSelf();
setMediaCodec(env,thiz, codec);
diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h
index f84a16a..9f2785a 100644
--- a/media/jni/android_media_MediaCodec.h
+++ b/media/jni/android_media_MediaCodec.h
@@ -135,6 +135,8 @@
sp<AMessage> mCallbackNotification;
+ status_t mInitStatus;
+
status_t createByteBufferFromABuffer(
JNIEnv *env, bool readOnly, bool clearBuffer, const sp<ABuffer> &buffer,
jobject *buf) const;
diff --git a/packages/SystemUI/res/layout/data_usage.xml b/packages/SystemUI/res/layout/data_usage.xml
index 63d22b2..8831a05 100644
--- a/packages/SystemUI/res/layout/data_usage.xml
+++ b/packages/SystemUI/res/layout/data_usage.xml
@@ -17,6 +17,9 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:paddingTop="16dp"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp"
android:orientation="vertical" >
<TextView
diff --git a/packages/SystemUI/res/layout/qs_detail.xml b/packages/SystemUI/res/layout/qs_detail.xml
index c6a7368..5869bf3 100644
--- a/packages/SystemUI/res/layout/qs_detail.xml
+++ b/packages/SystemUI/res/layout/qs_detail.xml
@@ -14,39 +14,43 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:background="@drawable/qs_detail_background"
- android:padding="16dp" >
-
- <TextView
- android:id="@android:id/button1"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:minWidth="88dp"
- android:layout_alignParentBottom="true"
- android:layout_alignParentEnd="true"
- android:text="@string/quick_settings_done"
- android:textAppearance="@style/TextAppearance.QS.DetailButton" />
-
- <TextView
- android:id="@android:id/button2"
- style="@style/QSBorderlessButton"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_marginEnd="8dp"
- android:minWidth="132dp"
- android:layout_toStartOf="@android:id/button1"
- android:text="@string/quick_settings_more_settings"
- android:textAppearance="@style/TextAppearance.QS.DetailButton" />
-
- <FrameLayout
- android:id="@android:id/content"
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_above="@android:id/button1" />
+ android:background="@drawable/qs_detail_background"
+ android:paddingBottom="16dp"
+ android:orientation="vertical">
-</RelativeLayout>
\ No newline at end of file
+ <FrameLayout
+ android:id="@android:id/content"
+ android:layout_width="match_parent"
+ android:layout_height="0dp"
+ android:layout_weight="1" />
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:paddingEnd="16dp"
+ android:gravity="end">
+
+ <TextView
+ android:id="@android:id/button2"
+ style="@style/QSBorderlessButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_marginEnd="8dp"
+ android:minWidth="132dp"
+ android:text="@string/quick_settings_more_settings"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton" />
+
+ <TextView
+ android:id="@android:id/button1"
+ style="@style/QSBorderlessButton"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:minWidth="88dp"
+ android:text="@string/quick_settings_done"
+ android:textAppearance="@style/TextAppearance.QS.DetailButton" />
+
+ </LinearLayout>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_detail_items.xml b/packages/SystemUI/res/layout/qs_detail_items.xml
index b64005f..f61a43c 100644
--- a/packages/SystemUI/res/layout/qs_detail_items.xml
+++ b/packages/SystemUI/res/layout/qs_detail_items.xml
@@ -17,7 +17,10 @@
<!-- extends FrameLayout -->
<com.android.systemui.qs.QSDetailItems xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="match_parent" >
+ android:layout_height="match_parent"
+ android:paddingTop="16dp"
+ android:paddingStart="16dp"
+ android:paddingEnd="16dp">
<LinearLayout
android:id="@android:id/list"
diff --git a/packages/SystemUI/res/layout/qs_user_detail.xml b/packages/SystemUI/res/layout/qs_user_detail.xml
index 1d6df61..91d3a53 100644
--- a/packages/SystemUI/res/layout/qs_user_detail.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail.xml
@@ -16,14 +16,12 @@
~ limitations under the License
-->
-<!-- GridView -->
+<!-- PseudoGridView -->
<com.android.systemui.qs.tiles.UserDetailView
xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:sysui="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:verticalSpacing="4dp"
- android:horizontalSpacing="4dp"
- android:numColumns="3"
- android:listSelector="@drawable/ripple_drawable">
-
-</com.android.systemui.qs.tiles.UserDetailView>
\ No newline at end of file
+ sysui:verticalSpacing="4dp"
+ sysui:horizontalSpacing="4dp"
+ style="@style/UserDetailView" />
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml
index 5ceed84..2322f16 100644
--- a/packages/SystemUI/res/layout/qs_user_detail_item.xml
+++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml
@@ -25,16 +25,17 @@
android:orientation="vertical"
android:gravity="top|center_horizontal"
android:paddingTop="16dp"
- android:paddingBottom="20dp"
+ android:minHeight="112dp"
android:clipChildren="false"
android:clipToPadding="false"
+ android:background="@drawable/ripple_drawable"
systemui:activatedFontFamily="sans-serif-medium">
<com.android.systemui.statusbar.phone.UserAvatarView
android:id="@+id/user_picture"
android:layout_width="@dimen/max_avatar_size"
android:layout_height="@dimen/max_avatar_size"
- android:layout_marginBottom="12dp"
+ android:layout_marginBottom="10dp"
systemui:frameWidth="2dp"
systemui:framePadding="6dp"
systemui:activeFrameColor="@color/current_user_border_color"/>
diff --git a/packages/SystemUI/res/values-sw600dp/styles.xml b/packages/SystemUI/res/values-sw600dp/styles.xml
index 5daf08e..9e5b1d6 100644
--- a/packages/SystemUI/res/values-sw600dp/styles.xml
+++ b/packages/SystemUI/res/values-sw600dp/styles.xml
@@ -34,4 +34,8 @@
<item name="android:layout_height">@dimen/search_panel_scrim_height</item>
<item name="android:layout_gravity">bottom</item>
</style>
+
+ <style name="UserDetailView">
+ <item name="numColumns">4</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 8bd3c39..6ecdca3 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -67,5 +67,10 @@
<declare-styleable name="DateView">
<attr name="datePattern" format="string" />
</declare-styleable>
+ <declare-styleable name="PseudoGridView">
+ <attr name="numColumns" format="integer" />
+ <attr name="verticalSpacing" format="dimension" />
+ <attr name="horizontalSpacing" format="dimension" />
+ </declare-styleable>
</resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 5db6912..baaa379 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -289,4 +289,8 @@
<item name="android:layout_height">@dimen/search_panel_scrim_height</item>
<item name="android:layout_gravity">bottom</item>
</style>
+
+ <style name="UserDetailView">
+ <item name="numColumns">3</item>
+ </style>
</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
new file mode 100644
index 0000000..cb6708e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/PseudoGridView.java
@@ -0,0 +1,213 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.qs;
+
+import com.android.systemui.R;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.database.DataSetObserver;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.BaseAdapter;
+
+import java.lang.ref.WeakReference;
+
+/**
+ * A view that arranges it's children in a grid with a fixed number of evenly spaced columns.
+ *
+ * {@see android.widget.GridView}
+ */
+public class PseudoGridView extends ViewGroup {
+
+ private int mNumColumns = 3;
+ private int mVerticalSpacing;
+ private int mHorizontalSpacing;
+
+ public PseudoGridView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+
+ final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.PseudoGridView);
+
+ final int N = a.getIndexCount();
+ for (int i = 0; i < N; i++) {
+ int attr = a.getIndex(i);
+ switch (attr) {
+ case R.styleable.PseudoGridView_numColumns:
+ mNumColumns = a.getInt(attr, 3);
+ break;
+ case R.styleable.PseudoGridView_verticalSpacing:
+ mVerticalSpacing = a.getDimensionPixelSize(attr, 0);
+ break;
+ case R.styleable.PseudoGridView_horizontalSpacing:
+ mHorizontalSpacing = a.getDimensionPixelSize(attr, 0);
+ break;
+ }
+ }
+
+ a.recycle();
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ if (MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.UNSPECIFIED) {
+ throw new UnsupportedOperationException("Needs a maximum width");
+ }
+ int width = MeasureSpec.getSize(widthMeasureSpec);
+
+ int childWidth = (width - (mNumColumns - 1) * mHorizontalSpacing) / mNumColumns;
+ int childWidthSpec = MeasureSpec.makeMeasureSpec(childWidth, MeasureSpec.EXACTLY);
+ int childHeightSpec = MeasureSpec.UNSPECIFIED;
+ int totalHeight = 0;
+ int children = getChildCount();
+ int rows = (children + mNumColumns - 1) / mNumColumns;
+ for (int row = 0; row < rows; row++) {
+ int startOfRow = row * mNumColumns;
+ int endOfRow = Math.min(startOfRow + mNumColumns, children);
+ int maxHeight = 0;
+ for (int i = startOfRow; i < endOfRow; i++) {
+ View child = getChildAt(i);
+ child.measure(childWidthSpec, childHeightSpec);
+ maxHeight = Math.max(maxHeight, child.getMeasuredHeight());
+ }
+ int maxHeightSpec = MeasureSpec.makeMeasureSpec(maxHeight, MeasureSpec.EXACTLY);
+ for (int i = startOfRow; i < endOfRow; i++) {
+ View child = getChildAt(i);
+ if (child.getMeasuredHeight() != maxHeight) {
+ child.measure(childWidthSpec, maxHeightSpec);
+ }
+ }
+ totalHeight += maxHeight;
+ if (row > 0) {
+ totalHeight += mVerticalSpacing;
+ }
+ }
+
+ setMeasuredDimension(width, getDefaultSize(totalHeight, heightMeasureSpec));
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ boolean isRtl = isLayoutRtl();
+ int children = getChildCount();
+ int rows = (children + mNumColumns - 1) / mNumColumns;
+ int y = 0;
+ for (int row = 0; row < rows; row++) {
+ int x = isRtl ? getWidth() : 0;
+ int maxHeight = 0;
+ int startOfRow = row * mNumColumns;
+ int endOfRow = Math.min(startOfRow + mNumColumns, children);
+ for (int i = startOfRow; i < endOfRow; i++) {
+ View child = getChildAt(i);
+ int width = child.getMeasuredWidth();
+ int height = child.getMeasuredHeight();
+ if (isRtl) {
+ x -= width;
+ }
+ child.layout(x, y, x + width, y + height);
+ maxHeight = Math.max(maxHeight, height);
+ if (isRtl) {
+ x -= mHorizontalSpacing;
+ } else {
+ x += width + mHorizontalSpacing;
+ }
+ }
+ y += maxHeight;
+ if (row > 0) {
+ y += mVerticalSpacing;
+ }
+ }
+ }
+
+ /**
+ * Bridges between a ViewGroup and a BaseAdapter.
+ * <p>
+ * Usage: {@code ViewGroupAdapterBridge.link(viewGroup, adapter)}
+ * <br />
+ * After this call, the ViewGroup's children will be provided by the adapter.
+ */
+ public static class ViewGroupAdapterBridge extends DataSetObserver {
+
+ private final WeakReference<ViewGroup> mViewGroup;
+ private final BaseAdapter mAdapter;
+ private boolean mReleased;
+
+ public static void link(ViewGroup viewGroup, BaseAdapter adapter) {
+ new ViewGroupAdapterBridge(viewGroup, adapter);
+ }
+
+ private ViewGroupAdapterBridge(ViewGroup viewGroup, BaseAdapter adapter) {
+ mViewGroup = new WeakReference<>(viewGroup);
+ mAdapter = adapter;
+ mReleased = false;
+ mAdapter.registerDataSetObserver(this);
+ refresh();
+ }
+
+ private void refresh() {
+ if (mReleased) {
+ return;
+ }
+ ViewGroup viewGroup = mViewGroup.get();
+ if (viewGroup == null) {
+ release();
+ return;
+ }
+ final int childCount = viewGroup.getChildCount();
+ final int adapterCount = mAdapter.getCount();
+ final int N = Math.max(childCount, adapterCount);
+ for (int i = 0; i < N; i++) {
+ if (i < adapterCount) {
+ View oldView = null;
+ if (i < childCount) {
+ oldView = viewGroup.getChildAt(i);
+ }
+ View newView = mAdapter.getView(i, oldView, viewGroup);
+ if (oldView == null) {
+ // We ran out of existing views. Add it at the end.
+ viewGroup.addView(newView);
+ } else if (oldView != newView) {
+ // We couldn't rebind the view. Replace it.
+ viewGroup.removeViewAt(i);
+ viewGroup.addView(newView, i);
+ }
+ } else {
+ int lastIndex = viewGroup.getChildCount() - 1;
+ viewGroup.removeViewAt(lastIndex);
+ }
+ }
+ }
+
+ @Override
+ public void onChanged() {
+ refresh();
+ }
+
+ @Override
+ public void onInvalidated() {
+ release();
+ }
+
+ private void release() {
+ if (!mReleased) {
+ mReleased = true;
+ mAdapter.unregisterDataSetObserver(this);
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
index 59f3b3d..3679b4c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java
@@ -326,8 +326,11 @@
if (mFooter.hasFooter()) {
h += mFooter.getView().getHeight();
}
- mDetail.measure(exactly(width), exactly(h));
- setMeasuredDimension(width, h);
+ mDetail.measure(exactly(width), MeasureSpec.UNSPECIFIED);
+ if (mDetail.getMeasuredHeight() < h) {
+ mDetail.measure(exactly(width), exactly(h));
+ }
+ setMeasuredDimension(width, Math.max(h, mDetail.getMeasuredHeight()));
}
private static int exactly(int size) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 8cff81a..c524edc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -17,45 +17,24 @@
package com.android.systemui.qs.tiles;
import com.android.systemui.R;
+import com.android.systemui.qs.PseudoGridView;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import android.content.Context;
-import android.content.Intent;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.AdapterView;
-import android.widget.GridView;
/**
* Quick settings detail view for user switching.
*/
-public class UserDetailView extends GridView {
+public class UserDetailView extends PseudoGridView {
- public UserDetailView(Context context) {
- this(context, null);
- }
+ private Adapter mAdapter;
public UserDetailView(Context context, AttributeSet attrs) {
- this(context, attrs, android.R.attr.gridViewStyle);
- }
-
- public UserDetailView(Context context, AttributeSet attrs, int defStyleAttr) {
- this(context, attrs, defStyleAttr, 0);
- }
-
- public UserDetailView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
-
- setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- UserSwitcherController.UserRecord tag =
- (UserSwitcherController.UserRecord) view.getTag();
- ((Adapter)getAdapter()).switchTo(tag);
- }
- });
+ super(context, attrs);
}
public static UserDetailView inflate(Context context, ViewGroup parent, boolean attach) {
@@ -64,10 +43,12 @@
}
public void createAndSetAdapter(UserSwitcherController controller) {
- setAdapter(new Adapter(mContext, controller));
+ mAdapter = new Adapter(mContext, controller);
+ ViewGroupAdapterBridge.link(this, mAdapter);
}
- public static class Adapter extends UserSwitcherController.BaseUserAdapter {
+ public static class Adapter extends UserSwitcherController.BaseUserAdapter
+ implements OnClickListener {
private Context mContext;
@@ -81,6 +62,9 @@
UserSwitcherController.UserRecord item = getItem(position);
UserDetailItemView v = UserDetailItemView.convertOrInflate(
mContext, convertView, parent);
+ if (v != convertView) {
+ v.setOnClickListener(this);
+ }
String name = getName(mContext, item);
if (item.picture == null) {
v.bind(name, getDrawable(mContext, item));
@@ -91,5 +75,12 @@
v.setTag(item);
return v;
}
+
+ @Override
+ public void onClick(View view) {
+ UserSwitcherController.UserRecord tag =
+ (UserSwitcherController.UserRecord) view.getTag();
+ switchTo(tag);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index c48f3f5..a1993f7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -465,12 +465,12 @@
@Override
public View createDetailView(Context context, View convertView, ViewGroup parent) {
+ UserDetailView v;
if (!(convertView instanceof UserDetailView)) {
- convertView = UserDetailView.inflate(context, parent, false);
- }
- UserDetailView v = (UserDetailView) convertView;
- if (v.getAdapter() == null) {
+ v = UserDetailView.inflate(context, parent, false);
v.createAndSetAdapter(UserSwitcherController.this);
+ } else {
+ v = (UserDetailView) convertView;
}
return v;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
index 2e97d18..6c4fb7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeController.java
@@ -29,11 +29,13 @@
Uri getExitConditionId();
long getNextAlarm();
void setUserId(int userId);
+ boolean isZenAvailable();
public static class Callback {
public void onZenChanged(int zen) {}
public void onExitConditionChanged(Uri exitConditionId) {}
public void onConditionsChanged(Condition[] conditions) {}
public void onNextAlarmChanged() {}
+ public void onZenAvailableChanged(boolean available) {}
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
index a3cdd41..9d3dec8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ZenModeControllerImpl.java
@@ -20,15 +20,18 @@
import android.app.AlarmManager;
import android.app.INotificationManager;
import android.content.BroadcastReceiver;
+import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.provider.Settings.Global;
+import android.provider.Settings.Secure;
import android.service.notification.Condition;
import android.service.notification.IConditionListener;
import android.service.notification.ZenModeConfig;
@@ -52,6 +55,7 @@
private final INotificationManager mNoMan;
private final LinkedHashMap<Uri, Condition> mConditions = new LinkedHashMap<Uri, Condition>();
private final AlarmManager mAlarmManager;
+ private final SetupObserver mSetupObserver;
private int mUserId;
private boolean mRequesting;
@@ -76,6 +80,8 @@
mNoMan = INotificationManager.Stub.asInterface(
ServiceManager.getService(Context.NOTIFICATION_SERVICE));
mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ mSetupObserver = new SetupObserver(handler);
+ mSetupObserver.register();
}
@Override
@@ -99,6 +105,11 @@
}
@Override
+ public boolean isZenAvailable() {
+ return mSetupObserver.isDeviceProvisioned() && mSetupObserver.isUserSetup();
+ }
+
+ @Override
public void requestConditions(boolean request) {
mRequesting = request;
try {
@@ -148,6 +159,7 @@
mContext.registerReceiverAsUser(mReceiver, new UserHandle(mUserId),
new IntentFilter(AlarmManager.ACTION_NEXT_ALARM_CLOCK_CHANGED), null, null);
mRegistered = true;
+ mSetupObserver.register();
}
private void fireNextAlarmChanged() {
@@ -162,6 +174,12 @@
}
}
+ private void fireZenAvailableChanged(boolean available) {
+ for (Callback cb : mCallbacks) {
+ cb.onZenAvailableChanged(available);
+ }
+ }
+
private void fireConditionsChanged(Condition[] conditions) {
for (Callback cb : mCallbacks) {
cb.onConditionsChanged(conditions);
@@ -204,4 +222,42 @@
}
}
};
+
+ private final class SetupObserver extends ContentObserver {
+ private final ContentResolver mResolver;
+
+ private boolean mRegistered;
+
+ public SetupObserver(Handler handler) {
+ super(handler);
+ mResolver = mContext.getContentResolver();
+ }
+
+ public boolean isUserSetup() {
+ return Secure.getIntForUser(mResolver, Secure.USER_SETUP_COMPLETE, 0, mUserId) != 0;
+ }
+
+ public boolean isDeviceProvisioned() {
+ return Global.getInt(mResolver, Global.DEVICE_PROVISIONED, 0) != 0;
+ }
+
+ public void register() {
+ if (mRegistered) {
+ mResolver.unregisterContentObserver(this);
+ }
+ mResolver.registerContentObserver(
+ Global.getUriFor(Global.DEVICE_PROVISIONED), false, this);
+ mResolver.registerContentObserver(
+ Secure.getUriFor(Secure.USER_SETUP_COMPLETE), false, this, mUserId);
+ fireZenAvailableChanged(isZenAvailable());
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri) {
+ if (Global.getUriFor(Global.DEVICE_PROVISIONED).equals(uri)
+ || Secure.getUriFor(Secure.USER_SETUP_COMPLETE).equals(uri)) {
+ fireZenAvailableChanged(isZenAvailable());
+ }
+ }
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
index 3a63a79..5233da2 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumePanel.java
@@ -107,7 +107,7 @@
private static final int MSG_SLIDER_VISIBILITY_CHANGED = 10;
private static final int MSG_DISPLAY_SAFE_VOLUME_WARNING = 11;
private static final int MSG_LAYOUT_DIRECTION = 12;
- private static final int MSG_ZEN_MODE_CHANGED = 13;
+ private static final int MSG_ZEN_MODE_AVAILABLE_CHANGED = 13;
private static final int MSG_USER_ACTIVITY = 14;
// Pseudo stream type for master volume
@@ -125,7 +125,7 @@
private final ZenModeController mZenController;
private boolean mRingIsSilent;
private boolean mVoiceCapable;
- private boolean mZenModeCapable;
+ private boolean mZenModeAvailable;
private boolean mZenPanelExpanded;
private int mTimeoutDelay = TIMEOUT_DELAY;
private float mDisabledAlpha;
@@ -405,9 +405,10 @@
mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE);
mVoiceCapable = context.getResources().getBoolean(R.bool.config_voice_capable);
- mZenModeCapable = !useMasterVolume && mZenController != null;
- updateZenMode(mZenController != null ? mZenController.getZen() : Global.ZEN_MODE_OFF);
- mZenController.addCallback(mZenCallback);
+ if (mZenController != null && !useMasterVolume) {
+ mZenModeAvailable = mZenController.isZenAvailable();
+ mZenController.addCallback(mZenCallback);
+ }
final boolean masterVolumeOnly = res.getBoolean(R.bool.config_useMasterVolume);
final boolean masterVolumeKeySounds = res.getBoolean(R.bool.config_useVolumeKeySounds);
@@ -434,7 +435,7 @@
pw.print(" mTag="); pw.println(mTag);
pw.print(" mRingIsSilent="); pw.println(mRingIsSilent);
pw.print(" mVoiceCapable="); pw.println(mVoiceCapable);
- pw.print(" mZenModeCapable="); pw.println(mZenModeCapable);
+ pw.print(" mZenModeAvailable="); pw.println(mZenModeAvailable);
pw.print(" mZenPanelExpanded="); pw.println(mZenPanelExpanded);
pw.print(" mTimeoutDelay="); pw.println(mTimeoutDelay);
pw.print(" mDisabledAlpha="); pw.println(mDisabledAlpha);
@@ -645,7 +646,7 @@
active.group.setVisibility(View.VISIBLE);
updateSlider(active);
updateTimeoutDelay();
- setZenPanelVisible(isNotificationOrRing(mActiveStreamType));
+ updateZenPanelVisible();
}
}
@@ -776,14 +777,8 @@
}
}
- private void updateZenMode(int zen) {
- final boolean show = mZenModeCapable && isNotificationOrRing(mActiveStreamType);
- setZenPanelVisible(show);
- }
-
- public void postZenModeChanged(int zen) {
- removeMessages(MSG_ZEN_MODE_CHANGED);
- obtainMessage(MSG_ZEN_MODE_CHANGED, zen).sendToTarget();
+ private void updateZenPanelVisible() {
+ setZenPanelVisible(mZenModeAvailable && isNotificationOrRing(mActiveStreamType));
}
public void postVolumeChanged(int streamType, int flags) {
@@ -1307,8 +1302,9 @@
setLayoutDirection(msg.arg1);
break;
- case MSG_ZEN_MODE_CHANGED:
- updateZenMode(msg.arg1);
+ case MSG_ZEN_MODE_AVAILABLE_CHANGED:
+ mZenModeAvailable = msg.arg1 != 0;
+ updateZenPanelVisible();
break;
case MSG_USER_ACTIVITY:
@@ -1359,8 +1355,8 @@
};
private final ZenModeController.Callback mZenCallback = new ZenModeController.Callback() {
- public void onZenChanged(int zen) {
- postZenModeChanged(zen);
+ public void onZenAvailableChanged(boolean available) {
+ obtainMessage(MSG_ZEN_MODE_AVAILABLE_CHANGED, available ? 1 : 0, 0).sendToTarget();
}
};
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index c5bc7d3..4653742 100755
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -1099,6 +1099,51 @@
}
}
+ // Find the first visible activity above the passed activity and if it is translucent return it
+ // otherwise return null;
+ ActivityRecord findNextTranslucentActivity(ActivityRecord r) {
+ TaskRecord task = r.task;
+ if (task == null) {
+ return null;
+ }
+
+ ActivityStack stack = task.stack;
+ if (stack == null) {
+ return null;
+ }
+
+ int stackNdx = mStacks.indexOf(stack);
+
+ ArrayList<TaskRecord> tasks = stack.mTaskHistory;
+ int taskNdx = tasks.indexOf(task);
+
+ ArrayList<ActivityRecord> activities = task.mActivities;
+ int activityNdx = activities.indexOf(r) + 1;
+
+ final int numStacks = mStacks.size();
+ while (stackNdx < numStacks) {
+ tasks = mStacks.get(stackNdx).mTaskHistory;
+ final int numTasks = tasks.size();
+ while (taskNdx < numTasks) {
+ activities = tasks.get(taskNdx).mActivities;
+ final int numActivities = activities.size();
+ while (activityNdx < numActivities) {
+ final ActivityRecord activity = activities.get(activityNdx);
+ if (!activity.finishing) {
+ return activity.fullscreen ? null : activity;
+ }
+ ++activityNdx;
+ }
+ activityNdx = 0;
+ ++taskNdx;
+ }
+ taskNdx = 0;
+ ++stackNdx;
+ }
+
+ return null;
+ }
+
// Checks if any of the stacks above this one has a fullscreen activity behind it.
// If so, this stack is hidden, otherwise it is visible.
private boolean isStackVisible() {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index b4e66c1..4a99ef3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2680,6 +2680,13 @@
}
stack.setMediaPlayer(playing ? r : null);
+ if (!playing) {
+ // Make the activity immediately above r opaque.
+ final ActivityRecord next = stack.findNextTranslucentActivity(r);
+ if (next != null) {
+ mService.convertFromTranslucent(next.appToken);
+ }
+ }
try {
top.app.thread.scheduleBackgroundMediaPlayingChanged(top.appToken, playing);
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/display/ElectronBeam.java b/services/core/java/com/android/server/display/ColorFade.java
similarity index 65%
rename from services/core/java/com/android/server/display/ElectronBeam.java
rename to services/core/java/com/android/server/display/ColorFade.java
index 18e4049..920fdfb 100644
--- a/services/core/java/com/android/server/display/ElectronBeam.java
+++ b/services/core/java/com/android/server/display/ColorFade.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,11 +16,16 @@
package com.android.server.display;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
+import android.content.Context;
+import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.graphics.SurfaceTexture;
import android.hardware.display.DisplayManagerInternal;
@@ -30,9 +35,8 @@
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLSurface;
-import android.opengl.GLES10;
+import android.opengl.GLES20;
import android.opengl.GLES11Ext;
-import android.os.Looper;
import android.util.FloatMath;
import android.util.Slog;
import android.view.DisplayInfo;
@@ -41,10 +45,12 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import libcore.io.Streams;
+
import com.android.server.LocalServices;
+import com.android.internal.R;
/**
- * Bzzzoooop! *crackle*
* <p>
* Animates a screen transition from on to off or off to on by applying
* some GL transformations to a screenshot.
@@ -53,20 +59,14 @@
* that belongs to the {@link DisplayPowerController}.
* </p>
*/
-final class ElectronBeam {
- private static final String TAG = "ElectronBeam";
+final class ColorFade {
+ private static final String TAG = "ColorFade";
private static final boolean DEBUG = false;
// The layer for the electron beam surface.
// This is currently hardcoded to be one layer above the boot animation.
- private static final int ELECTRON_BEAM_LAYER = 0x40000001;
-
- // The relative proportion of the animation to spend performing
- // the horizontal stretch effect. The remainder is spent performing
- // the vertical stretch effect.
- private static final float HSTRETCH_DURATION = 0.5f;
- private static final float VSTRETCH_DURATION = 1.0f - HSTRETCH_DURATION;
+ private static final int COLOR_FADE_LAYER = 0x40000001;
// The number of frames to draw when preparing the animation so that it will
// be ready to run smoothly. We use 3 frames because we are triple-buffered.
@@ -98,6 +98,11 @@
private final int[] mTexNames = new int[1];
private boolean mTexNamesGenerated;
private final float mTexMatrix[] = new float[16];
+ private final float mProjMatrix[] = new float[16];
+ private final int[] mGLBuffers = new int[2];
+ private int mTexCoordLoc, mVertexLoc, mTexUnitLoc, mProjMatrixLoc, mTexMatrixLoc;
+ private int mOpacityLoc, mScaleLoc, mGammaLoc, mSaturationLoc;
+ private int mProgram;
// Vertex and corresponding texture coordinates.
// We have 4 2D vertices, so 8 elements. The vertices form a quad.
@@ -105,12 +110,12 @@
private final FloatBuffer mTexCoordBuffer = createNativeFloatBuffer(8);
/**
- * Animates an electron beam warming up.
+ * Animates an color fade warming up.
*/
public static final int MODE_WARM_UP = 0;
/**
- * Animates an electron beam shutting off.
+ * Animates an color fade shutting off.
*/
public static final int MODE_COOL_DOWN = 1;
@@ -119,19 +124,19 @@
*/
public static final int MODE_FADE = 2;
- public ElectronBeam(int displayId) {
+ public ColorFade(int displayId) {
mDisplayId = displayId;
mDisplayManagerInternal = LocalServices.getService(DisplayManagerInternal.class);
}
/**
- * Warms up the electron beam in preparation for turning on or off.
+ * Warms up the color fade in preparation for turning on or off.
* This method prepares a GL context, and captures a screen shot.
*
* @param mode The desired mode for the upcoming animation.
- * @return True if the electron beam is ready, false if it is uncontrollable.
+ * @return True if the color fade is ready, false if it is uncontrollable.
*/
- public boolean prepare(int mode) {
+ public boolean prepare(Context context, int mode) {
if (DEBUG) {
Slog.d(TAG, "prepare: mode=" + mode);
}
@@ -139,18 +144,33 @@
mMode = mode;
// Get the display size and layer stack.
- // This is not expected to change while the electron beam surface is showing.
+ // This is not expected to change while the color fade surface is showing.
DisplayInfo displayInfo = mDisplayManagerInternal.getDisplayInfo(mDisplayId);
mDisplayLayerStack = displayInfo.layerStack;
mDisplayWidth = displayInfo.getNaturalWidth();
mDisplayHeight = displayInfo.getNaturalHeight();
// Prepare the surface for drawing.
- if (!tryPrepare()) {
+ if (!(createSurface() && createEglContext() && createEglSurface() &&
+ captureScreenshotTextureAndSetViewport())) {
dismiss();
return false;
}
+ // Init GL
+ if (!attachEglContext()) {
+ return false;
+ }
+ try {
+ if(!initGLShaders(context) || !initGLBuffers() || checkGlErrors("prepare")) {
+ detachEglContext();
+ dismiss();
+ return false;
+ }
+ } finally {
+ detachEglContext();
+ }
+
// Done.
mPrepared = true;
@@ -169,24 +189,125 @@
return true;
}
- private boolean tryPrepare() {
- if (createSurface()) {
- if (mMode == MODE_FADE) {
- return true;
- }
- return createEglContext()
- && createEglSurface()
- && captureScreenshotTextureAndSetViewport();
+ private String readFile(Context context, int resourceId) {
+ try{
+ InputStream stream = context.getResources().openRawResource(resourceId);
+ return new String(Streams.readFully(new InputStreamReader(stream)));
}
- return false;
+ catch (IOException e) {
+ Slog.e(TAG, "Unrecognized shader " + Integer.toString(resourceId));
+ throw new RuntimeException(e);
+ }
+ }
+
+ private int loadShader(Context context, int resourceId, int type) {
+ String source = readFile(context, resourceId);
+
+ int shader = GLES20.glCreateShader(type);
+
+ GLES20.glShaderSource(shader, source);
+ GLES20.glCompileShader(shader);
+
+ int[] compiled = new int[1];
+ GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compiled, 0);
+ if (compiled[0] == 0) {
+ Slog.e(TAG, "Could not compile shader " + shader + ", " + type + ":");
+ Slog.e(TAG, GLES20.glGetShaderSource(shader));
+ Slog.e(TAG, GLES20.glGetShaderInfoLog(shader));
+ GLES20.glDeleteShader(shader);
+ shader = 0;
+ }
+
+ return shader;
+ }
+
+ private boolean initGLShaders(Context context) {
+ int vshader = loadShader(context, com.android.internal.R.raw.color_fade_vert,
+ GLES20.GL_VERTEX_SHADER);
+ int fshader = loadShader(context, com.android.internal.R.raw.color_fade_frag,
+ GLES20.GL_FRAGMENT_SHADER);
+ if (vshader == 0 || fshader == 0) return false;
+
+ mProgram = GLES20.glCreateProgram();
+
+ GLES20.glAttachShader(mProgram, vshader);
+ GLES20.glAttachShader(mProgram, fshader);
+
+ GLES20.glLinkProgram(mProgram);
+
+ mVertexLoc = GLES20.glGetAttribLocation(mProgram, "position");
+ mTexCoordLoc = GLES20.glGetAttribLocation(mProgram, "uv");
+
+ mProjMatrixLoc = GLES20.glGetUniformLocation(mProgram, "proj_matrix");
+ mTexMatrixLoc = GLES20.glGetUniformLocation(mProgram, "tex_matrix");
+
+ mOpacityLoc = GLES20.glGetUniformLocation(mProgram, "opacity");
+ mGammaLoc = GLES20.glGetUniformLocation(mProgram, "gamma");
+ mSaturationLoc = GLES20.glGetUniformLocation(mProgram, "saturation");
+ mScaleLoc = GLES20.glGetUniformLocation(mProgram, "scale");
+ mTexUnitLoc = GLES20.glGetUniformLocation(mProgram, "texUnit");
+
+ GLES20.glUseProgram(mProgram);
+ GLES20.glUniform1i(mTexUnitLoc, 0);
+ GLES20.glUseProgram(0);
+
+ return true;
+ }
+
+ private boolean initGLBuffers() {
+ //Fill vertices
+ setQuad(mVertexBuffer, 0, 0, mDisplayWidth, mDisplayHeight);
+
+ // Setup GL Textures
+ GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
+ GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MAG_FILTER,
+ GLES20.GL_NEAREST);
+ GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_MIN_FILTER,
+ GLES20.GL_NEAREST);
+ GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_S,
+ GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glTexParameteri(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GLES20.GL_TEXTURE_WRAP_T,
+ GLES20.GL_CLAMP_TO_EDGE);
+ GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
+
+ // Setup GL Buffers
+ GLES20.glGenBuffers(2, mGLBuffers, 0);
+
+ // fill vertex buffer
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
+ GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mVertexBuffer.capacity() * 4,
+ mVertexBuffer, GLES20.GL_STATIC_DRAW);
+
+ // fill tex buffer
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
+ GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, mTexCoordBuffer.capacity() * 4,
+ mTexCoordBuffer, GLES20.GL_STATIC_DRAW);
+
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
+
+ return true;
+ }
+
+ private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
+ if (DEBUG) {
+ Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
+ }
+ vtx.put(0, x);
+ vtx.put(1, y);
+ vtx.put(2, x);
+ vtx.put(3, y + h);
+ vtx.put(4, x + w);
+ vtx.put(5, y + h);
+ vtx.put(6, x + w);
+ vtx.put(7, y);
}
/**
- * Dismisses the electron beam animation surface and cleans up.
+ * Dismisses the color fade animation surface and cleans up.
*
- * To prevent stray photons from leaking out after the electron beam has been
+ * To prevent stray photons from leaking out after the color fade has been
* turned off, it is a good idea to defer dismissing the animation until the
- * electron beam has been turned back on fully.
+ * color fade has been turned back on fully.
*/
public void dismiss() {
if (DEBUG) {
@@ -200,10 +321,10 @@
}
/**
- * Draws an animation frame showing the electron beam activated at the
+ * Draws an animation frame showing the color fade activated at the
* specified level.
*
- * @param level The electron beam level.
+ * @param level The color fade level.
* @return True if successful.
*/
public boolean draw(float level) {
@@ -224,15 +345,18 @@
}
try {
// Clear frame to solid black.
- GLES10.glClearColor(0f, 0f, 0f, 1f);
- GLES10.glClear(GLES10.GL_COLOR_BUFFER_BIT);
+ GLES20.glClearColor(0f, 0f, 0f, 1f);
+ GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
// Draw the frame.
- if (level < HSTRETCH_DURATION) {
- drawHStretch(1.0f - (level / HSTRETCH_DURATION));
- } else {
- drawVStretch(1.0f - ((level - HSTRETCH_DURATION) / VSTRETCH_DURATION));
- }
+ float one_minus_level = 1 - level;
+ float cos = FloatMath.cos((float)Math.PI * one_minus_level);
+ float sign = cos < 0 ? -1 : 1;
+ float opacity = -FloatMath.pow(one_minus_level, 2) + 1;
+ float saturation = FloatMath.pow(level, 4);
+ float scale = (-FloatMath.pow(one_minus_level, 2) + 1) * 0.1f + 0.9f;
+ float gamma = (0.5f * sign * FloatMath.pow(cos, 2) + 0.5f) * 0.9f + 0.1f;
+ drawFaded(opacity, 1.f / gamma, saturation, scale);
if (checkGlErrors("drawFrame")) {
return false;
}
@@ -244,139 +368,59 @@
return showSurface(1.0f);
}
- /**
- * Draws a frame where the content of the electron beam is collapsing inwards upon
- * itself vertically with red / green / blue channels dispersing and eventually
- * merging down to a single horizontal line.
- *
- * @param stretch The stretch factor. 0.0 is no collapse, 1.0 is full collapse.
- */
- private void drawVStretch(float stretch) {
- // compute interpolation scale factors for each color channel
- final float ar = scurve(stretch, 7.5f);
- final float ag = scurve(stretch, 8.0f);
- final float ab = scurve(stretch, 8.5f);
+ private void drawFaded(float opacity, float gamma, float saturation, float scale) {
if (DEBUG) {
- Slog.d(TAG, "drawVStretch: stretch=" + stretch
- + ", ar=" + ar + ", ag=" + ag + ", ab=" + ab);
+ Slog.d(TAG, "drawFaded: opacity=" + opacity + ", gamma=" + gamma +
+ ", saturation=" + saturation + ", scale=" + scale);
}
+ // Use shaders
+ GLES20.glUseProgram(mProgram);
- // set blending
- GLES10.glBlendFunc(GLES10.GL_ONE, GLES10.GL_ONE);
- GLES10.glEnable(GLES10.GL_BLEND);
+ // Set Uniforms
+ GLES20.glUniformMatrix4fv(mProjMatrixLoc, 1, false, mProjMatrix, 0);
+ GLES20.glUniformMatrix4fv(mTexMatrixLoc, 1, false, mTexMatrix, 0);
+ GLES20.glUniform1f(mOpacityLoc, opacity);
+ GLES20.glUniform1f(mGammaLoc, gamma);
+ GLES20.glUniform1f(mSaturationLoc, saturation);
+ GLES20.glUniform1f(mScaleLoc, scale);
- // bind vertex buffer
- GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
- GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
+ // Use textures
+ GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
+ GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
- // set-up texturing
- GLES10.glDisable(GLES10.GL_TEXTURE_2D);
- GLES10.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
+ // draw the plane
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[0]);
+ GLES20.glEnableVertexAttribArray(mVertexLoc);
+ GLES20.glVertexAttribPointer(mVertexLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
- // bind texture and set blending for drawing planes
- GLES10.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mTexNames[0]);
- GLES10.glTexEnvx(GLES10.GL_TEXTURE_ENV, GLES10.GL_TEXTURE_ENV_MODE,
- mMode == MODE_WARM_UP ? GLES10.GL_MODULATE : GLES10.GL_REPLACE);
- GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GLES10.GL_TEXTURE_MAG_FILTER, GLES10.GL_LINEAR);
- GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GLES10.GL_TEXTURE_MIN_FILTER, GLES10.GL_LINEAR);
- GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GLES10.GL_TEXTURE_WRAP_S, GLES10.GL_CLAMP_TO_EDGE);
- GLES10.glTexParameterx(GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
- GLES10.GL_TEXTURE_WRAP_T, GLES10.GL_CLAMP_TO_EDGE);
- GLES10.glEnable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
- GLES10.glTexCoordPointer(2, GLES10.GL_FLOAT, 0, mTexCoordBuffer);
- GLES10.glEnableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, mGLBuffers[1]);
+ GLES20.glEnableVertexAttribArray(mTexCoordLoc);
+ GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, 0);
- // draw the red plane
- setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ar);
- GLES10.glColorMask(true, false, false, true);
- GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
- // draw the green plane
- setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
- GLES10.glColorMask(false, true, false, true);
- GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
- // draw the blue plane
- setVStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ab);
- GLES10.glColorMask(false, false, true, true);
- GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
- // clean up after drawing planes
- GLES10.glDisable(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
- GLES10.glDisableClientState(GLES10.GL_TEXTURE_COORD_ARRAY);
- GLES10.glColorMask(true, true, true, true);
-
- // draw the white highlight (we use the last vertices)
- if (mMode == MODE_COOL_DOWN) {
- GLES10.glColor4f(ag, ag, ag, 1.0f);
- GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
- }
+ GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 4);
// clean up
- GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
- GLES10.glDisable(GLES10.GL_BLEND);
+ GLES20.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
+ GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
}
- /**
- * Draws a frame where the electron beam has been stretched out into
- * a thin white horizontal line that fades as it collapses inwards.
- *
- * @param stretch The stretch factor. 0.0 is maximum stretch / no fade,
- * 1.0 is collapsed / maximum fade.
- */
- private void drawHStretch(float stretch) {
- // compute interpolation scale factor
- final float ag = scurve(stretch, 8.0f);
- if (DEBUG) {
- Slog.d(TAG, "drawHStretch: stretch=" + stretch + ", ag=" + ag);
- }
-
- if (stretch < 1.0f) {
- // bind vertex buffer
- GLES10.glVertexPointer(2, GLES10.GL_FLOAT, 0, mVertexBuffer);
- GLES10.glEnableClientState(GLES10.GL_VERTEX_ARRAY);
-
- // draw narrow fading white line
- setHStretchQuad(mVertexBuffer, mDisplayWidth, mDisplayHeight, ag);
- GLES10.glColor4f(1.0f - ag*0.75f, 1.0f - ag*0.75f, 1.0f - ag*0.75f, 1.0f);
- GLES10.glDrawArrays(GLES10.GL_TRIANGLE_FAN, 0, 4);
-
- // clean up
- GLES10.glDisableClientState(GLES10.GL_VERTEX_ARRAY);
- }
- }
-
- private static void setVStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
- final float w = dw + (dw * a);
- final float h = dh - (dh * a);
- final float x = (dw - w) * 0.5f;
- final float y = (dh - h) * 0.5f;
- setQuad(vtx, x, y, w, h);
- }
-
- private static void setHStretchQuad(FloatBuffer vtx, float dw, float dh, float a) {
- final float w = 2 * dw * (1.0f - a);
- final float h = 1.0f;
- final float x = (dw - w) * 0.5f;
- final float y = (dh - h) * 0.5f;
- setQuad(vtx, x, y, w, h);
- }
-
- private static void setQuad(FloatBuffer vtx, float x, float y, float w, float h) {
- if (DEBUG) {
- Slog.d(TAG, "setQuad: x=" + x + ", y=" + y + ", w=" + w + ", h=" + h);
- }
- vtx.put(0, x);
- vtx.put(1, y);
- vtx.put(2, x);
- vtx.put(3, y + h);
- vtx.put(4, x + w);
- vtx.put(5, y + h);
- vtx.put(6, x + w);
- vtx.put(7, y);
+ private void ortho(float left, float right, float bottom, float top, float znear, float zfar) {
+ mProjMatrix[0] = 2f / (right - left);
+ mProjMatrix[1] = 0;
+ mProjMatrix[2] = 0;
+ mProjMatrix[3] = 0;
+ mProjMatrix[4] = 0;
+ mProjMatrix[5] = 2f / (top - bottom);
+ mProjMatrix[6] = 0;
+ mProjMatrix[7] = 0;
+ mProjMatrix[8] = 0;
+ mProjMatrix[9] = 0;
+ mProjMatrix[10] = -2f / (zfar - znear);
+ mProjMatrix[11] = 0;
+ mProjMatrix[12] = -(right + left) / (right - left);
+ mProjMatrix[13] = -(top + bottom) / (top - bottom);
+ mProjMatrix[14] = -(zfar + znear) / (zfar - znear);
+ mProjMatrix[15] = 1f;
}
private boolean captureScreenshotTextureAndSetViewport() {
@@ -385,7 +429,7 @@
}
try {
if (!mTexNamesGenerated) {
- GLES10.glGenTextures(1, mTexNames, 0);
+ GLES20.glGenTextures(1, mTexNames, 0);
if (checkGlErrors("glGenTextures")) {
return false;
}
@@ -413,15 +457,8 @@
mTexCoordBuffer.put(6, 1f); mTexCoordBuffer.put(7, 0f);
// Set up our viewport.
- GLES10.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
- GLES10.glMatrixMode(GLES10.GL_PROJECTION);
- GLES10.glLoadIdentity();
- GLES10.glOrthof(0, mDisplayWidth, 0, mDisplayHeight, 0, 1);
- GLES10.glMatrixMode(GLES10.GL_MODELVIEW);
- GLES10.glLoadIdentity();
- GLES10.glMatrixMode(GLES10.GL_TEXTURE);
- GLES10.glLoadIdentity();
- GLES10.glLoadMatrixf(mTexMatrix, 0);
+ GLES20.glViewport(0, 0, mDisplayWidth, mDisplayHeight);
+ ortho(0, mDisplayWidth, 0, mDisplayHeight, -1, 1);
} finally {
detachEglContext();
}
@@ -433,7 +470,7 @@
mTexNamesGenerated = false;
if (attachEglContext()) {
try {
- GLES10.glDeleteTextures(1, mTexNames, 0);
+ GLES20.glDeleteTextures(1, mTexNames, 0);
checkGlErrors("glDeleteTextures");
} finally {
detachEglContext();
@@ -460,6 +497,8 @@
if (mEglConfig == null) {
int[] eglConfigAttribList = new int[] {
+ EGL14.EGL_RENDERABLE_TYPE,
+ EGL14.EGL_OPENGL_ES2_BIT,
EGL14.EGL_RED_SIZE, 8,
EGL14.EGL_GREEN_SIZE, 8,
EGL14.EGL_BLUE_SIZE, 8,
@@ -478,6 +517,7 @@
if (mEglContext == null) {
int[] eglContextAttribList = new int[] {
+ EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,
EGL14.EGL_NONE
};
mEglContext = EGL14.eglCreateContext(mEglDisplay, mEglConfig,
@@ -490,16 +530,6 @@
return true;
}
- /* not used because it is too expensive to create / destroy contexts all of the time
- private void destroyEglContext() {
- if (mEglContext != null) {
- if (!EGL14.eglDestroyContext(mEglDisplay, mEglContext)) {
- logEglError("eglDestroyContext");
- }
- mEglContext = null;
- }
- }*/
-
private boolean createSurface() {
if (mSurfaceSession == null) {
mSurfaceSession = new SurfaceSession();
@@ -516,7 +546,7 @@
flags = SurfaceControl.OPAQUE | SurfaceControl.HIDDEN;
}
mSurfaceControl = new SurfaceControl(mSurfaceSession,
- "ElectronBeam", mDisplayWidth, mDisplayHeight,
+ "ColorFade", mDisplayWidth, mDisplayHeight,
PixelFormat.OPAQUE, flags);
} catch (OutOfResourcesException ex) {
Slog.e(TAG, "Unable to create surface.", ex);
@@ -584,7 +614,7 @@
if (!mSurfaceVisible || mSurfaceAlpha != alpha) {
SurfaceControl.openTransaction();
try {
- mSurfaceControl.setLayer(ELECTRON_BEAM_LAYER);
+ mSurfaceControl.setLayer(COLOR_FADE_LAYER);
mSurfaceControl.setAlpha(alpha);
mSurfaceControl.show();
} finally {
@@ -614,34 +644,6 @@
}
}
- /**
- * Interpolates a value in the range 0 .. 1 along a sigmoid curve
- * yielding a result in the range 0 .. 1 scaled such that:
- * scurve(0) == 0, scurve(0.5) == 0.5, scurve(1) == 1.
- */
- private static float scurve(float value, float s) {
- // A basic sigmoid has the form y = 1.0f / FloatMap.exp(-x * s).
- // Here we take the input datum and shift it by 0.5 so that the
- // domain spans the range -0.5 .. 0.5 instead of 0 .. 1.
- final float x = value - 0.5f;
-
- // Next apply the sigmoid function to the scaled value
- // which produces a value in the range 0 .. 1 so we subtract
- // 0.5 to get a value in the range -0.5 .. 0.5 instead.
- final float y = sigmoid(x, s) - 0.5f;
-
- // To obtain the desired boundary conditions we need to scale
- // the result so that it fills a range of -1 .. 1.
- final float v = sigmoid(0.5f, s) - 0.5f;
-
- // And finally remap the value back to a range of 0 .. 1.
- return y / v * 0.5f + 0.5f;
- }
-
- private static float sigmoid(float x, float s) {
- return 1.0f / (1.0f + FloatMath.exp(-x * s));
- }
-
private static FloatBuffer createNativeFloatBuffer(int size) {
ByteBuffer bb = ByteBuffer.allocateDirect(size * 4);
bb.order(ByteOrder.nativeOrder());
@@ -659,7 +661,7 @@
private static boolean checkGlErrors(String func, boolean log) {
boolean hadError = false;
int error;
- while ((error = GLES10.glGetError()) != GLES10.GL_NO_ERROR) {
+ while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
if (log) {
Slog.e(TAG, func + " failed: error " + error, new Throwable());
}
@@ -670,7 +672,7 @@
public void dump(PrintWriter pw) {
pw.println();
- pw.println("Electron Beam State:");
+ pw.println("Color Fade State:");
pw.println(" mPrepared=" + mPrepared);
pw.println(" mMode=" + mMode);
pw.println(" mDisplayLayerStack=" + mDisplayLayerStack);
@@ -685,7 +687,7 @@
* Updates the position and transformation of the matrix whenever the display
* is rotated. This is a little tricky because the display transaction
* callback can be invoked on any thread, not necessarily the thread that
- * owns the electron beam.
+ * owns the color fade.
*/
private static final class NaturalSurfaceLayout implements DisplayTransactionListener {
private final DisplayManagerInternal mDisplayManagerInternal;
@@ -725,7 +727,8 @@
mSurfaceControl.setMatrix(0, -1, 1, 0);
break;
case Surface.ROTATION_180:
- mSurfaceControl.setPosition(displayInfo.logicalWidth, displayInfo.logicalHeight);
+ mSurfaceControl.setPosition(displayInfo.logicalWidth,
+ displayInfo.logicalHeight);
mSurfaceControl.setMatrix(-1, 0, 0, -1);
break;
case Surface.ROTATION_270:
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index d0e4b33..9a67321 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -64,7 +64,7 @@
* blocker as long as the display is not ready. So most of the work done here
* does not need to worry about holding a suspend blocker unless it happens
* independently of the display ready signal.
- *
+ *
* For debugging, you can make the electron beam and brightness animations run
* slower by changing the "animator duration scale" option in Development Settings.
*/
@@ -78,14 +78,14 @@
// We might want to turn this off if we cannot get a guarantee that the screen
// actually turns on and starts showing new content after the call to set the
// screen state returns. Playing the animation can also be somewhat slow.
- private static final boolean USE_ELECTRON_BEAM_ON_ANIMATION = false;
+ private static final boolean USE_COLOR_FADE_ON_ANIMATION = false;
// The minimum reduction in brightness when dimmed.
private static final int SCREEN_DIM_MINIMUM_REDUCTION = 10;
- private static final int ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS = 250;
- private static final int ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS = 400;
+ private static final int COLOR_FADE_ON_ANIMATION_DURATION_MILLIS = 250;
+ private static final int COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS = 600;
private static final int MSG_UPDATE_POWER_STATE = 1;
private static final int MSG_PROXIMITY_SENSOR_DEBOUNCED = 2;
@@ -107,6 +107,8 @@
private final Object mLock = new Object();
+ private final Context mContext;
+
// Our handler.
private final DisplayControllerHandler mHandler;
@@ -146,7 +148,7 @@
// True if we should fade the screen while turning it off, false if we should play
// a stylish electron beam animation instead.
- private boolean mElectronBeamFadesConfig;
+ private boolean mColorFadeFadesConfig;
// The pending power request.
// Initially null until the first call to requestPowerState.
@@ -223,8 +225,8 @@
private AutomaticBrightnessController mAutomaticBrightnessController;
// Animators.
- private ObjectAnimator mElectronBeamOnAnimator;
- private ObjectAnimator mElectronBeamOffAnimator;
+ private ObjectAnimator mColorFadeOnAnimator;
+ private ObjectAnimator mColorFadeOffAnimator;
private RampAnimator<DisplayPowerState> mScreenBrightnessRampAnimator;
/**
@@ -240,6 +242,7 @@
mLights = LocalServices.getService(LightsManager.class);
mSensorManager = sensorManager;
mBlanker = blanker;
+ mContext = context;
final Resources resources = context.getResources();
@@ -287,7 +290,7 @@
mScreenBrightnessRangeMinimum = screenBrightnessRangeMinimum;
- mElectronBeamFadesConfig = resources.getBoolean(
+ mColorFadeFadesConfig = resources.getBoolean(
com.android.internal.R.bool.config_animateScreenLights);
if (!DEBUG_PRETEND_PROXIMITY_SENSOR_ABSENT) {
@@ -378,17 +381,17 @@
// In the future, we might manage multiple displays independently.
mPowerState = new DisplayPowerState(mBlanker,
mLights.getLight(LightsManager.LIGHT_ID_BACKLIGHT),
- new ElectronBeam(Display.DEFAULT_DISPLAY));
+ new ColorFade(Display.DEFAULT_DISPLAY));
- mElectronBeamOnAnimator = ObjectAnimator.ofFloat(
- mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 0.0f, 1.0f);
- mElectronBeamOnAnimator.setDuration(ELECTRON_BEAM_ON_ANIMATION_DURATION_MILLIS);
- mElectronBeamOnAnimator.addListener(mAnimatorListener);
+ mColorFadeOnAnimator = ObjectAnimator.ofFloat(
+ mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 0.0f, 1.0f);
+ mColorFadeOnAnimator.setDuration(COLOR_FADE_ON_ANIMATION_DURATION_MILLIS);
+ mColorFadeOnAnimator.addListener(mAnimatorListener);
- mElectronBeamOffAnimator = ObjectAnimator.ofFloat(
- mPowerState, DisplayPowerState.ELECTRON_BEAM_LEVEL, 1.0f, 0.0f);
- mElectronBeamOffAnimator.setDuration(ELECTRON_BEAM_OFF_ANIMATION_DURATION_MILLIS);
- mElectronBeamOffAnimator.addListener(mAnimatorListener);
+ mColorFadeOffAnimator = ObjectAnimator.ofFloat(
+ mPowerState, DisplayPowerState.COLOR_FADE_LEVEL, 1.0f, 0.0f);
+ mColorFadeOffAnimator.setDuration(COLOR_FADE_OFF_ANIMATION_DURATION_MILLIS);
+ mColorFadeOffAnimator.addListener(mAnimatorListener);
mScreenBrightnessRampAnimator = new RampAnimator<DisplayPowerState>(
mPowerState, DisplayPowerState.SCREEN_BRIGHTNESS);
@@ -600,34 +603,34 @@
// Wait for previous off animation to complete beforehand.
// It is relatively short but if we cancel it and switch to the
// on animation immediately then the results are pretty ugly.
- if (!mElectronBeamOffAnimator.isStarted()) {
+ if (!mColorFadeOffAnimator.isStarted()) {
// Turn the screen on. The contents of the screen may not yet
// be visible if the electron beam has not been dismissed because
// its last frame of animation is solid black.
setScreenState(Display.STATE_ON);
if (mPowerRequest.blockScreenOn
- && mPowerState.getElectronBeamLevel() == 0.0f) {
+ && mPowerState.getColorFadeLevel() == 0.0f) {
blockScreenOn();
} else {
unblockScreenOn();
- if (USE_ELECTRON_BEAM_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
+ if (USE_COLOR_FADE_ON_ANIMATION && mPowerRequest.isBrightOrDim()) {
// Perform screen on animation.
- if (!mElectronBeamOnAnimator.isStarted()) {
- if (mPowerState.getElectronBeamLevel() == 1.0f) {
- mPowerState.dismissElectronBeam();
- } else if (mPowerState.prepareElectronBeam(
- mElectronBeamFadesConfig ?
- ElectronBeam.MODE_FADE :
- ElectronBeam.MODE_WARM_UP)) {
- mElectronBeamOnAnimator.start();
+ if (!mColorFadeOnAnimator.isStarted()) {
+ if (mPowerState.getColorFadeLevel() == 1.0f) {
+ mPowerState.dismissColorFade();
+ } else if (mPowerState.prepareColorFade(mContext,
+ mColorFadeFadesConfig ?
+ ColorFade.MODE_FADE :
+ ColorFade.MODE_WARM_UP)) {
+ mColorFadeOnAnimator.start();
} else {
- mElectronBeamOnAnimator.end();
+ mColorFadeOnAnimator.end();
}
}
} else {
// Skip screen on animation.
- mPowerState.setElectronBeamLevel(1.0f);
- mPowerState.dismissElectronBeam();
+ mPowerState.setColorFadeLevel(1.0f);
+ mPowerState.dismissColorFade();
}
}
}
@@ -640,8 +643,8 @@
|| mPowerState.getScreenState() != Display.STATE_ON) {
// Set screen state and dismiss the black surface without fanfare.
setScreenState(state);
- mPowerState.setElectronBeamLevel(1.0f);
- mPowerState.dismissElectronBeam();
+ mPowerState.setColorFadeLevel(1.0f);
+ mPowerState.dismissColorFade();
}
} else if (state == Display.STATE_DOZE_SUSPEND) {
// Want screen dozing and suspended.
@@ -652,27 +655,27 @@
|| mPowerState.getScreenState() == Display.STATE_DOZE_SUSPEND) {
// Set screen state and dismiss the black surface without fanfare.
setScreenState(state);
- mPowerState.setElectronBeamLevel(1.0f);
- mPowerState.dismissElectronBeam();
+ mPowerState.setColorFadeLevel(1.0f);
+ mPowerState.dismissColorFade();
}
} else {
// Want screen off.
// Wait for previous on animation to complete beforehand.
unblockScreenOn();
- if (!mElectronBeamOnAnimator.isStarted()) {
+ if (!mColorFadeOnAnimator.isStarted()) {
if (mPowerRequest.policy == DisplayPowerRequest.POLICY_OFF) {
// Perform screen off animation.
- if (!mElectronBeamOffAnimator.isStarted()) {
- if (mPowerState.getElectronBeamLevel() == 0.0f) {
+ if (!mColorFadeOffAnimator.isStarted()) {
+ if (mPowerState.getColorFadeLevel() == 0.0f) {
setScreenState(Display.STATE_OFF);
- } else if (mPowerState.prepareElectronBeam(
- mElectronBeamFadesConfig ?
- ElectronBeam.MODE_FADE :
- ElectronBeam.MODE_COOL_DOWN)
+ } else if (mPowerState.prepareColorFade(mContext,
+ mColorFadeFadesConfig ?
+ ColorFade.MODE_FADE :
+ ColorFade.MODE_COOL_DOWN)
&& mPowerState.getScreenState() != Display.STATE_OFF) {
- mElectronBeamOffAnimator.start();
+ mColorFadeOffAnimator.start();
} else {
- mElectronBeamOffAnimator.end();
+ mColorFadeOffAnimator.end();
}
}
} else {
@@ -687,8 +690,8 @@
// which will be handled asynchronously.
if (mustNotify
&& !mScreenOnWasBlocked
- && !mElectronBeamOnAnimator.isStarted()
- && !mElectronBeamOffAnimator.isStarted()
+ && !mColorFadeOnAnimator.isStarted()
+ && !mColorFadeOffAnimator.isStarted()
&& !mScreenBrightnessRampAnimator.isAnimating()
&& mPowerState.waitUntilClean(mCleanListener)) {
synchronized (mLock) {
@@ -936,13 +939,13 @@
pw.println(" mScreenBrightnessRampAnimator.isAnimating()=" +
mScreenBrightnessRampAnimator.isAnimating());
- if (mElectronBeamOnAnimator != null) {
- pw.println(" mElectronBeamOnAnimator.isStarted()=" +
- mElectronBeamOnAnimator.isStarted());
+ if (mColorFadeOnAnimator != null) {
+ pw.println(" mColorFadeOnAnimator.isStarted()=" +
+ mColorFadeOnAnimator.isStarted());
}
- if (mElectronBeamOffAnimator != null) {
- pw.println(" mElectronBeamOffAnimator.isStarted()=" +
- mElectronBeamOffAnimator.isStarted());
+ if (mColorFadeOffAnimator != null) {
+ pw.println(" mColorFadeOffAnimator.isStarted()=" +
+ mColorFadeOffAnimator.isStarted());
}
if (mPowerState != null) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerState.java b/services/core/java/com/android/server/display/DisplayPowerState.java
index 4821e74..6522b89 100644
--- a/services/core/java/com/android/server/display/DisplayPowerState.java
+++ b/services/core/java/com/android/server/display/DisplayPowerState.java
@@ -18,6 +18,7 @@
import com.android.server.lights.Light;
+import android.content.Context;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Looper;
@@ -56,7 +57,7 @@
private final Choreographer mChoreographer;
private final DisplayBlanker mBlanker;
private final Light mBacklight;
- private final ElectronBeam mElectronBeam;
+ private final ColorFade mColorFade;
private final PhotonicModulator mPhotonicModulator;
private int mScreenState;
@@ -64,19 +65,19 @@
private boolean mScreenReady;
private boolean mScreenUpdatePending;
- private boolean mElectronBeamPrepared;
- private float mElectronBeamLevel;
- private boolean mElectronBeamReady;
- private boolean mElectronBeamDrawPending;
+ private boolean mColorFadePrepared;
+ private float mColorFadeLevel;
+ private boolean mColorFadeReady;
+ private boolean mColorFadeDrawPending;
private Runnable mCleanListener;
- public DisplayPowerState(DisplayBlanker blanker, Light backlight, ElectronBeam electronBeam) {
+ public DisplayPowerState(DisplayBlanker blanker, Light backlight, ColorFade electronBeam) {
mHandler = new Handler(true /*async*/);
mChoreographer = Choreographer.getInstance();
mBlanker = blanker;
mBacklight = backlight;
- mElectronBeam = electronBeam;
+ mColorFade = electronBeam;
mPhotonicModulator = new PhotonicModulator();
// At boot time, we know that the screen is on and the electron beam
@@ -89,21 +90,21 @@
mScreenBrightness = PowerManager.BRIGHTNESS_ON;
scheduleScreenUpdate();
- mElectronBeamPrepared = false;
- mElectronBeamLevel = 1.0f;
- mElectronBeamReady = true;
+ mColorFadePrepared = false;
+ mColorFadeLevel = 1.0f;
+ mColorFadeReady = true;
}
- public static final FloatProperty<DisplayPowerState> ELECTRON_BEAM_LEVEL =
+ public static final FloatProperty<DisplayPowerState> COLOR_FADE_LEVEL =
new FloatProperty<DisplayPowerState>("electronBeamLevel") {
@Override
public void setValue(DisplayPowerState object, float value) {
- object.setElectronBeamLevel(value);
+ object.setColorFadeLevel(value);
}
@Override
public Float get(DisplayPowerState object) {
- return object.getElectronBeamLevel();
+ return object.getColorFadeLevel();
}
};
@@ -176,26 +177,26 @@
* @param mode The electron beam animation mode to prepare.
* @return True if the electron beam was prepared.
*/
- public boolean prepareElectronBeam(int mode) {
- if (!mElectronBeam.prepare(mode)) {
- mElectronBeamPrepared = false;
- mElectronBeamReady = true;
+ public boolean prepareColorFade(Context context, int mode) {
+ if (!mColorFade.prepare(context, mode)) {
+ mColorFadePrepared = false;
+ mColorFadeReady = true;
return false;
}
- mElectronBeamPrepared = true;
- mElectronBeamReady = false;
- scheduleElectronBeamDraw();
+ mColorFadePrepared = true;
+ mColorFadeReady = false;
+ scheduleColorFadeDraw();
return true;
}
/**
* Dismisses the electron beam surface.
*/
- public void dismissElectronBeam() {
- mElectronBeam.dismiss();
- mElectronBeamPrepared = false;
- mElectronBeamReady = true;
+ public void dismissColorFade() {
+ mColorFade.dismiss();
+ mColorFadePrepared = false;
+ mColorFadeReady = true;
}
/**
@@ -211,20 +212,20 @@
*
* @param level The level, ranges from 0.0 (full off) to 1.0 (full on).
*/
- public void setElectronBeamLevel(float level) {
- if (mElectronBeamLevel != level) {
+ public void setColorFadeLevel(float level) {
+ if (mColorFadeLevel != level) {
if (DEBUG) {
- Slog.d(TAG, "setElectronBeamLevel: level=" + level);
+ Slog.d(TAG, "setColorFadeLevel: level=" + level);
}
- mElectronBeamLevel = level;
+ mColorFadeLevel = level;
if (mScreenState != Display.STATE_OFF) {
mScreenReady = false;
scheduleScreenUpdate(); // update backlight brightness
}
- if (mElectronBeamPrepared) {
- mElectronBeamReady = false;
- scheduleElectronBeamDraw();
+ if (mColorFadePrepared) {
+ mColorFadeReady = false;
+ scheduleColorFadeDraw();
}
}
}
@@ -232,8 +233,8 @@
/**
* Gets the level of the electron beam steering current.
*/
- public float getElectronBeamLevel() {
- return mElectronBeamLevel;
+ public float getColorFadeLevel() {
+ return mColorFadeLevel;
}
/**
@@ -243,7 +244,7 @@
* The listener always overrides any previously set listener.
*/
public boolean waitUntilClean(Runnable listener) {
- if (!mScreenReady || !mElectronBeamReady) {
+ if (!mScreenReady || !mColorFadeReady) {
mCleanListener = listener;
return false;
} else {
@@ -259,13 +260,13 @@
pw.println(" mScreenBrightness=" + mScreenBrightness);
pw.println(" mScreenReady=" + mScreenReady);
pw.println(" mScreenUpdatePending=" + mScreenUpdatePending);
- pw.println(" mElectronBeamPrepared=" + mElectronBeamPrepared);
- pw.println(" mElectronBeamLevel=" + mElectronBeamLevel);
- pw.println(" mElectronBeamReady=" + mElectronBeamReady);
- pw.println(" mElectronBeamDrawPending=" + mElectronBeamDrawPending);
+ pw.println(" mColorFadePrepared=" + mColorFadePrepared);
+ pw.println(" mColorFadeLevel=" + mColorFadeLevel);
+ pw.println(" mColorFadeReady=" + mColorFadeReady);
+ pw.println(" mColorFadeDrawPending=" + mColorFadeDrawPending);
mPhotonicModulator.dump(pw);
- mElectronBeam.dump(pw);
+ mColorFade.dump(pw);
}
private void scheduleScreenUpdate() {
@@ -280,17 +281,17 @@
mHandler.post(mScreenUpdateRunnable);
}
- private void scheduleElectronBeamDraw() {
- if (!mElectronBeamDrawPending) {
- mElectronBeamDrawPending = true;
+ private void scheduleColorFadeDraw() {
+ if (!mColorFadeDrawPending) {
+ mColorFadeDrawPending = true;
mChoreographer.postCallback(Choreographer.CALLBACK_TRAVERSAL,
- mElectronBeamDrawRunnable, null);
+ mColorFadeDrawRunnable, null);
}
}
private void invokeCleanListenerIfNeeded() {
final Runnable listener = mCleanListener;
- if (listener != null && mScreenReady && mElectronBeamReady) {
+ if (listener != null && mScreenReady && mColorFadeReady) {
mCleanListener = null;
listener.run();
}
@@ -302,7 +303,7 @@
mScreenUpdatePending = false;
int brightness = mScreenState != Display.STATE_OFF
- && mElectronBeamLevel > 0f ? mScreenBrightness : 0;
+ && mColorFadeLevel > 0f ? mScreenBrightness : 0;
if (mPhotonicModulator.setState(mScreenState, brightness)) {
if (DEBUG) {
Slog.d(TAG, "Screen ready");
@@ -317,16 +318,16 @@
}
};
- private final Runnable mElectronBeamDrawRunnable = new Runnable() {
+ private final Runnable mColorFadeDrawRunnable = new Runnable() {
@Override
public void run() {
- mElectronBeamDrawPending = false;
+ mColorFadeDrawPending = false;
- if (mElectronBeamPrepared) {
- mElectronBeam.draw(mElectronBeamLevel);
+ if (mColorFadePrepared) {
+ mColorFade.draw(mColorFadeLevel);
}
- mElectronBeamReady = true;
+ mColorFadeReady = true;
invokeCleanListenerIfNeeded();
}
};
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index cef127e..44b7f01 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1402,7 +1402,9 @@
boolean didDexOptLibraryOrTool = false;
- final List<String> instructionSets = getAllInstructionSets();
+ final List<String> allInstructionSets = getAllInstructionSets();
+ final String[] dexCodeInstructionSets =
+ getDexCodeInstructionSets(allInstructionSets.toArray(new String[allInstructionSets.size()]));
/**
* Ensure all external libraries have had dexopt run on them.
@@ -1412,7 +1414,7 @@
// (and framework jars) into all available architectures. It's possible
// to compile them only when we come across an app that uses them (there's
// already logic for that in scanPackageLI) but that adds some complexity.
- for (String instructionSet : instructionSets) {
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (SharedLibraryEntry libEntry : mSharedLibraries.values()) {
final String lib = libEntry.path;
if (lib == null) {
@@ -1421,16 +1423,16 @@
try {
byte dexoptRequired = DexFile.isDexOptNeededInternal(lib, null,
- instructionSet,
+ dexCodeInstructionSet,
false);
if (dexoptRequired != DexFile.UP_TO_DATE) {
alreadyDexOpted.add(lib);
// The list of "shared libraries" we have at this point is
if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
- mInstaller.dexopt(lib, Process.SYSTEM_UID, true, instructionSet);
+ mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
} else {
- mInstaller.patchoat(lib, Process.SYSTEM_UID, true, instructionSet);
+ mInstaller.patchoat(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet);
}
didDexOptLibraryOrTool = true;
}
@@ -1465,7 +1467,7 @@
// TODO: We could compile these only for the most preferred ABI. We should
// first double check that the dex files for these commands are not referenced
// by other system apps.
- for (String instructionSet : instructionSets) {
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
for (int i=0; i<frameworkFiles.length; i++) {
File libPath = new File(frameworkDir, frameworkFiles[i]);
String path = libPath.getPath();
@@ -1479,13 +1481,13 @@
}
try {
byte dexoptRequired = DexFile.isDexOptNeededInternal(path, null,
- instructionSet,
+ dexCodeInstructionSet,
false);
if (dexoptRequired == DexFile.DEXOPT_NEEDED) {
- mInstaller.dexopt(path, Process.SYSTEM_UID, true, instructionSet);
+ mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
didDexOptLibraryOrTool = true;
} else if (dexoptRequired == DexFile.PATCHOAT_NEEDED) {
- mInstaller.patchoat(path, Process.SYSTEM_UID, true, instructionSet);
+ mInstaller.patchoat(path, Process.SYSTEM_UID, true, dexCodeInstructionSet);
didDexOptLibraryOrTool = true;
}
} catch (FileNotFoundException e) {
@@ -1509,8 +1511,8 @@
// small maintenance release update that the library and tool
// jars may be unchanged but APK could be removed resulting in
// unused dalvik-cache files.
- for (String instructionSet : instructionSets) {
- mInstaller.pruneDexCache(instructionSet);
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ mInstaller.pruneDexCache(dexCodeInstructionSet);
}
// Additionally, delete all dex files from the root directory
@@ -4632,9 +4634,10 @@
// 1.) we need to dexopt, either because we are forced or it is needed
// 2.) we are defering a needed dexopt
// 3.) we are skipping an unneeded dexopt
+ final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String path : paths) {
- for (String instructionSet : instructionSets) {
- if (!forceDex && pkg.mDexOptPerformed.contains(instructionSet)) {
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ if (!forceDex && pkg.mDexOptPerformed.contains(dexCodeInstructionSet)) {
continue;
}
@@ -4645,13 +4648,13 @@
// odex file and it matches the checksum of the image but not its base address,
// meaning we need to move it.
final byte isDexOptNeeded = DexFile.isDexOptNeededInternal(path,
- pkg.packageName, instructionSet, defer);
+ pkg.packageName, dexCodeInstructionSet, defer);
if (forceDex || (!defer && isDexOptNeeded == DexFile.DEXOPT_NEEDED)) {
Log.i(TAG, "Running dexopt on: " + path + " pkg="
- + pkg.applicationInfo.packageName + " isa=" + instructionSet);
+ + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet);
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
final int ret = mInstaller.dexopt(path, sharedGid, !isForwardLocked(pkg),
- pkg.packageName, instructionSet);
+ pkg.packageName, dexCodeInstructionSet);
if (ret < 0) {
// Don't bother running dexopt again if we failed, it will probably
@@ -4660,13 +4663,13 @@
return DEX_OPT_FAILED;
} else {
performedDexOpt = true;
- pkg.mDexOptPerformed.add(instructionSet);
+ pkg.mDexOptPerformed.add(dexCodeInstructionSet);
}
} else if (!defer && isDexOptNeeded == DexFile.PATCHOAT_NEEDED) {
Log.i(TAG, "Running patchoat on: " + pkg.applicationInfo.packageName);
final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
final int ret = mInstaller.patchoat(path, sharedGid, !isForwardLocked(pkg),
- pkg.packageName, instructionSet);
+ pkg.packageName, dexCodeInstructionSet);
if (ret < 0) {
// Don't bother running patchoat again if we failed, it will probably
@@ -4675,7 +4678,7 @@
return DEX_OPT_FAILED;
} else {
performedDexOpt = true;
- pkg.mDexOptPerformed.add(instructionSet);
+ pkg.mDexOptPerformed.add(dexCodeInstructionSet);
}
}
@@ -4764,6 +4767,23 @@
return allInstructionSets;
}
+ /**
+ * Returns the instruction set that should be used to compile dex code. In the presence of
+ * a native bridge this might be different than the one shared libraries use.
+ */
+ private static String getDexCodeInstructionSet(String sharedLibraryIsa) {
+ String dexCodeIsa = SystemProperties.get("ro.dalvik.vm.isa." + sharedLibraryIsa);
+ return (dexCodeIsa.isEmpty() ? sharedLibraryIsa : dexCodeIsa);
+ }
+
+ private static String[] getDexCodeInstructionSets(String[] instructionSets) {
+ HashSet<String> dexCodeInstructionSets = new HashSet<String>(instructionSets.length);
+ for (String instructionSet : instructionSets) {
+ dexCodeInstructionSets.add(getDexCodeInstructionSet(instructionSet));
+ }
+ return dexCodeInstructionSets.toArray(new String[dexCodeInstructionSets.size()]);
+ }
+
@Override
public void forceDexOpt(String packageName) {
enforceSystemOrRoot("forceDexOpt");
@@ -6183,7 +6203,8 @@
ps.pkg.applicationInfo.primaryCpuAbi = null;
return;
} else {
- mInstaller.rmdex(ps.codePathString, getPreferredInstructionSet());
+ mInstaller.rmdex(ps.codePathString,
+ getDexCodeInstructionSet(getPreferredInstructionSet()));
}
}
}
@@ -9412,10 +9433,10 @@
if (instructionSets == null) {
throw new IllegalStateException("instructionSet == null");
}
-
+ String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
for (String codePath : allCodePaths) {
- for (String instructionSet : instructionSets) {
- int retCode = mInstaller.rmdex(codePath, instructionSet);
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ int retCode = mInstaller.rmdex(codePath, dexCodeInstructionSet);
if (retCode < 0) {
Slog.w(TAG, "Couldn't remove dex file for package: "
+ " at location " + codePath + ", retcode=" + retCode);
@@ -9695,8 +9716,9 @@
if (instructionSets == null) {
throw new IllegalStateException("instructionSet == null");
}
- for (String instructionSet : instructionSets) {
- int retCode = mInstaller.rmdex(sourceFile, instructionSet);
+ String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
+ int retCode = mInstaller.rmdex(sourceFile, dexCodeInstructionSet);
if (retCode < 0) {
Slog.w(TAG, "Couldn't remove dex file for package: "
+ " at location "
@@ -10199,9 +10221,10 @@
// TODO: extend to move split APK dex files
if ((newPackage.applicationInfo.flags&ApplicationInfo.FLAG_HAS_CODE) != 0) {
final String[] instructionSets = getAppDexInstructionSets(newPackage.applicationInfo);
- for (String instructionSet : instructionSets) {
+ String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
+ for (String dexCodeInstructionSet : dexCodeInstructionSets) {
int retCode = mInstaller.movedex(oldCodePath, newPackage.baseCodePath,
- instructionSet);
+ dexCodeInstructionSet);
if (retCode != 0) {
/*
* Programs may be lazily run through dexopt, so the
@@ -10212,8 +10235,8 @@
* file from a previous version of the package.
*/
newPackage.mDexOptPerformed.clear();
- mInstaller.rmdex(oldCodePath, instructionSet);
- mInstaller.rmdex(newPackage.baseCodePath, instructionSet);
+ mInstaller.rmdex(oldCodePath, dexCodeInstructionSet);
+ mInstaller.rmdex(newPackage.baseCodePath, dexCodeInstructionSet);
}
}
}
@@ -11360,9 +11383,9 @@
// not just the first level.
// TODO(multiArch): Extend getSizeInfo to look at *all* instruction sets, not
// just the primary.
+ String[] dexCodeInstructionSets = getDexCodeInstructionSets(getAppDexInstructionSets(ps));
int res = mInstaller.getSizeInfo(packageName, userHandle, p.baseCodePath, libDirRoot,
- publicSrcDir, asecPath, getAppDexInstructionSets(ps),
- pStats);
+ publicSrcDir, asecPath, dexCodeInstructionSets, pStats);
if (res < 0) {
return false;
}