summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/SurfaceControl.java33
-rw-r--r--core/java/android/view/Window.java26
-rw-r--r--core/java/android/view/WindowManager.java47
-rw-r--r--core/jni/android_view_SurfaceControl.cpp41
-rw-r--r--core/res/res/values/cm_symbols.xml4
-rw-r--r--core/res/res/values/config.xml4
-rw-r--r--packages/SystemUI/AndroidManifest.xml3
-rw-r--r--packages/SystemUI/res/values/colors.xml1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/BlurLayer.java196
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java14
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java1
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java88
-rw-r--r--services/core/java/com/android/server/wm/BlurLayer.java313
-rw-r--r--services/core/java/com/android/server/wm/DisplayContent.java29
-rw-r--r--services/core/java/com/android/server/wm/TaskStack.java98
-rw-r--r--services/core/java/com/android/server/wm/WindowAnimator.java16
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java47
-rw-r--r--services/core/java/com/android/server/wm/WindowStateAnimator.java120
19 files changed, 1070 insertions, 12 deletions
diff --git a/core/java/android/view/SurfaceControl.java b/core/java/android/view/SurfaceControl.java
index 584fe76..e839468 100644
--- a/core/java/android/view/SurfaceControl.java
+++ b/core/java/android/view/SurfaceControl.java
@@ -58,6 +58,11 @@ public class SurfaceControl {
private static native void nativeSetWindowCrop(long nativeObject, int l, int t, int r, int b);
private static native void nativeSetLayerStack(long nativeObject, int layerStack);
+ private static native void nativeSetBlur(long nativeObject, float blur);
+ private static native void nativeSetBlurMaskSurface(long nativeObject, long maskLayerNativeObject);
+ private static native void nativeSetBlurMaskSampling(long nativeObject, int blurMaskSampling);
+ private static native void nativeSetBlurMaskAlphaThreshold(long nativeObject, float alpha);
+
private static native boolean nativeClearContentFrameStats(long nativeObject);
private static native boolean nativeGetContentFrameStats(long nativeObject, WindowContentFrameStats outStats);
private static native boolean nativeClearAnimationFrameStats();
@@ -170,6 +175,11 @@ public class SurfaceControl {
public static final int FX_SURFACE_NORMAL = 0x00000000;
/**
+ * Surface creation flag: Creates a blur surface.
+ */
+ public static final int FX_SURFACE_BLUR = 0x00010000;
+
+ /**
* Surface creation flag: Creates a Dim surface.
* Everything behind this surface is dimmed by the amount specified
* in {@link #setAlpha}. It is an error to lock a Dim surface, since it
@@ -384,6 +394,29 @@ public class SurfaceControl {
nativeSetSize(mNativeObject, w, h);
}
+ public void setBlur(float blur) {
+ checkNotReleased();
+ nativeSetBlur(mNativeObject, blur);
+ }
+
+ public void setBlurMaskSurface(SurfaceControl maskSurface) {
+ checkNotReleased();
+ if (maskSurface != null) {
+ maskSurface.checkNotReleased();
+ }
+ nativeSetBlurMaskSurface(mNativeObject, maskSurface == null ? 0:maskSurface.mNativeObject);
+ }
+
+ public void setBlurMaskSampling(int blurMaskSampling) {
+ checkNotReleased();
+ nativeSetBlurMaskSampling(mNativeObject, blurMaskSampling);
+ }
+
+ public void setBlurMaskAlphaThreshold(float alpha) {
+ checkNotReleased();
+ nativeSetBlurMaskAlphaThreshold(mNativeObject, alpha);
+ }
+
public void hide() {
checkNotReleased();
nativeSetFlags(mNativeObject, SURFACE_HIDDEN, SURFACE_HIDDEN);
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 0b26175..2150d33 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -199,6 +199,7 @@ public abstract class Window {
private boolean mHaveWindowFormat = false;
private boolean mHaveDimAmount = false;
+ private boolean mHaveBlurAmount = false;
private int mDefaultWindowFormat = PixelFormat.OPAQUE;
private boolean mHasSoftInputMode = false;
@@ -818,6 +819,13 @@ public abstract class Window {
setPrivateFlags(flags, flags);
}
+ /** @hide */
+ public void setBlurMaskAlphaThreshold(float alpha) {
+ final WindowManager.LayoutParams attrs = getAttributes();
+ attrs.blurMaskAlphaThreshold = alpha;
+ dispatchWindowAttributesChanged(attrs);
+ }
+
/**
* Convenience function to clear the flag bits as specified in flags, as
* per {@link #setFlags}.
@@ -899,6 +907,19 @@ public abstract class Window {
}
/**
+ * Set the amount of blur behind the window when using
+ * {@link WindowManager.LayoutParams#FLAG_BLUR_BEHIND}.
+ * This feature may not be supported by all devices.
+ * {@hide}
+ */
+ public void setBlurAmount(float amount) {
+ final WindowManager.LayoutParams attrs = getAttributes();
+ attrs.blurAmount = amount;
+ mHaveBlurAmount = true;
+ dispatchWindowAttributesChanged(attrs);
+ }
+
+ /**
* Specify custom window attributes. <strong>PLEASE NOTE:</strong> the
* layout params you give here should generally be from values previously
* retrieved with {@link #getAttributes()}; you probably do not want to
@@ -1408,6 +1429,11 @@ public abstract class Window {
return mHaveDimAmount;
}
+ /** @hide */
+ protected boolean haveBlurAmount() {
+ return mHaveBlurAmount;
+ }
+
public abstract void setChildDrawable(int featureId, Drawable drawable);
public abstract void setChildInt(int featureId, int value);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 9263875..6cb27cc 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1134,6 +1134,19 @@ public interface WindowManager extends ViewManager {
public static final int PRIVATE_FLAG_PREVENT_POWER_KEY = 0x20000000;
/**
+ * Window flag: adding additional blur layer and set this as masking layer
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_BLUR_WITH_MASKING = 0x40000000;
+
+ /**
+ * Window flag: adding additional blur layer and set this as masking layer.
+ * This is faster and ugglier than non-scaled version.
+ * {@hide}
+ */
+ public static final int PRIVATE_FLAG_BLUR_WITH_MASKING_SCALED = 0x80000000;
+
+ /**
* Control flags that are private to the platform.
* @hide
*/
@@ -1395,6 +1408,15 @@ public interface WindowManager extends ViewManager {
public float dimAmount = 1.0f;
/**
+ * When {@link #FLAG_BLUR_BEHIND} is set, this is the amount of blur
+ * to apply. Range is from 1.0 for maximum to 0.0 for no
+ * blur.
+ * @hide
+ */
+ public float blurAmount = 1.0f;
+
+
+ /**
* Default value for {@link #screenBrightness} and {@link #buttonBrightness}
* indicating that the brightness value is not overridden for this window
* and normal brightness policy should be used.
@@ -1587,6 +1609,14 @@ public interface WindowManager extends ViewManager {
*/
public long userActivityTimeout = -1;
+ /**
+ * Threshold value that blur masking layer uses to determine whether
+ * to use or discard the blurred color.
+ * Value should be between 0.0 and 1.0
+ * @hide
+ */
+ public float blurMaskAlphaThreshold = 0.0f;
+
public LayoutParams() {
super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
type = TYPE_APPLICATION;
@@ -1673,6 +1703,7 @@ public interface WindowManager extends ViewManager {
out.writeInt(windowAnimations);
out.writeFloat(alpha);
out.writeFloat(dimAmount);
+ out.writeFloat(blurAmount);
out.writeFloat(screenBrightness);
out.writeFloat(buttonBrightness);
out.writeInt(rotationAnimation);
@@ -1693,6 +1724,7 @@ public interface WindowManager extends ViewManager {
out.writeInt(surfaceInsets.bottom);
out.writeInt(hasManualSurfaceInsets ? 1 : 0);
out.writeInt(needsMenuKey);
+ out.writeFloat(blurMaskAlphaThreshold);
}
public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1723,6 +1755,7 @@ public interface WindowManager extends ViewManager {
windowAnimations = in.readInt();
alpha = in.readFloat();
dimAmount = in.readFloat();
+ blurAmount = in.readFloat();
screenBrightness = in.readFloat();
buttonBrightness = in.readFloat();
rotationAnimation = in.readInt();
@@ -1743,6 +1776,7 @@ public interface WindowManager extends ViewManager {
surfaceInsets.bottom = in.readInt();
hasManualSurfaceInsets = in.readInt() != 0;
needsMenuKey = in.readInt();
+ blurMaskAlphaThreshold = in.readFloat();
}
@SuppressWarnings({"PointlessBitwiseExpression"})
@@ -1782,6 +1816,10 @@ public interface WindowManager extends ViewManager {
/** {@hide} */
public static final int PREFERRED_DISPLAY_MODE_ID = 1 << 23;
/** {@hide} */
+ public static final int BLUR_AMOUNT_CHANGED = 1 << 29;
+ /** {@hide} */
+ public static final int BLUR_MASK_ALPHA_THRESHOLD_CHANGED = 1 << 30;
+ /** {@hide} */
public static final int EVERYTHING_CHANGED = 0xffffffff;
// internal buffer to backup/restore parameters under compatibility mode.
@@ -1876,6 +1914,10 @@ public interface WindowManager extends ViewManager {
dimAmount = o.dimAmount;
changes |= DIM_AMOUNT_CHANGED;
}
+ if (blurAmount != o.blurAmount) {
+ blurAmount = o.blurAmount;
+ changes |= BLUR_AMOUNT_CHANGED;
+ }
if (screenBrightness != o.screenBrightness) {
screenBrightness = o.screenBrightness;
changes |= SCREEN_BRIGHTNESS_CHANGED;
@@ -1941,6 +1983,11 @@ public interface WindowManager extends ViewManager {
changes |= NEEDS_MENU_KEY_CHANGED;
}
+ if (blurMaskAlphaThreshold != o.blurMaskAlphaThreshold) {
+ blurMaskAlphaThreshold = o.blurMaskAlphaThreshold;
+ changes |= BLUR_MASK_ALPHA_THRESHOLD_CHANGED;
+ }
+
return changes;
}
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index 20352eb..7156c0f 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -316,6 +316,39 @@ static void nativeSetLayerStack(JNIEnv* env, jclass clazz, jlong nativeObject, j
}
}
+static void nativeSetBlur(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat blur) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ status_t err = ctrl->setBlur(blur);
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
+}
+
+static void nativeSetBlurMaskSurface(JNIEnv* env, jclass clazz, jlong nativeObject, jlong maskLayerNativeObject) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ SurfaceControl* const maskLayer = reinterpret_cast<SurfaceControl *>(maskLayerNativeObject);
+ status_t err = ctrl->setBlurMaskSurface(maskLayer);
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
+}
+
+static void nativeSetBlurMaskSampling(JNIEnv* env, jclass clazz, jlong nativeObject, jint blurMaskSampling) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ status_t err = ctrl->setBlurMaskSampling(blurMaskSampling);
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
+}
+
+static void nativeSetBlurMaskAlphaThreshold(JNIEnv* env, jclass clazz, jlong nativeObject, jfloat alpha) {
+ SurfaceControl* const ctrl = reinterpret_cast<SurfaceControl *>(nativeObject);
+ status_t err = ctrl->setBlurMaskAlphaThreshold(alpha);
+ if (err < 0 && err != NO_INIT) {
+ doThrowIAE(env);
+ }
+}
+
static jobject nativeGetBuiltInDisplay(JNIEnv* env, jclass clazz, jint id) {
sp<IBinder> token(SurfaceComposerClient::getBuiltInDisplay(id));
return javaObjectForIBinder(env, token);
@@ -614,6 +647,14 @@ static JNINativeMethod sSurfaceControlMethods[] = {
(void*)nativeSetWindowCrop },
{"nativeSetLayerStack", "(JI)V",
(void*)nativeSetLayerStack },
+ {"nativeSetBlur", "(JF)V",
+ (void*)nativeSetBlur },
+ {"nativeSetBlurMaskSurface", "(JJ)V",
+ (void*)nativeSetBlurMaskSurface },
+ {"nativeSetBlurMaskSampling", "(JI)V",
+ (void*)nativeSetBlurMaskSampling },
+ {"nativeSetBlurMaskAlphaThreshold", "(JF)V",
+ (void*)nativeSetBlurMaskAlphaThreshold },
{"nativeGetBuiltInDisplay", "(I)Landroid/os/IBinder;",
(void*)nativeGetBuiltInDisplay },
{"nativeCreateDisplay", "(Ljava/lang/String;Z)Landroid/os/IBinder;",
diff --git a/core/res/res/values/cm_symbols.xml b/core/res/res/values/cm_symbols.xml
index 143adc9..164594e 100644
--- a/core/res/res/values/cm_symbols.xml
+++ b/core/res/res/values/cm_symbols.xml
@@ -120,4 +120,8 @@
<java-symbol type="string" name="privacy_guard_notification_detail" />
<java-symbol type="string" name="privacy_guard_dialog_title" />
<java-symbol type="string" name="privacy_guard_dialog_summary" />
+
+ <!-- Blur effects -->
+ <java-symbol type="bool" name="config_ui_blur_enabled" />
+
</resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b2bf07a..1e7b102 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2516,4 +2516,8 @@
<!-- Allow the gesture to double tap the power button twice to start the camera while the device
is non-interactive. -->
<bool name="config_cameraDoubleTapPowerGestureEnabled">true</bool>
+
+ <!-- Support in Surfaceflinger for blur layers.
+ NOTE: This requires additional hardware-specific code. -->
+ <bool name="config_ui_blur_enabled">false</bool>
</resources>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index d7e222e..aceb9f1 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -139,6 +139,9 @@
<!-- Weather -->
<uses-permission android:name="com.cyanogenmod.lockclock.permission.READ_WEATHER" />
+ <!-- blur surface -->
+ <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+
<application
android:name=".SystemUIApplication"
android:persistent="true"
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 303f82e..f116f05 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -35,6 +35,7 @@
<color name="batterymeter_bolt_color">#FFFFFFFF</color>
<color name="qs_batterymeter_frame_color">#FF404040</color>
<color name="system_primary_color">#ff263238</color><!-- blue grey 900 -->
+ <color name="system_primary_color_translucent">#90aaaaaa</color><!-- blue grey 900 -->
<color name="system_secondary_color">#ff384248</color>
<color name="system_accent_color">#ff80CBC4</color><!-- deep teal 200 -->
<color name="system_warning_color">#fff4511e</color><!-- deep orange 600 -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BlurLayer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BlurLayer.java
new file mode 100644
index 0000000..a966409
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BlurLayer.java
@@ -0,0 +1,196 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.systemui.statusbar.phone;
+
+import android.graphics.PixelFormat;
+import android.util.Slog;
+import android.view.SurfaceControl;
+import android.view.SurfaceSession;
+
+import java.io.PrintWriter;
+
+public class BlurLayer {
+ private static final String TAG = "BlurLayer";
+ private static final boolean DEBUG = true;
+ private SurfaceControl mBlurSurface;
+ private int mLayer = -1;
+ private float mAlpha = 0;
+ private float mBlur = 0;
+ private int mX, mY;
+ private int mW, mH;
+ private boolean mIsShow;
+
+ public BlurLayer(SurfaceSession mFxSession, int w, int h, String tag) {
+ this(mFxSession, 0, 0, w, h, tag);
+ }
+
+ public BlurLayer(SurfaceSession mFxSession, int x, int y, int w, int h, String tag) {
+ mX = x;
+ mY = y;
+ mW = w;
+ mH = h;
+ mIsShow = false;
+
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface = new SurfaceControl(mFxSession, TAG+"_"+tag, 16, 16, PixelFormat.OPAQUE,
+ SurfaceControl.FX_SURFACE_BLUR | SurfaceControl.HIDDEN);
+ mBlurSurface.setLayerStack(0);
+ mBlurSurface.setPosition(mX, mY);
+ mBlurSurface.setSize(mW, mH);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception creating BlurLayer surface", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+
+ public void setSize(int w, int h) {
+ if (mBlurSurface != null && (mW != w || mH != h) ) {
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface.setSize(w, h);
+ mW = w;
+ mH = h;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting setSize immediately", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception setSize", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void setPosition(int x, int y) {
+ if (mBlurSurface != null && (mX != x || mY != y) ) {
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface.setPosition(x, y);
+ mX = x;
+ mY = y;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting setPosition immediately", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception setPosition", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void setLayer(int layer) {
+ if (mBlurSurface != null && mLayer != layer) {
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface.setLayer(layer);
+ mLayer = layer;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting setLayer immediately", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception setLayer", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void setAlpha(float alpha){
+ if(mBlurSurface != null && mAlpha != alpha){
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface.setAlpha(alpha);
+ mAlpha = alpha;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting alpha immediately", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception setAlpha", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void setBlur(float blur){
+ if(mBlurSurface != null && mBlur != blur ){
+ SurfaceControl.openTransaction();
+ try {
+ mBlurSurface.setBlur(blur);
+ mBlur = blur;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting blur immediately", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception setBlur", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void show() {
+ if(mBlurSurface != null && !mIsShow ){
+ try {
+ mBlurSurface.show();
+ mIsShow = true;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure show()", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception show()", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void hide(){
+ if(mBlurSurface != null && mIsShow ){
+ try {
+ mBlurSurface.hide();
+ mIsShow = false;
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure hide()", e);
+ } catch (Exception e) {
+ Slog.e(TAG, "Exception hide()", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ public void destroySurface() {
+ if (DEBUG) Slog.v(TAG, "destroySurface.");
+ if (mBlurSurface != null) {
+ mBlurSurface.destroy();
+ mBlurSurface = null;
+ }
+ }
+
+}
+
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 30dcd4d..73d5f01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1976,6 +1976,9 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
final boolean hasBackdrop = backdropBitmap != null;
mKeyguardShowingMedia = hasBackdrop;
+ if (mStatusBarWindowManager != null) {
+ mStatusBarWindowManager.setShowingMedia(mKeyguardShowingMedia);
+ }
if ((hasBackdrop || DEBUG_MEDIA_FAKE_ARTWORK)
&& (mState == StatusBarState.KEYGUARD || mState == StatusBarState.SHADE_LOCKED)
@@ -2226,6 +2229,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
return mWakeUpComingFromTouch;
}
+ void setBlur(float b){
+ mStatusBarWindowManager.setBlur(b);
+ }
+
public boolean isFalsingThresholdNeeded() {
return getBarState() == StatusBarState.KEYGUARD;
}
@@ -3193,7 +3200,8 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
private void addStatusBarWindow() {
makeStatusBarView();
mStatusBarWindow.addContent(mStatusBarWindowContent);
- mStatusBarWindowManager = new StatusBarWindowManager(mContext);
+ mStatusBarWindowManager = new StatusBarWindowManager(mContext, mKeyguardMonitor);
+ mStatusBarWindowManager.setShowingMedia(mKeyguardShowingMedia);
mStatusBarWindowManager.add(mStatusBarWindow, getStatusBarHeight());
}
@@ -4125,6 +4133,10 @@ public class PhoneStatusBar extends BaseStatusBar implements DemoMode,
}
}
+ boolean isSecure() {
+ return mStatusBarKeyguardViewManager != null && mStatusBarKeyguardViewManager.isSecure();
+ }
+
public long calculateGoingToFullShadeDelay() {
return mKeyguardFadingAwayDelay + mKeyguardFadingAwayDuration;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index c0887ca..3b068d6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -193,6 +193,7 @@ public class PhoneStatusBarView extends PanelBar {
super.panelExpansionChanged(panel, frac, expanded);
mPanelFraction = frac;
updateScrimFraction();
+ mBar.setBlur(frac);
}
private void updateScrimFraction() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 25b653b..f679a69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -198,6 +198,7 @@ public class StatusBarKeyguardViewManager {
updateStates();
}
mPhoneStatusBar.onScreenTurnedOn();
+ mStatusBarWindowManager.onKeyguardChanged();
}
public void onScreenTurnedOff() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
index 35bc599..117d19d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarWindowManager.java
@@ -19,18 +19,24 @@ package com.android.systemui.statusbar.phone;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.content.res.Resources;
+import android.graphics.Point;
import android.graphics.PixelFormat;
+import android.os.Handler;
import android.os.SystemProperties;
import android.view.Gravity;
+import android.view.Display;
+import android.view.SurfaceSession;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
+import android.view.WindowManagerPolicy;
import com.android.keyguard.R;
import com.android.systemui.keyguard.KeyguardViewMediator;
import com.android.systemui.statusbar.BaseStatusBar;
import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -39,7 +45,7 @@ import java.lang.reflect.Field;
/**
* Encapsulates all logic for the status bar window state management.
*/
-public class StatusBarWindowManager {
+public class StatusBarWindowManager implements KeyguardMonitor.Callback {
private final Context mContext;
private final WindowManager mWindowManager;
@@ -49,14 +55,33 @@ public class StatusBarWindowManager {
private int mBarHeight;
private final boolean mKeyguardScreenRotation;
private final float mScreenBrightnessDoze;
+
+ private boolean mKeyguardBlurEnabled;
+ private boolean mShowingMedia;
+ private BlurLayer mKeyguardBlur;
+ private final SurfaceSession mFxSession;
+
+ private final KeyguardMonitor mKeyguardMonitor;
+
+ private static final int TYPE_LAYER_MULTIPLIER = 10000; // refer to WindowManagerService.TYPE_LAYER_MULTIPLIER
+ private static final int TYPE_LAYER_OFFSET = 1000; // refer to WindowManagerService.TYPE_LAYER_OFFSET
+
+ private static final int STATUS_BAR_LAYER = 16 * TYPE_LAYER_MULTIPLIER + TYPE_LAYER_OFFSET;
+
private final State mCurrentState = new State();
- public StatusBarWindowManager(Context context) {
+ public StatusBarWindowManager(Context context, KeyguardMonitor kgm) {
mContext = context;
mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
mKeyguardScreenRotation = shouldEnableKeyguardScreenRotation();
mScreenBrightnessDoze = mContext.getResources().getInteger(
com.android.internal.R.integer.config_screenBrightnessDoze) / 255f;
+
+ mKeyguardMonitor = kgm;
+ mKeyguardMonitor.addCallback(this);
+ mKeyguardBlurEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_ui_blur_enabled);
+ mFxSession = new SurfaceSession();
}
private boolean shouldEnableKeyguardScreenRotation() {
@@ -95,15 +120,30 @@ public class StatusBarWindowManager {
mWindowManager.addView(mStatusBarView, mLp);
mLpChanged = new WindowManager.LayoutParams();
mLpChanged.copyFrom(mLp);
+
+ if (mKeyguardBlurEnabled) {
+ Display display = mWindowManager.getDefaultDisplay();
+ Point xy = new Point();
+ display.getRealSize(xy);
+ mKeyguardBlur = new BlurLayer(mFxSession, xy.x, xy.y, "KeyGuard");
+ if (mKeyguardBlur != null) {
+ mKeyguardBlur.setLayer(STATUS_BAR_LAYER - 2);
+ }
+ }
}
private void applyKeyguardFlags(State state) {
if (state.keyguardShowing) {
- mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
mLpChanged.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+ if (!mKeyguardBlurEnabled) {
+ mLpChanged.flags |= WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+ }
} else {
mLpChanged.flags &= ~WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
mLpChanged.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
+ if (mKeyguardBlurEnabled) {
+ mKeyguardBlur.hide();
+ }
}
}
@@ -216,13 +256,33 @@ public class StatusBarWindowManager {
}
}
+ private void applyKeyguardBlurShow(){
+ boolean isblur = false;
+ if (mCurrentState.keyguardShowing && mKeyguardBlurEnabled
+ && !mCurrentState.keyguardOccluded
+ && !mShowingMedia) {
+ isblur = true;
+ }
+ if (mKeyguardBlur != null) {
+ if (isblur) {
+ mKeyguardBlur.show();
+ } else {
+ mKeyguardBlur.hide();
+ }
+ }
+ }
+
public void setKeyguardShowing(boolean showing) {
mCurrentState.keyguardShowing = showing;
apply(mCurrentState);
}
public void setKeyguardOccluded(boolean occluded) {
+ final boolean oldOccluded = mCurrentState.keyguardOccluded;
mCurrentState.keyguardOccluded = occluded;
+ if (oldOccluded != occluded) {
+ applyKeyguardBlurShow();
+ }
apply(mCurrentState);
}
@@ -262,6 +322,23 @@ public class StatusBarWindowManager {
apply(mCurrentState);
}
+ void setBlur(float b){
+ if (mKeyguardBlurEnabled && mKeyguardBlur != null) {
+ float minBlur = mKeyguardMonitor.isSecure() ? 1.0f : 0.0f;
+ if (b < minBlur) {
+ b = minBlur;
+ } else if (b > 1.0f) {
+ b = 1.0f;
+ }
+ mKeyguardBlur.setBlur(b);
+ }
+ }
+
+ public void setShowingMedia(boolean showingMedia) {
+ mShowingMedia = showingMedia;
+ applyKeyguardBlurShow();
+ }
+
/**
* @param state The {@link StatusBarState} of the status bar.
*/
@@ -299,6 +376,11 @@ public class StatusBarWindowManager {
apply(mCurrentState);
}
+ @Override
+ public void onKeyguardChanged() {
+ applyKeyguardBlurShow();
+ }
+
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("StatusBarWindowManager state:");
pw.println(mCurrentState);
diff --git a/services/core/java/com/android/server/wm/BlurLayer.java b/services/core/java/com/android/server/wm/BlurLayer.java
new file mode 100644
index 0000000..b54ac9e
--- /dev/null
+++ b/services/core/java/com/android/server/wm/BlurLayer.java
@@ -0,0 +1,313 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * 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.server.wm;
+
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.SystemClock;
+import android.util.Slog;
+import android.view.DisplayInfo;
+import android.view.SurfaceControl;
+
+import java.io.PrintWriter;
+
+public class BlurLayer {
+ private static final String TAG = "BlurLayer";
+ private static final boolean DEBUG = false;
+
+ /** Reference to the owner of this object. */
+ final DisplayContent mDisplayContent;
+
+ /** Actual surface that blurs */
+ SurfaceControl mBlurSurface;
+
+ /** Last value passed to mBlurSurface.setBlur() */
+ float mBlur = 0;
+
+ /** Last value passed to mBlurSurface.setLayer() */
+ int mLayer = -1;
+
+ /** Next values to pass to mBlurSurface.setPosition() and mBlurSurface.setSize() */
+ Rect mBounds = new Rect();
+
+ /** Last values passed to mBlurSurface.setPosition() and mBlurSurface.setSize() */
+ Rect mLastBounds = new Rect();
+
+ /** True after mBlurSurface.show() has been called, false after mBlurSurface.hide(). */
+ private boolean mShowing = false;
+
+ /** Value of mBlur when beginning transition to mTargetBlur */
+ float mStartBlur = 0;
+
+ /** Final value of mBlur following transition */
+ float mTargetBlur = 0;
+
+ /** Time in units of SystemClock.uptimeMillis() at which the current transition started */
+ long mStartTime;
+
+ /** Time in milliseconds to take to transition from mStartBlur to mTargetBlur */
+ long mDuration;
+
+ /** Owning stack */
+ final TaskStack mStack;
+
+ BlurLayer(WindowManagerService service, TaskStack stack, DisplayContent displayContent) {
+ mStack = stack;
+ mDisplayContent = displayContent;
+ final int displayId = mDisplayContent.getDisplayId();
+ if (DEBUG) Slog.v(TAG, "Ctor: displayId=" + displayId);
+ SurfaceControl.openTransaction();
+ try {
+ if (WindowManagerService.DEBUG_SURFACE_TRACE) {
+ mBlurSurface = new WindowStateAnimator.SurfaceTrace(service.mFxSession,
+ "BlurSurface",
+ 16, 16, PixelFormat.OPAQUE,
+ SurfaceControl.FX_SURFACE_BLUR | SurfaceControl.HIDDEN);
+ } else {
+ mBlurSurface = new SurfaceControl(service.mFxSession, TAG,
+ 16, 16, PixelFormat.OPAQUE,
+ SurfaceControl.FX_SURFACE_BLUR | SurfaceControl.HIDDEN);
+ }
+ if (WindowManagerService.SHOW_TRANSACTIONS ||
+ WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(TAG,
+ " BLUR " + mBlurSurface + ": CREATE");
+ mBlurSurface.setLayerStack(displayId);
+ } catch (Exception e) {
+ Slog.e(WindowManagerService.TAG, "Exception creating Blur surface", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+
+ /** Return true if blur layer is showing */
+ boolean isBlurring() {
+ return mTargetBlur != 0;
+ }
+
+ /** Return true if in a transition period */
+ boolean isAnimating() {
+ return mTargetBlur != mBlur;
+ }
+
+ float getTargetBlur() {
+ return mTargetBlur;
+ }
+
+ void setLayer(int layer) {
+ if (mLayer != layer) {
+ mLayer = layer;
+ mBlurSurface.setLayer(layer);
+ }
+ }
+
+ int getLayer() {
+ return mLayer;
+ }
+
+ private void setBlur(float blur) {
+ if (mBlur != blur) {
+ if (DEBUG) Slog.v(TAG, "setBlur blur=" + blur);
+ try {
+ mBlurSurface.setBlur(blur);
+ if (blur == 0 && mShowing) {
+ if (DEBUG) Slog.v(TAG, "setBlur hiding");
+ mBlurSurface.hide();
+ mShowing = false;
+ } else if (blur > 0 && !mShowing) {
+ if (DEBUG) Slog.v(TAG, "setBlur showing");
+ mBlurSurface.show();
+ mShowing = true;
+ }
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting blur immediately", e);
+ }
+ mBlur = blur;
+ }
+ }
+
+ void adjustBounds() {
+ final int dw, dh;
+ final float xPos, yPos;
+ if (!mStack.isFullscreen()) {
+ dw = mBounds.width();
+ dh = mBounds.height();
+ xPos = mBounds.left;
+ yPos = mBounds.top;
+ } else {
+ // Set surface size to screen size.
+ final DisplayInfo info = mDisplayContent.getDisplayInfo();
+ dw = info.logicalWidth;
+ dh = info.logicalHeight;
+ xPos = 0;
+ yPos = 0;
+ }
+
+ mBlurSurface.setPosition(xPos, yPos);
+ mBlurSurface.setSize(dw, dh);
+ mLastBounds.set(mBounds);
+ }
+
+ void setBounds(Rect bounds) {
+ mBounds.set(bounds);
+ if (isBlurring() && !mLastBounds.equals(bounds)) {
+ try {
+ SurfaceControl.openTransaction();
+ adjustBounds();
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Failure setting size", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+ }
+ }
+
+ /**
+ * @param duration The time to test.
+ * @return True if the duration would lead to an earlier end to the current animation.
+ */
+ private boolean durationEndsEarlier(long duration) {
+ return SystemClock.uptimeMillis() + duration < mStartTime + mDuration;
+ }
+
+ /** Jump to the end of the animation.
+ * NOTE: Must be called with Surface transaction open. */
+ void show() {
+ if (isAnimating()) {
+ if (DEBUG) Slog.v(TAG, "show: immediate");
+ show(mLayer, mTargetBlur, 0);
+ }
+ }
+
+ /**
+ * Begin an animation to a new dim value.
+ * NOTE: Must be called with Surface transaction open.
+ *
+ * @param layer The layer to set the surface to.
+ * @param blur The dim value to end at.
+ * @param duration How long to take to get there in milliseconds.
+ */
+ void show(int layer, float blur, long duration) {
+ if (DEBUG) Slog.v(TAG, "show: layer=" + layer + " blur=" + blur
+ + " duration=" + duration);
+ if (mBlurSurface == null) {
+ Slog.e(TAG, "show: no Surface");
+ // Make sure isAnimating() returns false.
+ mTargetBlur = mBlur = 0;
+ return;
+ }
+
+ if (!mLastBounds.equals(mBounds)) {
+ adjustBounds();
+ }
+ setLayer(layer);
+
+ long curTime = SystemClock.uptimeMillis();
+ final boolean animating = isAnimating();
+ if ((animating && (mTargetBlur != blur || durationEndsEarlier(duration)))
+ || (!animating && mBlur != blur)) {
+ if (duration <= 0) {
+ // No animation required, just set values.
+ setBlur(blur);
+ } else {
+ // Start or continue animation with new parameters.
+ mStartBlur = mBlur;
+ mStartTime = curTime;
+ mDuration = duration;
+ }
+ }
+ if (DEBUG) Slog.v(TAG, "show: mStartBlur=" + mStartBlur + " mStartTime=" + mStartTime);
+ mTargetBlur = blur;
+ }
+
+ /** Immediate hide.
+ * NOTE: Must be called with Surface transaction open. */
+ void hide() {
+ if (mShowing) {
+ if (DEBUG) Slog.v(TAG, "hide: immediate");
+ hide(0);
+ }
+ }
+
+ /**
+ * Gradually fade to transparent.
+ * NOTE: Must be called with Surface transaction open.
+ *
+ * @param duration Time to fade in milliseconds.
+ */
+ void hide(long duration) {
+ if (mShowing && (mTargetBlur != 0 || durationEndsEarlier(duration))) {
+ if (DEBUG) Slog.v(TAG, "hide: duration=" + duration);
+ show(mLayer, 0, duration);
+ }
+ }
+
+ /**
+ * Advance the dimming per the last #show(int, float, long) call.
+ * NOTE: Must be called with Surface transaction open.
+ *
+ * @return True if animation is still required after this step.
+ */
+ boolean stepAnimation() {
+ if (mBlurSurface == null) {
+ Slog.e(TAG, "stepAnimation: null Surface");
+ // Ensure that isAnimating() returns false;
+ mTargetBlur = mBlur = 0;
+ return false;
+ }
+
+ if (isAnimating()) {
+ final long curTime = SystemClock.uptimeMillis();
+ final float blurDelta = mTargetBlur - mStartBlur;
+ float blur = mStartBlur + blurDelta * (curTime - mStartTime) / mDuration;
+ if (blurDelta > 0 && blur > mTargetBlur ||
+ blurDelta < 0 && blur < mTargetBlur) {
+ // Don't exceed limits.
+ blur = mTargetBlur;
+ }
+ if (DEBUG) Slog.v(TAG, "stepAnimation: curTime=" + curTime + " blur=" + blur);
+ setBlur(blur);
+ }
+
+ return isAnimating();
+ }
+
+ /** Cleanup */
+ void destroySurface() {
+ if (DEBUG) Slog.v(TAG, "destroySurface.");
+ if (mBlurSurface != null) {
+ mBlurSurface.destroy();
+ mBlurSurface = null;
+ }
+ }
+
+ public void printTo(String prefix, PrintWriter pw) {
+ pw.print(prefix); pw.print("mBlurSurface="); pw.print(mBlurSurface);
+ pw.print(" mLayer="); pw.print(mLayer);
+ pw.print(" mBlur="); pw.println(mBlur);
+ pw.print(prefix); pw.print("mLastBounds="); pw.print(mLastBounds.toShortString());
+ pw.print(" mBounds="); pw.println(mBounds.toShortString());
+ pw.print(prefix); pw.print("Last animation: ");
+ pw.print(" mDuration="); pw.print(mDuration);
+ pw.print(" mStartTime="); pw.print(mStartTime);
+ pw.print(" curTime="); pw.println(SystemClock.uptimeMillis());
+ pw.print(prefix); pw.print(" mStartBlur="); pw.print(mStartBlur);
+ pw.print(" mTargetBlur="); pw.println(mTargetBlur);
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 4db0b1e..331ddbf 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -301,6 +301,35 @@ class DisplayContent {
}
}
+ boolean animateBlurLayers() {
+ boolean result = false;
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ result |= mStacks.get(stackNdx).animateBlurLayers();
+ }
+ return result;
+ }
+
+ void resetBlurring() {
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ mStacks.get(stackNdx).resetBlurringTag();
+ }
+ }
+
+ boolean isBlurring() {
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ if (mStacks.get(stackNdx).isBlurring()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ void stopBlurringIfNeeded() {
+ for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
+ mStacks.get(stackNdx).stopBlurringIfNeeded();
+ }
+ }
+
void close() {
for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
mStacks.get(stackNdx).close();
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 985bbfb..480da44 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -37,6 +37,8 @@ public class TaskStack {
/** Amount of time in milliseconds to animate the dim surface from one value to another,
* when no window animation is driving it. */
private static final int DEFAULT_DIM_DURATION = 200;
+ private static final int DEFAULT_BLUR_DURATION = 50;
+ private static final float MAX_BLUR_AMOUNT = 1.0f;
/** Unique identifier */
final int mStackId;
@@ -78,6 +80,10 @@ public class TaskStack {
* then stop any dimming. */
boolean mDimmingTag;
+ boolean mBlurringTag;
+ BlurLayer mBlurLayer;
+ WindowStateAnimator mBlurWinAnimator;
+
/** Application tokens that are exiting, but still on screen for animations. */
final AppTokenList mExitingAppTokens = new AppTokenList();
@@ -162,6 +168,7 @@ public class TaskStack {
}
mDimLayer.setBounds(bounds);
+ mBlurLayer.setBounds(bounds);
mAnimationBackgroundSurface.setBounds(bounds);
mBounds.set(bounds);
mRotation = rotation;
@@ -363,6 +370,7 @@ public class TaskStack {
mDisplayContent = displayContent;
mDimLayer = new DimLayer(mService, this, displayContent);
mAnimationBackgroundSurface = new DimLayer(mService, this, displayContent);
+ mBlurLayer = new BlurLayer(mService, this, displayContent);
updateDisplayInfo();
}
@@ -386,7 +394,6 @@ public class TaskStack {
if (doAnotherLayoutPass) {
mService.requestTraversalLocked();
}
-
close();
}
@@ -395,6 +402,10 @@ public class TaskStack {
mAnimationBackgroundSurface.hide();
}
+ private long getBlurBehindFadeDuration(long duration) {
+ return getDimBehindFadeDuration(duration);
+ }
+
private long getDimBehindFadeDuration(long duration) {
TypedValue tv = new TypedValue();
mService.mContext.getResources().getValue(
@@ -498,6 +509,82 @@ public class TaskStack {
}
}
+ boolean animateBlurLayers() {
+ boolean result = false;
+ final int blurLayer;
+ final float blurAmount;
+ if (mBlurWinAnimator == null) {
+ blurLayer = mBlurLayer.getLayer();
+ blurAmount = 0;
+ } else {
+ blurLayer = mBlurWinAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_BLUR;
+ blurAmount = mBlurWinAnimator.mWin.mAttrs.blurAmount;
+ }
+ final float targetBlur = mBlurLayer.getTargetBlur();
+ if (targetBlur != blurAmount) {
+ if (mBlurWinAnimator == null) {
+ mBlurLayer.hide(DEFAULT_BLUR_DURATION);
+ } else {
+ long duration = (mBlurWinAnimator.mAnimating && mBlurWinAnimator.mAnimation != null)
+ ? mBlurWinAnimator.mAnimation.computeDurationHint()
+ : DEFAULT_BLUR_DURATION;
+ if (targetBlur > blurAmount) {
+ duration = getBlurBehindFadeDuration(duration);
+ }
+ if (duration > DEFAULT_BLUR_DURATION)
+ duration = DEFAULT_BLUR_DURATION;
+ mBlurLayer.show(blurLayer, blurAmount, duration);
+ }
+ } else if (mBlurLayer.getLayer() != blurLayer) {
+ mBlurLayer.setLayer(blurLayer);
+ }
+ if (mBlurLayer.isAnimating()) {
+ if (!mService.okToDisplay()) {
+ // Jump to the end of the animation.
+ mBlurLayer.show();
+ } else {
+ result = mBlurLayer.stepAnimation();
+ }
+ }
+ return result;
+ }
+
+ void resetBlurringTag() {
+ mBlurringTag = false;
+ }
+
+ void setBlurringTag() {
+ mBlurringTag = true;
+ }
+
+ boolean testBlurringTag() {
+ return mBlurringTag;
+ }
+
+ boolean isBlurring() {
+ return mBlurLayer.isBlurring();
+ }
+
+ boolean isBlurring(WindowStateAnimator winAnimator) {
+ return mBlurWinAnimator == winAnimator && mBlurLayer.isBlurring();
+ }
+
+ void stopBlurringIfNeeded() {
+ if (!mBlurringTag && isBlurring()) {
+ mBlurWinAnimator = null;
+ }
+ }
+
+ void startBlurringIfNeeded(WindowStateAnimator newWinAnimator) {
+ final WindowStateAnimator existingBlurWinAnimator = mBlurWinAnimator;
+ // Don't turn on for an unshown surface, or for any layer but the highest blur layer.
+ if (newWinAnimator.mSurfaceShown && (existingBlurWinAnimator == null
+ || !existingBlurWinAnimator.mSurfaceShown
+ || existingBlurWinAnimator.mAnimLayer < newWinAnimator.mAnimLayer)) {
+ mBlurWinAnimator = newWinAnimator;
+ }
+ }
+
void switchUser() {
int top = mTasks.size();
for (int taskNdx = 0; taskNdx < top; ++taskNdx) {
@@ -519,6 +606,10 @@ public class TaskStack {
mDimLayer.destroySurface();
mDimLayer = null;
}
+ if (mBlurLayer != null) {
+ mBlurLayer.destroySurface();
+ mBlurLayer = null;
+ }
mDisplayContent = null;
}
@@ -537,6 +628,11 @@ public class TaskStack {
mDimLayer.printTo(prefix + " ", pw);
pw.print(prefix); pw.print("mDimWinAnimator="); pw.println(mDimWinAnimator);
}
+ if (mBlurLayer.isBlurring()) {
+ pw.print(prefix); pw.println("mBlurLayer:");
+ mBlurLayer.printTo(prefix, pw);
+ pw.print(prefix); pw.print("mBlurWinAnimator="); pw.println(mBlurWinAnimator);
+ }
if (!mExitingAppTokens.isEmpty()) {
pw.println();
pw.println(" Exiting application tokens:");
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index c5cd729..5d9878f 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -97,6 +97,8 @@ public class WindowAnimator {
/** Use one animation for all entering activities after keyguard is dismissed. */
Animation mPostKeyguardExitAnimation;
+ private final boolean mBlurUiEnabled;
+
// forceHiding states.
static final int KEYGUARD_NOT_SHOWN = 0;
static final int KEYGUARD_SHOWN = 1;
@@ -117,6 +119,9 @@ public class WindowAnimator {
mContext = service.mContext;
mPolicy = service.mPolicy;
+ mBlurUiEnabled = mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_ui_blur_enabled);
+
mAnimationFrameCallback = new Choreographer.FrameCallback() {
public void doFrame(long frameTimeNs) {
synchronized (mService.mWindowMap) {
@@ -215,7 +220,7 @@ public class WindowAnimator {
// Only hide windows if the keyguard is active and not animating away.
boolean keyguardOn = mPolicy.isKeyguardShowingOrOccluded()
- && mForceHiding != KEYGUARD_ANIMATING_OUT;
+ && (mForceHiding != KEYGUARD_ANIMATING_OUT && !mBlurUiEnabled);
return keyguardOn && !allowWhenLocked && (win.getDisplayId() == Display.DEFAULT_DISPLAY);
}
@@ -224,7 +229,7 @@ public class WindowAnimator {
final WindowList windows = mService.getWindowListLocked(displayId);
- if (mKeyguardGoingAway) {
+ if (mKeyguardGoingAway && !mBlurUiEnabled) {
for (int i = windows.size() - 1; i >= 0; i--) {
WindowState win = windows.get(i);
if (!mPolicy.isKeyguardHostWindow(win.mAttrs)) {
@@ -238,7 +243,8 @@ public class WindowAnimator {
// Create a new animation to delay until keyguard is gone on its own.
winAnimator.mAnimation = new AlphaAnimation(1.0f, 1.0f);
- winAnimator.mAnimation.setDuration(KEYGUARD_ANIM_TIMEOUT_MS);
+ winAnimator.mAnimation.setDuration(
+ mBlurUiEnabled ? 0 : KEYGUARD_ANIM_TIMEOUT_MS);
winAnimator.mAnimationIsEntrance = false;
winAnimator.mAnimationStartTime = -1;
winAnimator.mKeyguardGoingAwayAnimation = true;
@@ -328,7 +334,8 @@ public class WindowAnimator {
if (nowAnimating && win.mWinAnimator.mKeyguardGoingAwayAnimation) {
mForceHiding = KEYGUARD_ANIMATING_OUT;
} else {
- mForceHiding = win.isDrawnLw() ? KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
+ mForceHiding = win.isDrawnLw() && !mBlurUiEnabled ?
+ KEYGUARD_SHOWN : KEYGUARD_NOT_SHOWN;
}
}
if (DEBUG_KEYGUARD || WindowManagerService.DEBUG_VISIBILITY) Slog.v(TAG,
@@ -698,6 +705,7 @@ public class WindowAnimator {
}
mAnimating |= mService.getDisplayContentLocked(displayId).animateDimLayers();
+ mAnimating |= mService.getDisplayContentLocked(displayId).animateBlurLayers();
//TODO (multidisplay): Magnification is supported only for the default display.
if (mService.mAccessibilityController != null
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 3eca7d5..69decfd 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -154,6 +154,7 @@ import java.util.List;
import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_BLUR_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
import static android.view.WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
@@ -248,7 +249,17 @@ public class WindowManagerService extends IWindowManager.Stub
/**
* Dim surface layer is immediately below target window.
*/
- static final int LAYER_OFFSET_DIM = 1;
+ static final int LAYER_OFFSET_DIM = 1+1;
+
+ /**
+ * Blur surface layer is immediately below dim layer.
+ */
+ static final int LAYER_OFFSET_BLUR = 2+1;
+
+ /**
+ * Blur_with_masking layer is immediately below blur layer.
+ */
+ static final int LAYER_OFFSET_BLUR_WITH_MASKING = 1;
/**
* FocusedStackFrame layer is immediately above focused window.
@@ -8961,7 +8972,7 @@ public class WindowManagerService extends IWindowManager.Stub
anyLayerChanged = true;
}
final TaskStack stack = w.getStack();
- if (layerChanged && stack != null && stack.isDimming(winAnimator)) {
+ if (layerChanged && stack != null && (stack.isDimming(winAnimator) || stack.isBlurring(winAnimator))) {
// Force an animation pass just to update the mDimLayer layer.
scheduleAnimationLocked();
}
@@ -9863,6 +9874,31 @@ public class WindowManagerService extends IWindowManager.Stub
}
}
+ private void handleFlagBlurBehind(WindowState w) {
+ final WindowManager.LayoutParams attrs = w.mAttrs;
+ if ((attrs.flags & FLAG_BLUR_BEHIND) != 0
+ && w.isDisplayedLw()
+ && !w.mExiting) {
+ final WindowStateAnimator winAnimator = w.mWinAnimator;
+ final TaskStack stack = w.getStack();
+ if (stack == null) {
+ return;
+ }
+ stack.setBlurringTag();
+ if (!stack.isBlurring(winAnimator)) {
+ if (localLOGV) Slog.v(TAG, "Win " + w + " start blurring");
+ stack.startBlurringIfNeeded(winAnimator);
+ }
+ }
+ }
+
+ private void handlePrivateFlagBlurWithMasking(WindowState w) {
+ final WindowManager.LayoutParams attrs = w.mAttrs;
+ boolean hideForced = !w.isDisplayedLw() || w.mExiting;
+ final WindowStateAnimator winAnimator = w.mWinAnimator;
+ winAnimator.updateBlurWithMaskingState(attrs, hideForced);
+ }
+
private void updateAllDrawnLocked(DisplayContent displayContent) {
// See if any windows have been drawn, so they (and others
// associated with them) can now be shown.
@@ -10038,6 +10074,7 @@ public class WindowManagerService extends IWindowManager.Stub
mInnerFields.mObscured = false;
mInnerFields.mSyswin = false;
displayContent.resetDimming();
+ displayContent.resetBlurring();
// Only used if default window
final boolean someoneLosingFocus = !mLosingFocus.isEmpty();
@@ -10062,6 +10099,11 @@ public class WindowManagerService extends IWindowManager.Stub
handleFlagDimBehind(w);
}
+ if (stack != null && !stack.testBlurringTag()) {
+ handleFlagBlurBehind(w);
+ }
+ handlePrivateFlagBlurWithMasking(w);
+
if (isDefaultDisplay && obscuredChanged && (mWallpaperTarget == w)
&& w.isVisibleLw()) {
// This is the wallpaper target and its obscured state
@@ -10201,6 +10243,7 @@ public class WindowManagerService extends IWindowManager.Stub
true /* inTraversal, must call performTraversalInTrans... below */);
getDisplayContentLocked(displayId).stopDimmingIfNeeded();
+ getDisplayContentLocked(displayId).stopBlurringIfNeeded();
if (updateAllDrawn) {
updateAllDrawnLocked(displayContent);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 308aa67..0f45e39 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -95,6 +95,13 @@ class WindowStateAnimator {
SurfaceControl mSurfaceControl;
SurfaceControl mPendingDestroySurface;
+ int mLayerStack;
+
+ SurfaceControl mSurfaceControlBlur;
+ SurfaceControl mPendingDestroySurfaceBlur;
+ boolean mSurfaceBlurShown; // last value
+ boolean mSurfaceBlurScaleNeeded;
+ final static int BLUR_LAYER_OFFSET = WindowManagerService.LAYER_OFFSET_BLUR_WITH_MASKING;
/**
* Set when we have changed the size of the surface, to know that
@@ -504,6 +511,12 @@ class WindowStateAnimator {
} catch (RuntimeException e) {
Slog.w(TAG, "Exception hiding surface in " + mWin);
}
+ if (mSurfaceControlBlur != null) {
+ try { mSurfaceControlBlur.hide(); }
+ catch (RuntimeException e) {
+ Slog.w(TAG, "Exception hiding surface blur in " + mWin);
+ }
+ }
}
}
}
@@ -936,7 +949,8 @@ class WindowStateAnimator {
mSurfaceControl.setPosition(left, top);
mSurfaceLayer = mAnimLayer;
if (displayContent != null) {
- mSurfaceControl.setLayerStack(displayContent.getDisplay().getLayerStack());
+ mLayerStack = displayContent.getDisplay().getLayerStack();
+ mSurfaceControl.setLayerStack(mLayerStack);
}
mSurfaceControl.setLayer(mAnimLayer);
mSurfaceControl.setAlpha(0);
@@ -953,6 +967,7 @@ class WindowStateAnimator {
}
if (WindowManagerService.localLOGV) Slog.v(
TAG, "Created surface " + this);
+ updateBlurWithMaskingState(attrs, false);
}
return mSurfaceControl;
}
@@ -996,6 +1011,13 @@ class WindowStateAnimator {
}
mPendingDestroySurface = mSurfaceControl;
}
+
+ if (mSurfaceControlBlur != null && mPendingDestroySurfaceBlur != mSurfaceControlBlur) {
+ if (mPendingDestroySurfaceBlur != null) {
+ mPendingDestroySurfaceBlur.destroy();
+ }
+ mPendingDestroySurfaceBlur = mSurfaceControlBlur;
+ }
} else {
if (SHOW_TRANSACTIONS || SHOW_SURFACE_ALLOC) {
RuntimeException e = null;
@@ -1006,6 +1028,9 @@ class WindowStateAnimator {
WindowManagerService.logSurface(mWin, "DESTROY", e);
}
mSurfaceControl.destroy();
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.destroy();
+ }
}
mService.hideWallpapersLocked(mWin);
} catch (RuntimeException e) {
@@ -1016,6 +1041,7 @@ class WindowStateAnimator {
mSurfaceShown = false;
mSurfaceControl = null;
+ mSurfaceControlBlur = null;
mWin.mHasSurface = false;
mDrawState = NO_SURFACE;
}
@@ -1033,6 +1059,9 @@ class WindowStateAnimator {
WindowManagerService.logSurface(mWin, "DESTROY PENDING", e);
}
mPendingDestroySurface.destroy();
+ if (mPendingDestroySurfaceBlur != null) {
+ mPendingDestroySurfaceBlur.destroy();
+ }
mService.hideWallpapersLocked(mWin);
}
} catch (RuntimeException e) {
@@ -1042,6 +1071,7 @@ class WindowStateAnimator {
}
mSurfaceDestroyDeferred = false;
mPendingDestroySurface = null;
+ mPendingDestroySurfaceBlur = null;
}
void computeShownFrameLocked() {
@@ -1417,6 +1447,9 @@ class WindowStateAnimator {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
"POS " + left + ", " + top, null);
mSurfaceControl.setPosition(left, top);
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.setPosition(left, top);
+ }
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + w
+ " pos=(" + left + "," + top + ")", e);
@@ -1436,6 +1469,9 @@ class WindowStateAnimator {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
"SIZE " + width + "x" + height, null);
mSurfaceControl.setSize(width, height);
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.setSize(width, height);
+ }
mSurfaceControl.setMatrix(
mDsDx * w.mHScale, mDtDx * w.mVScale,
mDsDy * w.mHScale, mDtDy * w.mVScale);
@@ -1447,6 +1483,12 @@ class WindowStateAnimator {
stack.startDimmingIfNeeded(this);
}
}
+ if ((w.mAttrs.flags & LayoutParams.FLAG_BLUR_BEHIND) != 0) {
+ final TaskStack stack = w.getStack();
+ if (stack != null) {
+ stack.startBlurringIfNeeded(this);
+ }
+ }
} catch (RuntimeException e) {
// If something goes wrong with the surface (such
// as running out of memory), don't take down the
@@ -1532,6 +1574,14 @@ class WindowStateAnimator {
mDsDx * w.mHScale, mDtDx * w.mVScale,
mDsDy * w.mHScale, mDtDy * w.mVScale);
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.setAlpha(mShownAlpha);
+ mSurfaceControlBlur.setLayer(mAnimLayer-BLUR_LAYER_OFFSET);
+ mSurfaceControlBlur.setMatrix(
+ mDsDx*w.mHScale, mDtDx*w.mVScale,
+ mDsDy*w.mHScale, mDtDy*w.mVScale);
+ }
+
if (mLastHidden && mDrawState == HAS_DRAWN) {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
"SHOW (performLayout)", null);
@@ -1622,6 +1672,9 @@ class WindowStateAnimator {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(mWin,
"POS " + left + ", " + top, null);
mSurfaceControl.setPosition(mWin.mFrame.left + left, mWin.mFrame.top + top);
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.setPosition(mWin.mFrame.left + left, mWin.mFrame.top + top);
+ }
updateSurfaceWindowCrop(false);
} catch (RuntimeException e) {
Slog.w(TAG, "Error positioning surface of " + mWin
@@ -1800,6 +1853,9 @@ class WindowStateAnimator {
if (mSurfaceControl != null) {
mSurfaceShown = true;
mSurfaceControl.show();
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.show();
+ }
if (mWin.mTurnOnScreen) {
if (DEBUG_VISIBILITY) Slog.v(TAG,
"Show surface turning screen on: " + mWin);
@@ -1994,4 +2050,66 @@ class WindowStateAnimator {
sb.append('}');
return sb.toString();
}
+
+ void updateBlurWithMaskingState(WindowManager.LayoutParams attrs, boolean hideForced) {
+ boolean blurVisible = !hideForced && 0 != (attrs.privateFlags &
+ (WindowManager.LayoutParams.PRIVATE_FLAG_BLUR_WITH_MASKING |
+ WindowManager.LayoutParams.PRIVATE_FLAG_BLUR_WITH_MASKING_SCALED) );
+ boolean blurScaleNeeded = blurVisible && 0 != (attrs.privateFlags &
+ WindowManager.LayoutParams.PRIVATE_FLAG_BLUR_WITH_MASKING_SCALED);
+
+ if (mSurfaceBlurShown == blurVisible && mSurfaceBlurScaleNeeded == blurScaleNeeded) return;
+ mSurfaceBlurShown = blurVisible;
+ mSurfaceBlurScaleNeeded = blurScaleNeeded;
+
+ if (!blurVisible) {
+ // we don't destroy mSurfaceControlBlur
+ if (mSurfaceControlBlur != null) {
+ mSurfaceControlBlur.hide();
+ } else {
+ // nothing to do
+ }
+ return;
+ }
+
+ if (mSurfaceControl == null) return;
+
+ if (blurVisible) {
+ if (null == mSurfaceControlBlur) {
+ int flags = SurfaceControl.HIDDEN | SurfaceControl.FX_SURFACE_BLUR;
+ final boolean isHwAccelerated = (attrs.flags &
+ WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+ final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
+ if (!PixelFormat.formatHasAlpha(attrs.format)) {
+ flags |= SurfaceControl.OPAQUE;
+ }
+
+ mSurfaceControlBlur = new SurfaceControl(
+ mSession.mSurfaceSession,
+ attrs.getTitle().toString() + " blur",
+ (int)mSurfaceW, (int)mSurfaceH, format, flags);
+ }
+
+ SurfaceControl.openTransaction();
+ try {
+ mSurfaceControlBlur.setPosition(mSurfaceX, mSurfaceY);
+ mSurfaceControlBlur.setLayerStack(mLayerStack);
+ mSurfaceControlBlur.setLayer(mAnimLayer-BLUR_LAYER_OFFSET);
+ mSurfaceControlBlur.setAlpha(mShownAlpha);
+ mSurfaceControlBlur.setBlur(1.0f);
+ mSurfaceControlBlur.setBlurMaskSurface(mSurfaceControl);
+ final int BLUR_MASKING_SAMPLING = 4;
+ mSurfaceControlBlur.setBlurMaskSampling(blurScaleNeeded ? BLUR_MASKING_SAMPLING : 1);
+ mSurfaceControlBlur.setBlurMaskAlphaThreshold(attrs.blurMaskAlphaThreshold);
+ } catch (RuntimeException e) {
+ Slog.w(TAG, "Error creating blur surface", e);
+ } finally {
+ SurfaceControl.closeTransaction();
+ }
+
+ if (mSurfaceShown) {
+ mSurfaceControlBlur.show();
+ }
+ }
+ }
}