blob: 5874202dfaeb0000053065190725c3f4bb1e16e9 [file] [log] [blame]
/*
* Copyright (C) 2011 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.wm;
import android.content.res.Resources;
import android.graphics.PixelFormat;
import android.util.Slog;
import android.util.TypedValue;
import android.view.Surface;
import android.view.SurfaceSession;
import java.io.PrintWriter;
/**
* DimAnimator class that controls the dim animation. This holds the surface and
* all state used for dim animation.
*/
class DimAnimator {
static final String TAG = "DimAnimator";
Surface mDimSurface;
boolean mDimShown = false;
float mDimCurrentAlpha;
float mDimTargetAlpha;
float mDimDeltaPerMs;
long mLastDimAnimTime;
int mLastDimWidth, mLastDimHeight;
DimAnimator (SurfaceSession session, final int layerStack) {
try {
if (WindowManagerService.DEBUG_SURFACE_TRACE) {
mDimSurface = new WindowStateAnimator.SurfaceTrace(session,
"DimAnimator",
16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM | Surface.HIDDEN);
} else {
mDimSurface = new Surface(session, "DimAnimator",
16, 16, PixelFormat.OPAQUE,
Surface.FX_SURFACE_DIM | Surface.HIDDEN);
}
if (WindowManagerService.SHOW_TRANSACTIONS ||
WindowManagerService.SHOW_SURFACE_ALLOC) Slog.i(WindowManagerService.TAG,
" DIM " + mDimSurface + ": CREATE");
mDimSurface.setLayerStack(layerStack);
mDimSurface.setAlpha(0.0f);
mDimSurface.show();
} catch (Exception e) {
Slog.e(WindowManagerService.TAG, "Exception creating Dim surface", e);
}
}
/**
* Set's the dim surface's layer and update dim parameters that will be used in
* {@link #updateSurface} after all windows are examined.
*/
void updateParameters(final Resources res, final Parameters params, final long currentTime) {
if (mDimSurface == null) {
Slog.e(TAG, "updateParameters: no Surface");
return;
}
// Multiply by 1.5 so that rotating a frozen surface that includes this does not expose a
// corner.
final int dw = (int) (params.mDimWidth * 1.5);
final int dh = (int) (params.mDimHeight * 1.5);
final WindowStateAnimator winAnimator = params.mDimWinAnimator;
final float target = params.mDimTarget;
if (!mDimShown) {
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG,
" DIM " + mDimSurface + ": SHOW pos=(0,0) (" + dw + "x" + dh + ")");
mDimShown = true;
try {
mLastDimWidth = dw;
mLastDimHeight = dh;
// back off position so mDimXXX/4 is before and mDimXXX/4 is after
mDimSurface.setPosition(-1 * dw / 6, -1 * dh /6);
mDimSurface.setSize(dw, dh);
mDimSurface.show();
} catch (RuntimeException e) {
Slog.w(WindowManagerService.TAG, "Failure showing dim surface", e);
}
} else if (mLastDimWidth != dw || mLastDimHeight != dh) {
mLastDimWidth = dw;
mLastDimHeight = dh;
mDimSurface.setSize(dw, dh);
// back off position so mDimXXX/4 is before and mDimXXX/4 is after
mDimSurface.setPosition(-1 * dw / 6, -1 * dh /6);
}
mDimSurface.setLayer(winAnimator.mAnimLayer - WindowManagerService.LAYER_OFFSET_DIM);
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM "
+ mDimSurface + ": layer=" + (winAnimator.mAnimLayer-1) + " target=" + target);
if (mDimTargetAlpha != target) {
// If the desired dim level has changed, then
// start an animation to it.
mLastDimAnimTime = currentTime;
long duration = (winAnimator.mAnimating && winAnimator.mAnimation != null)
? winAnimator.mAnimation.computeDurationHint()
: WindowManagerService.DEFAULT_DIM_DURATION;
if (target > mDimTargetAlpha) {
TypedValue tv = new TypedValue();
res.getValue(com.android.internal.R.fraction.config_dimBehindFadeDuration,
tv, true);
if (tv.type == TypedValue.TYPE_FRACTION) {
duration = (long)tv.getFraction(duration, duration);
} else if (tv.type >= TypedValue.TYPE_FIRST_INT
&& tv.type <= TypedValue.TYPE_LAST_INT) {
duration = tv.data;
}
}
if (duration < 1) {
// Don't divide by zero
duration = 1;
}
mDimTargetAlpha = target;
mDimDeltaPerMs = (mDimTargetAlpha-mDimCurrentAlpha) / duration;
}
}
/**
* Updating the surface's alpha. Returns true if the animation continues, or returns
* false when the animation is finished and the dim surface is hidden.
*/
boolean updateSurface(boolean dimming, long currentTime, boolean displayFrozen) {
if (mDimSurface == null) {
Slog.e(TAG, "updateSurface: no Surface");
return false;
}
if (!dimming) {
if (mDimTargetAlpha != 0) {
mLastDimAnimTime = currentTime;
mDimTargetAlpha = 0;
mDimDeltaPerMs = (-mDimCurrentAlpha) / WindowManagerService.DEFAULT_DIM_DURATION;
}
}
boolean animating = mLastDimAnimTime != 0;
if (animating) {
mDimCurrentAlpha += mDimDeltaPerMs
* (currentTime-mLastDimAnimTime);
if (displayFrozen) {
// If the display is frozen, there is no reason to animate.
animating = false;
} else if (mDimDeltaPerMs > 0) {
if (mDimCurrentAlpha > mDimTargetAlpha) {
animating = false;
}
} else if (mDimDeltaPerMs < 0) {
if (mDimCurrentAlpha < mDimTargetAlpha) {
animating = false;
}
} else {
animating = false;
}
// Do we need to continue animating?
if (animating) {
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM "
+ mDimSurface + ": alpha=" + mDimCurrentAlpha);
mLastDimAnimTime = currentTime;
mDimSurface.setAlpha(mDimCurrentAlpha);
} else {
mDimCurrentAlpha = mDimTargetAlpha;
mLastDimAnimTime = 0;
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM "
+ mDimSurface + ": final alpha=" + mDimCurrentAlpha);
mDimSurface.setAlpha(mDimCurrentAlpha);
if (!dimming) {
if (WindowManagerService.SHOW_TRANSACTIONS) Slog.i(WindowManagerService.TAG, " DIM " + mDimSurface
+ ": HIDE");
try {
mDimSurface.hide();
} catch (RuntimeException e) {
Slog.w(WindowManagerService.TAG, "Illegal argument exception hiding dim surface");
}
mDimShown = false;
}
}
}
return animating;
}
public void kill() {
if (mDimSurface != null) {
mDimSurface.destroy();
mDimSurface = null;
}
}
public void printTo(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("mDimSurface="); pw.print(mDimSurface);
pw.print(" "); pw.print(mLastDimWidth); pw.print(" x ");
pw.println(mLastDimHeight);
pw.print(prefix);
pw.print("mDimShown="); pw.print(mDimShown);
pw.print(" current="); pw.print(mDimCurrentAlpha);
pw.print(" target="); pw.print(mDimTargetAlpha);
pw.print(" delta="); pw.print(mDimDeltaPerMs);
pw.print(" lastAnimTime="); pw.println(mLastDimAnimTime);
}
static class Parameters {
final WindowStateAnimator mDimWinAnimator;
final int mDimWidth;
final int mDimHeight;
final float mDimTarget;
Parameters(final WindowStateAnimator dimWinAnimator, final int dimWidth,
final int dimHeight, final float dimTarget) {
mDimWinAnimator = dimWinAnimator;
mDimWidth = dimWidth;
mDimHeight = dimHeight;
mDimTarget = dimTarget;
}
Parameters(Parameters o) {
mDimWinAnimator = o.mDimWinAnimator;
mDimWidth = o.mDimWidth;
mDimHeight = o.mDimHeight;
mDimTarget = o.mDimTarget;
}
public void printTo(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("mDimWinAnimator="); pw.print(mDimWinAnimator.mWin.mAttrs.getTitle());
pw.print(" "); pw.print(mDimWidth); pw.print(" x ");
pw.print(mDimHeight);
pw.print(" mDimTarget="); pw.println(mDimTarget);
}
}
}