diff options
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(); + } + } + } } |