Merge "Unhide notification category."
diff --git a/core/java/android/view/animation/ClipRectAnimation.java b/core/java/android/view/animation/ClipRectAnimation.java
new file mode 100644
index 0000000..2361501
--- /dev/null
+++ b/core/java/android/view/animation/ClipRectAnimation.java
@@ -0,0 +1,59 @@
+/*
+ * 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 android.view.animation;
+
+import android.graphics.Rect;
+
+/**
+ * An animation that controls the clip of an object. See the
+ * {@link android.view.animation full package} description for details and
+ * sample code.
+ *
+ * @hide
+ */
+public class ClipRectAnimation extends Animation {
+ private Rect mFromRect = new Rect();
+ private Rect mToRect = new Rect();
+
+ /**
+ * Constructor to use when building a ClipRectAnimation from code
+ *
+ * @param fromClip the clip rect to animate from
+ * @param toClip the clip rect to animate to
+ */
+ public ClipRectAnimation(Rect fromClip, Rect toClip) {
+ if (fromClip == null || toClip == null) {
+ throw new RuntimeException("Expected non-null animation clip rects");
+ }
+ mFromRect.set(fromClip);
+ mToRect.set(toClip);
+ }
+
+ @Override
+ protected void applyTransformation(float it, Transformation tr) {
+ int l = mFromRect.left + (int) ((mToRect.left - mFromRect.left) * it);
+ int t = mFromRect.top + (int) ((mToRect.top - mFromRect.top) * it);
+ int r = mFromRect.right + (int) ((mToRect.right - mFromRect.right) * it);
+ int b = mFromRect.bottom + (int) ((mToRect.bottom - mFromRect.bottom) * it);
+ tr.setClipRect(l, t, r, b);
+ }
+
+ @Override
+ public boolean willChangeTransformationMatrix() {
+ return false;
+ }
+}
diff --git a/core/java/android/view/animation/Transformation.java b/core/java/android/view/animation/Transformation.java
index 890909b..2f4fe73 100644
--- a/core/java/android/view/animation/Transformation.java
+++ b/core/java/android/view/animation/Transformation.java
@@ -17,6 +17,7 @@
package android.view.animation;
import android.graphics.Matrix;
+import android.graphics.Rect;
import java.io.PrintWriter;
@@ -47,6 +48,9 @@
protected float mAlpha;
protected int mTransformationType;
+ private boolean mHasClipRect;
+ private Rect mClipRect = new Rect();
+
/**
* Creates a new transformation with alpha = 1 and the identity matrix.
*/
@@ -65,6 +69,8 @@
} else {
mMatrix.reset();
}
+ mClipRect.setEmpty();
+ mHasClipRect = false;
mAlpha = 1.0f;
mTransformationType = TYPE_BOTH;
}
@@ -98,9 +104,15 @@
public void set(Transformation t) {
mAlpha = t.getAlpha();
mMatrix.set(t.getMatrix());
+ if (t.mHasClipRect) {
+ setClipRect(t.getClipRect());
+ } else {
+ mHasClipRect = false;
+ mClipRect.setEmpty();
+ }
mTransformationType = t.getTransformationType();
}
-
+
/**
* Apply this Transformation to an existing Transformation, e.g. apply
* a scale effect to something that has already been rotated.
@@ -109,6 +121,9 @@
public void compose(Transformation t) {
mAlpha *= t.getAlpha();
mMatrix.preConcat(t.getMatrix());
+ if (t.mHasClipRect) {
+ setClipRect(t.getClipRect());
+ }
}
/**
@@ -119,6 +134,9 @@
public void postCompose(Transformation t) {
mAlpha *= t.getAlpha();
mMatrix.postConcat(t.getMatrix());
+ if (t.mHasClipRect) {
+ setClipRect(t.getClipRect());
+ }
}
/**
@@ -138,6 +156,39 @@
}
/**
+ * Sets the current Transform's clip rect
+ * @hide
+ */
+ public void setClipRect(Rect r) {
+ setClipRect(r.left, r.top, r.right, r.bottom);
+ }
+
+ /**
+ * Sets the current Transform's clip rect
+ * @hide
+ */
+ public void setClipRect(int l, int t, int r, int b) {
+ mClipRect.set(l, t, r, b);
+ mHasClipRect = true;
+ }
+
+ /**
+ * Returns the current Transform's clip rect
+ * @hide
+ */
+ public Rect getClipRect() {
+ return mClipRect;
+ }
+
+ /**
+ * Returns whether the current Transform's clip rect is set
+ * @hide
+ */
+ public boolean hasClipRect() {
+ return mHasClipRect;
+ }
+
+ /**
* @return The degree of transparency
*/
public float getAlpha() {
diff --git a/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png b/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png
index 6b31579..7b6d48b 100644
--- a/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png
+++ b/core/res/res/drawable-xhdpi/cab_background_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png b/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png
index df0121b..bafe878 100644
--- a/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png
+++ b/core/res/res/drawable-xhdpi/cab_background_top_holo_light.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png b/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png
index 418f322..cbb4f4c 100644
--- a/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png
+++ b/core/res/res/drawable-xxhdpi/cab_background_top_holo_dark.9.png
Binary files differ
diff --git a/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png b/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png
index a5a59d4..6d467f7 100644
--- a/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png
+++ b/core/res/res/drawable-xxhdpi/cab_background_top_holo_light.9.png
Binary files differ
diff --git a/libs/hwui/OpenGLRenderer.cpp b/libs/hwui/OpenGLRenderer.cpp
index cb8155b..cdd789d 100644
--- a/libs/hwui/OpenGLRenderer.cpp
+++ b/libs/hwui/OpenGLRenderer.cpp
@@ -3226,11 +3226,13 @@
const int casterVertexCount = casterVertices2d.size();
Vector3 casterPolygon[casterVertexCount];
float minZ = FLT_MAX;
+ float maxZ = -FLT_MAX;
for (int i = 0; i < casterVertexCount; i++) {
const Vertex& point2d = casterVertices2d[i];
casterPolygon[i] = Vector3(point2d.x, point2d.y, 0);
mapPointFakeZ(casterPolygon[i], casterTransformXY, casterTransformZ);
minZ = fmin(minZ, casterPolygon[i].z);
+ maxZ = fmax(maxZ, casterPolygon[i].z);
}
// map the centroid of the caster into 3d
@@ -3248,6 +3250,15 @@
}
centroid3d.z += casterLift;
}
+
+ // Check whether we want to draw the shadow at all by checking the caster's
+ // bounds against clip.
+ // We only have ortho projection, so we can just ignore the Z in caster for
+ // simple rejection calculation.
+ Rect localClip = mSnapshot->getLocalClip();
+ Rect casterBounds(casterOutline->getBounds());
+ casterTransformXY.mapRect(casterBounds);
+
bool isCasterOpaque = (casterAlpha == 1.0f);
// draw caster's shadows
if (mCaches.propertyAmbientShadowStrength > 0) {
@@ -3255,7 +3266,7 @@
VertexBuffer ambientShadowVertexBuffer;
VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateAmbientShadow(
isCasterOpaque, casterPolygon, casterVertexCount, centroid3d,
- ambientShadowVertexBuffer);
+ casterBounds, localClip, maxZ, ambientShadowVertexBuffer);
drawVertexBuffer(vertexBufferMode, ambientShadowVertexBuffer, &paint);
}
@@ -3266,7 +3277,8 @@
mCaches.propertyLightPosYScale, mCaches.propertyLightPosZScale);
VertexBufferMode vertexBufferMode = ShadowTessellator::tessellateSpotShadow(
isCasterOpaque, casterPolygon, casterVertexCount, lightPosScale,
- *currentTransform(), getWidth(), getHeight(), spotShadowVertexBuffer);
+ *currentTransform(), getWidth(), getHeight(), casterBounds, localClip,
+ spotShadowVertexBuffer);
drawVertexBuffer(vertexBufferMode, spotShadowVertexBuffer, &paint);
}
diff --git a/libs/hwui/Rect.h b/libs/hwui/Rect.h
index c230149..0083b77 100644
--- a/libs/hwui/Rect.h
+++ b/libs/hwui/Rect.h
@@ -18,6 +18,7 @@
#define ANDROID_HWUI_RECT_H
#include <cmath>
+#include <SkRect.h>
#include <utils/Log.h>
@@ -68,6 +69,13 @@
bottom(height) {
}
+ inline Rect(const SkRect& rect):
+ left(rect.fLeft),
+ top(rect.fTop),
+ right(rect.fRight),
+ bottom(rect.fBottom) {
+ }
+
friend int operator==(const Rect& a, const Rect& b) {
return !memcmp(&a, &b, sizeof(a));
}
diff --git a/libs/hwui/ShadowTessellator.cpp b/libs/hwui/ShadowTessellator.cpp
index 771904a..4d0edfb 100644
--- a/libs/hwui/ShadowTessellator.cpp
+++ b/libs/hwui/ShadowTessellator.cpp
@@ -35,7 +35,8 @@
VertexBufferMode ShadowTessellator::tessellateAmbientShadow(bool isCasterOpaque,
const Vector3* casterPolygon, int casterVertexCount,
- const Vector3& centroid3d, VertexBuffer& shadowVertexBuffer) {
+ const Vector3& centroid3d, const Rect& casterBounds,
+ const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer) {
ATRACE_CALL();
// A bunch of parameters to tweak the shadow.
@@ -43,6 +44,16 @@
const float heightFactor = 1.0f / 128;
const float geomFactor = 64;
+ Rect ambientShadowBounds(casterBounds);
+ ambientShadowBounds.outset(maxZ * geomFactor * heightFactor);
+
+ if (!localClip.intersects(ambientShadowBounds)) {
+#if DEBUG_SHADOW
+ ALOGD("Ambient shadow is out of clip rect!");
+#endif
+ return kVertexBufferMode_OnePolyRingShadow;
+ }
+
return AmbientShadow::createAmbientShadow(isCasterOpaque, casterPolygon,
casterVertexCount, centroid3d, heightFactor, geomFactor,
shadowVertexBuffer);
@@ -52,7 +63,8 @@
VertexBufferMode ShadowTessellator::tessellateSpotShadow(bool isCasterOpaque,
const Vector3* casterPolygon, int casterVertexCount,
const Vector3& lightPosScale, const mat4& receiverTransform,
- int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer) {
+ int screenWidth, int screenHeight, const Rect& casterBounds,
+ const Rect& localClip, VertexBuffer& shadowVertexBuffer) {
ATRACE_CALL();
// A bunch of parameters to tweak the shadow.
@@ -73,6 +85,18 @@
const float lightSize = maximal / 4;
const int lightVertexCount = 8;
+ // Now light and caster are both in local space, we will check whether
+ // the shadow is within the clip area.
+ Rect lightRect = Rect(lightCenter.x - lightSize, lightCenter.y - lightSize,
+ lightCenter.x + lightSize, lightCenter.y + lightSize);
+ lightRect.unionWith(localClip);
+ if (!lightRect.intersects(casterBounds)) {
+#if DEBUG_SHADOW
+ ALOGD("Spot shadow is out of clip rect!");
+#endif
+ return kVertexBufferMode_OnePolyRingShadow;
+ }
+
VertexBufferMode mode = SpotShadow::createSpotShadow(isCasterOpaque,
casterPolygon, casterVertexCount, lightCenter, lightSize,
lightVertexCount, shadowVertexBuffer);
diff --git a/libs/hwui/ShadowTessellator.h b/libs/hwui/ShadowTessellator.h
index ab039fa..ff3de74 100644
--- a/libs/hwui/ShadowTessellator.h
+++ b/libs/hwui/ShadowTessellator.h
@@ -66,12 +66,14 @@
public:
static VertexBufferMode tessellateAmbientShadow(bool isCasterOpaque,
const Vector3* casterPolygon, int casterVertexCount,
- const Vector3& centroid3d, VertexBuffer& shadowVertexBuffer);
+ const Vector3& centroid3d, const Rect& casterBounds,
+ const Rect& localClip, float maxZ, VertexBuffer& shadowVertexBuffer);
static VertexBufferMode tessellateSpotShadow(bool isCasterOpaque,
const Vector3* casterPolygon, int casterVertexCount,
const Vector3& lightPosScale, const mat4& receiverTransform,
- int screenWidth, int screenHeight, VertexBuffer& shadowVertexBuffer);
+ int screenWidth, int screenHeight, const Rect& casterBounds,
+ const Rect& localClip, VertexBuffer& shadowVertexBuffer);
static void generateShadowIndices(uint16_t* shadowIndices);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index ed981ed..3d47cb6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -18,6 +18,7 @@
import android.content.Context;
import android.content.res.Configuration;
+import android.content.res.Resources;
import android.graphics.Rect;
import android.util.DisplayMetrics;
import android.util.TypedValue;
@@ -31,6 +32,7 @@
DisplayMetrics mDisplayMetrics;
public Rect systemInsets = new Rect();
+ public Rect displayRect = new Rect();
/** Private constructor */
private RecentsConfiguration() {}
@@ -51,10 +53,11 @@
/** Updates the state, given the specified context */
void update(Context context) {
- mDisplayMetrics = context.getResources().getDisplayMetrics();
+ Resources res = context.getResources();
+ DisplayMetrics dm = res.getDisplayMetrics();
+ mDisplayMetrics = dm;
- boolean isPortrait = context.getResources().getConfiguration().orientation ==
- Configuration.ORIENTATION_PORTRAIT;
+ displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
}
public void updateSystemInsets(Rect insets) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 77b78f3..d997222 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -17,6 +17,7 @@
package com.android.systemui.recents.views;
import android.app.ActivityOptions;
+import android.content.ActivityNotFoundException;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
@@ -210,11 +211,14 @@
int offsetX = 0;
int offsetY = 0;
if (tv == null) {
- // Launch the activity
+ // If there is no actual task view, then use the stack view as the source view
+ // and then offset to the expected transform rect, but bound this to just
+ // outside the display rect (to ensure we don't animate from too far away)
+ RecentsConfiguration config = RecentsConfiguration.getInstance();
sourceView = stackView;
transform = stackView.getStackTransform(stack.indexOfTask(task));
offsetX = transform.rect.left;
- offsetY = transform.rect.top;
+ offsetY = Math.min(transform.rect.top, config.displayRect.height());
} else {
transform = stackView.getStackTransform(stack.indexOfTask(task));
}
@@ -242,10 +246,14 @@
i.setFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY
| Intent.FLAG_ACTIVITY_TASK_ON_HOME
| Intent.FLAG_ACTIVITY_NEW_TASK);
- if (opts != null) {
- getContext().startActivityAsUser(i, opts.toBundle(), UserHandle.CURRENT);
- } else {
- getContext().startActivityAsUser(i, UserHandle.CURRENT);
+ try {
+ if (opts != null) {
+ getContext().startActivityAsUser(i, opts.toBundle(), UserHandle.CURRENT);
+ } else {
+ getContext().startActivityAsUser(i, UserHandle.CURRENT);
+ }
+ } catch (ActivityNotFoundException anfe) {
+ Console.logError(getContext(), "Could not start Activity");
}
Console.logTraceTime(Constants.DebugFlags.App.TimeRecentsLaunchTask,
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 756e06a..7d8b5af 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -19,18 +19,22 @@
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Point;
+import android.graphics.Rect;
import android.os.Debug;
import android.os.Handler;
import android.os.IRemoteCallback;
+import android.os.SystemProperties;
import android.util.Slog;
import android.view.WindowManager;
import android.view.animation.AlphaAnimation;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.AnimationUtils;
+import android.view.animation.ClipRectAnimation;
import android.view.animation.Interpolator;
import android.view.animation.ScaleAnimation;
+import android.view.animation.TranslateAnimation;
import com.android.internal.util.DumpUtils.Dump;
import com.android.server.AttributeCache;
import com.android.server.wm.WindowManagerService.H;
@@ -125,6 +129,12 @@
private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
+ // These are the possible states for the enter/exit activities during a thumbnail transition
+ private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_UP = 0;
+ private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_UP = 1;
+ private static final int THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN = 2;
+ private static final int THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN = 3;
+
private String mNextAppTransitionPackage;
private Bitmap mNextAppTransitionThumbnail;
// Used for thumbnail transitions. True if we're scaling up, false if scaling down
@@ -148,10 +158,13 @@
private final Interpolator mThumbnailFadeoutInterpolator;
private int mCurrentUserId = 0;
+ private boolean mUseAlternateThumbnailAnimation;
AppTransition(Context context, Handler h) {
mContext = context;
mH = h;
+ mUseAlternateThumbnailAnimation =
+ SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
mConfigShortAnimTime = context.getResources().getInteger(
com.android.internal.R.integer.config_shortAnimTime);
mDecelerateInterpolator = AnimationUtils.loadInterpolator(context,
@@ -384,80 +397,10 @@
return a;
}
- Animation createThumbnailAnimationLocked(int transit, boolean enter, boolean thumb,
- int appWidth, int appHeight) {
- Animation a;
- final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
- final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
- final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
- final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
- if (thumb) {
- // Animation for zooming thumbnail from its initial size to
- // filling the screen.
- if (mNextAppTransitionScaleUp) {
- float scaleW = appWidth / thumbWidth;
- float scaleH = appHeight / thumbHeight;
- Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
- computePivot(mNextAppTransitionStartX, 1 / scaleW),
- computePivot(mNextAppTransitionStartY, 1 / scaleH));
- scale.setInterpolator(mDecelerateInterpolator);
-
- Animation alpha = new AlphaAnimation(1, 0);
- alpha.setInterpolator(mThumbnailFadeoutInterpolator);
-
- // This AnimationSet uses the Interpolators assigned above.
- AnimationSet set = new AnimationSet(false);
- set.addAnimation(scale);
- set.addAnimation(alpha);
- a = set;
- } else {
- float scaleW = appWidth / thumbWidth;
- float scaleH = appHeight / thumbHeight;
- a = new ScaleAnimation(scaleW, 1, scaleH, 1,
- computePivot(mNextAppTransitionStartX, 1 / scaleW),
- computePivot(mNextAppTransitionStartY, 1 / scaleH));
- }
- } else if (enter) {
- // Entering app zooms out from the center of the thumbnail.
- if (mNextAppTransitionScaleUp) {
- float scaleW = thumbWidth / appWidth;
- float scaleH = thumbHeight / appHeight;
- a = new ScaleAnimation(scaleW, 1, scaleH, 1,
- computePivot(mNextAppTransitionStartX, scaleW),
- computePivot(mNextAppTransitionStartY, scaleH));
- } else {
- // noop animation
- a = new AlphaAnimation(1, 1);
- }
- } else {
- // Exiting app
- if (mNextAppTransitionScaleUp) {
- if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
- // Fade out while bringing up selected activity. This keeps the
- // current activity from showing through a launching wallpaper
- // activity.
- a = new AlphaAnimation(1, 0);
- } else {
- // noop animation
- a = new AlphaAnimation(1, 1);
- }
- } else {
- float scaleW = thumbWidth / appWidth;
- float scaleH = thumbHeight / appHeight;
- Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
- computePivot(mNextAppTransitionStartX, scaleW),
- computePivot(mNextAppTransitionStartY, scaleH));
-
- Animation alpha = new AlphaAnimation(1, 0);
-
- AnimationSet set = new AnimationSet(true);
- set.addAnimation(scale);
- set.addAnimation(alpha);
- set.setZAdjustment(Animation.ZORDER_TOP);
- a = set;
- }
- }
-
+ /**
+ * Prepares the specified animation with a standard duration, interpolator, etc.
+ */
+ Animation prepareThumbnailAnimation(Animation a, int appWidth, int appHeight, int transit) {
// Pick the desired duration. If this is an inter-activity transition,
// it is the standard duration for that. Otherwise we use the longer
// task transition duration.
@@ -478,9 +421,223 @@
return a;
}
+ /**
+ * Return the current thumbnail transition state.
+ */
+ int getThumbnailTransitionState(boolean enter) {
+ if (enter) {
+ if (mNextAppTransitionScaleUp) {
+ return THUMBNAIL_TRANSITION_ENTER_SCALE_UP;
+ } else {
+ return THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN;
+ }
+ } else {
+ if (mNextAppTransitionScaleUp) {
+ return THUMBNAIL_TRANSITION_EXIT_SCALE_UP;
+ } else {
+ return THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN;
+ }
+ }
+ }
+
+ /**
+ * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
+ * when a thumbnail is specified with the activity options.
+ */
+ Animation createThumbnailScaleAnimationLocked(int appWidth, int appHeight, int transit) {
+ Animation a;
+ final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
+ final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
+ final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
+ final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
+
+ if (mNextAppTransitionScaleUp) {
+ // Animation for the thumbnail zooming from its initial size to the full screen
+ float scaleW = appWidth / thumbWidth;
+ float scaleH = appHeight / thumbHeight;
+ Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
+ computePivot(mNextAppTransitionStartX, 1 / scaleW),
+ computePivot(mNextAppTransitionStartY, 1 / scaleH));
+ scale.setInterpolator(mDecelerateInterpolator);
+
+ Animation alpha = new AlphaAnimation(1, 0);
+ alpha.setInterpolator(mThumbnailFadeoutInterpolator);
+
+ // This AnimationSet uses the Interpolators assigned above.
+ AnimationSet set = new AnimationSet(false);
+ set.addAnimation(scale);
+ set.addAnimation(alpha);
+ a = set;
+ } else {
+ // Animation for the thumbnail zooming down from the full screen to its final size
+ float scaleW = appWidth / thumbWidth;
+ float scaleH = appHeight / thumbHeight;
+ a = new ScaleAnimation(scaleW, 1, scaleH, 1,
+ computePivot(mNextAppTransitionStartX, 1 / scaleW),
+ computePivot(mNextAppTransitionStartY, 1 / scaleH));
+ }
+
+ return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
+ }
+
+ /**
+ * This alternate animation is created when we are doing a thumbnail transition, for the
+ * activity that is leaving, and the activity that is entering.
+ */
+ Animation createAlternateThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
+ int appHeight, int transit,
+ Rect containingFrame, Rect contentInsets) {
+ Animation a;
+ final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
+ final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
+ final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
+ final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
+
+ switch (thumbTransitState) {
+ case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
+ // Entering app scales up with the thumbnail
+ float scale = thumbWidth / appWidth;
+ int unscaledThumbHeight = (int) (thumbHeight / scale);
+ int scaledTopDecor = (int) (scale * contentInsets.top);
+ Rect fromClipRect = new Rect(containingFrame);
+ fromClipRect.bottom = (fromClipRect.top + unscaledThumbHeight);
+ Rect toClipRect = new Rect(containingFrame);
+
+ Animation scaleAnim = new ScaleAnimation(scale, 1, scale, 1,
+ computePivot(mNextAppTransitionStartX, scale),
+ computePivot(mNextAppTransitionStartY, scale));
+ Animation alphaAnim = new AlphaAnimation(1, 1);
+ Animation clipAnim = new ClipRectAnimation(fromClipRect, toClipRect);
+ Animation translateAnim = new TranslateAnimation(0, 0, -scaledTopDecor, 0);
+
+ AnimationSet set = new AnimationSet(true);
+ set.addAnimation(alphaAnim);
+ set.addAnimation(clipAnim);
+ set.addAnimation(scaleAnim);
+ set.addAnimation(translateAnim);
+ a = set;
+ break;
+ }
+ case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
+ // Exiting app while the thumbnail is scaling up should fade
+ if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
+ // Fade out while bringing up selected activity. This keeps the
+ // current activity from showing through a launching wallpaper
+ // activity.
+ a = new AlphaAnimation(1, 0);
+ } else {
+ // noop animation
+ a = new AlphaAnimation(1, 1);
+ }
+ break;
+ }
+ case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
+ // Entering the other app, it should just be visible while we scale the thumbnail
+ // down above it
+ a = new AlphaAnimation(1, 1);
+ break;
+ }
+ case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
+ // Exiting the current app, the app should scale down with the thumbnail
+ float scale = thumbWidth / appWidth;
+ int unscaledThumbHeight = (int) (thumbHeight / scale);
+ int scaledTopDecor = (int) (scale * contentInsets.top);
+ Rect fromClipRect = new Rect(containingFrame);
+ Rect toClipRect = new Rect(containingFrame);
+ toClipRect.bottom = (toClipRect.top + unscaledThumbHeight);
+
+ Animation scaleAnim = new ScaleAnimation(1, scale, 1, scale,
+ computePivot(mNextAppTransitionStartX, scale),
+ computePivot(mNextAppTransitionStartY, scale));
+ Animation alphaAnim = new AlphaAnimation(1, 1);
+ Animation clipAnim = new ClipRectAnimation(fromClipRect, toClipRect);
+ Animation translateAnim = new TranslateAnimation(0, 0, 0, -scaledTopDecor);
+
+ AnimationSet set = new AnimationSet(true);
+ set.addAnimation(alphaAnim);
+ set.addAnimation(clipAnim);
+ set.addAnimation(scaleAnim);
+ set.addAnimation(translateAnim);
+
+ a = set;
+ a.setZAdjustment(Animation.ZORDER_TOP);
+ break;
+ }
+ default:
+ throw new RuntimeException("Invalid thumbnail transition state");
+ }
+
+ return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
+ }
+
+ /**
+ * This animation is created when we are doing a thumbnail transition, for the activity that is
+ * leaving, and the activity that is entering.
+ */
+ Animation createThumbnailEnterExitAnimationLocked(int thumbTransitState, int appWidth,
+ int appHeight, int transit) {
+ Animation a;
+ final int thumbWidthI = mNextAppTransitionThumbnail.getWidth();
+ final float thumbWidth = thumbWidthI > 0 ? thumbWidthI : 1;
+ final int thumbHeightI = mNextAppTransitionThumbnail.getHeight();
+ final float thumbHeight = thumbHeightI > 0 ? thumbHeightI : 1;
+
+ switch (thumbTransitState) {
+ case THUMBNAIL_TRANSITION_ENTER_SCALE_UP: {
+ // Entering app scales up with the thumbnail
+ float scaleW = thumbWidth / appWidth;
+ float scaleH = thumbHeight / appHeight;
+ a = new ScaleAnimation(scaleW, 1, scaleH, 1,
+ computePivot(mNextAppTransitionStartX, scaleW),
+ computePivot(mNextAppTransitionStartY, scaleH));
+ break;
+ }
+ case THUMBNAIL_TRANSITION_EXIT_SCALE_UP: {
+ // Exiting app while the thumbnail is scaling up should fade or stay in place
+ if (transit == TRANSIT_WALLPAPER_INTRA_OPEN) {
+ // Fade out while bringing up selected activity. This keeps the
+ // current activity from showing through a launching wallpaper
+ // activity.
+ a = new AlphaAnimation(1, 0);
+ } else {
+ // noop animation
+ a = new AlphaAnimation(1, 1);
+ }
+ break;
+ }
+ case THUMBNAIL_TRANSITION_ENTER_SCALE_DOWN: {
+ // Entering the other app, it should just be visible while we scale the thumbnail
+ // down above it
+ a = new AlphaAnimation(1, 1);
+ break;
+ }
+ case THUMBNAIL_TRANSITION_EXIT_SCALE_DOWN: {
+ // Exiting the current app, the app should scale down with the thumbnail
+ float scaleW = thumbWidth / appWidth;
+ float scaleH = thumbHeight / appHeight;
+ Animation scale = new ScaleAnimation(1, scaleW, 1, scaleH,
+ computePivot(mNextAppTransitionStartX, scaleW),
+ computePivot(mNextAppTransitionStartY, scaleH));
+
+ Animation alpha = new AlphaAnimation(1, 0);
+
+ AnimationSet set = new AnimationSet(true);
+ set.addAnimation(scale);
+ set.addAnimation(alpha);
+ set.setZAdjustment(Animation.ZORDER_TOP);
+ a = set;
+ break;
+ }
+ default:
+ throw new RuntimeException("Invalid thumbnail transition state");
+ }
+
+ return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
+ }
+
Animation loadAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
- int appWidth, int appHeight) {
+ int appWidth, int appHeight, Rect containingFrame, Rect contentInsets) {
Animation a;
if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
a = loadAnimation(mNextAppTransitionPackage, enter ?
@@ -501,7 +658,14 @@
mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
mNextAppTransitionScaleUp =
(mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
- a = createThumbnailAnimationLocked(transit, enter, false, appWidth, appHeight);
+ if (mUseAlternateThumbnailAnimation) {
+ a = createAlternateThumbnailEnterExitAnimationLocked(
+ getThumbnailTransitionState(enter), appWidth, appHeight, transit,
+ containingFrame, contentInsets);
+ } else {
+ a = createThumbnailEnterExitAnimationLocked(getThumbnailTransitionState(enter),
+ appWidth, appHeight, transit);
+ }
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) {
String animName = mNextAppTransitionScaleUp ?
"ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN";
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index adfb2bd..4f80f1f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -3155,7 +3155,22 @@
final int height = displayInfo.appHeight;
if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG, "applyAnimation: atoken="
+ atoken);
- Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height);
+
+ // Determine the visible rect to calculate the thumbnail clip
+ WindowState win = atoken.findMainWindow();
+ Rect containingFrame = new Rect(0, 0, width, height);
+ Rect contentInsets = new Rect();
+ if (win != null) {
+ if (win.mContainingFrame != null) {
+ containingFrame.set(win.mContainingFrame);
+ }
+ if (win.mContentInsets != null) {
+ contentInsets.set(win.mContentInsets);
+ }
+ }
+
+ Animation a = mAppTransition.loadAnimation(lp, transit, enter, width, height,
+ containingFrame, contentInsets);
if (a != null) {
if (DEBUG_ANIM) {
RuntimeException e = null;
@@ -8608,11 +8623,13 @@
wtoken.deferClearAllDrawn = false;
}
+ boolean useAlternateThumbnailAnimation =
+ SystemProperties.getBoolean("persist.anim.use_alt_thumbnail", false);
AppWindowAnimator appAnimator =
topOpeningApp == null ? null : topOpeningApp.mAppAnimator;
Bitmap nextAppTransitionThumbnail = mAppTransition.getNextAppTransitionThumbnail();
- if (nextAppTransitionThumbnail != null && appAnimator != null
- && appAnimator.animation != null) {
+ if (!useAlternateThumbnailAnimation && nextAppTransitionThumbnail != null
+ && appAnimator != null && appAnimator.animation != null) {
// This thumbnail animation is very special, we need to have
// an extra surface with the thumbnail included with the animation.
Rect dirty = new Rect(0, 0, nextAppTransitionThumbnail.getWidth(),
@@ -8636,8 +8653,8 @@
drawSurface.release();
appAnimator.thumbnailLayer = topOpeningLayer;
DisplayInfo displayInfo = getDefaultDisplayInfoLocked();
- Animation anim = mAppTransition.createThumbnailAnimationLocked(
- transit, true, true, displayInfo.appWidth, displayInfo.appHeight);
+ Animation anim = mAppTransition.createThumbnailScaleAnimationLocked(
+ displayInfo.appWidth, displayInfo.appHeight, transit);
appAnimator.thumbnailAnimation = anim;
anim.restrictDuration(MAX_ANIMATION_DURATION);
anim.scaleCurrentDuration(mTransitionAnimationScale);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 2cd6000..6b3c368 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -113,6 +113,11 @@
float mAlpha = 0;
float mLastAlpha = 0;
+ boolean mHasClipRect;
+ Rect mClipRect = new Rect();
+ Rect mTmpClipRect = new Rect();
+ Rect mLastClipRect = new Rect();
+
// Used to save animation distances between the time they are calculated and when they are
// used.
int mAnimDw;
@@ -951,6 +956,7 @@
if (screenAnimation) {
tmpMatrix.postConcat(screenRotationAnimation.getEnterTransformation().getMatrix());
}
+
//TODO (multidisplay): Magnification is supported only for the default display.
if (mService.mAccessibilityController != null && displayId == Display.DEFAULT_DISPLAY) {
MagnificationSpec spec = mService.mAccessibilityController
@@ -985,6 +991,7 @@
// transforming since it is more important to have that
// animation be smooth.
mShownAlpha = mAlpha;
+ mHasClipRect = false;
if (!mService.mLimitedAlphaCompositing
|| (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
|| (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
@@ -998,6 +1005,10 @@
}
if (appTransformation != null) {
mShownAlpha *= appTransformation.getAlpha();
+ if (appTransformation.hasClipRect()) {
+ mClipRect.set(appTransformation.getClipRect());
+ mHasClipRect = true;
+ }
}
if (mAnimator.mUniverseBackground != null) {
mShownAlpha *= mAnimator.mUniverseBackground.mUniverseTransform.getAlpha();
@@ -1149,15 +1160,32 @@
applyDecorRect(w.mDecorFrame);
}
- if (!w.mSystemDecorRect.equals(w.mLastSystemDecorRect)) {
- w.mLastSystemDecorRect.set(w.mSystemDecorRect);
+ // By default, the clip rect is the system decor rect
+ Rect clipRect = w.mSystemDecorRect;
+ if (mHasClipRect) {
+
+ // If we have an animated clip rect, intersect it with the system decor rect
+ // NOTE: We are adding a temporary workaround due to the status bar not always reporting
+ // the correct system decor rect. In such cases, we take into account the specified
+ // content insets as well.
+ int offsetTop = Math.max(w.mSystemDecorRect.top, w.mContentInsets.top);
+ mTmpClipRect.set(w.mSystemDecorRect);
+ mTmpClipRect.offset(0, -offsetTop);
+ mTmpClipRect.intersect(mClipRect);
+ mTmpClipRect.offset(0, offsetTop);
+ clipRect = mTmpClipRect;
+
+ }
+
+ if (!clipRect.equals(mLastClipRect)) {
+ mLastClipRect.set(clipRect);
try {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
- "CROP " + w.mSystemDecorRect.toShortString(), null);
- mSurfaceControl.setWindowCrop(w.mSystemDecorRect);
+ "CROP " + clipRect.toShortString(), null);
+ mSurfaceControl.setWindowCrop(clipRect);
} catch (RuntimeException e) {
Slog.w(TAG, "Error setting crop surface of " + w
- + " crop=" + w.mSystemDecorRect.toShortString(), e);
+ + " crop=" + clipRect.toShortString(), e);
if (!recoveringMemory) {
mService.reclaimSomeSurfaceMemoryLocked(this, "crop", true);
}
@@ -1302,8 +1330,8 @@
mSurfaceLayer = mAnimLayer;
mSurfaceControl.setLayer(mAnimLayer);
mSurfaceControl.setMatrix(
- mDsDx*w.mHScale, mDtDx*w.mVScale,
- mDsDy*w.mHScale, mDtDy*w.mVScale);
+ mDsDx * w.mHScale, mDtDx * w.mVScale,
+ mDsDy * w.mHScale, mDtDy * w.mVScale);
if (mLastHidden && mDrawState == HAS_DRAWN) {
if (WindowManagerService.SHOW_TRANSACTIONS) WindowManagerService.logSurface(w,
diff --git a/services/usb/java/com/android/server/usb/UsbDeviceManager.java b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
index efbfb33..502ee18 100644
--- a/services/usb/java/com/android/server/usb/UsbDeviceManager.java
+++ b/services/usb/java/com/android/server/usb/UsbDeviceManager.java
@@ -90,7 +90,6 @@
private static final int MSG_SYSTEM_READY = 3;
private static final int MSG_BOOT_COMPLETED = 4;
private static final int MSG_USER_SWITCHED = 5;
- private static final int MSG_START_ACCESSORY_MODE = 6;
private static final int AUDIO_MODE_NONE = 0;
private static final int AUDIO_MODE_SOURCE = 1;
@@ -153,7 +152,7 @@
mHandler.updateState(state);
} else if ("START".equals(accessory)) {
if (DEBUG) Slog.d(TAG, "got accessory start");
- mHandler.sendEmptyMessage(MSG_START_ACCESSORY_MODE);
+ startAccessoryMode();
}
}
};
@@ -171,7 +170,7 @@
if (nativeIsStartRequested()) {
if (DEBUG) Slog.d(TAG, "accessory attached at boot");
- mHandler.sendEmptyMessage(MSG_START_ACCESSORY_MODE);
+ startAccessoryMode();
}
boolean secureAdbEnabled = SystemProperties.getBoolean("ro.adb.secure", false);
@@ -233,8 +232,6 @@
functions = UsbManager.USB_FUNCTION_AUDIO_SOURCE;
}
- if (DEBUG) Slog.d(TAG, "startAccessoryMode: " + functions);
-
if (functions != null) {
mAccessoryModeRequestTime = SystemClock.elapsedRealtime();
setCurrentFunctions(functions, false);
@@ -309,7 +306,6 @@
// current USB state
private boolean mConnected;
private boolean mConfigured;
- private boolean mAccessoryStartPending;
private String mCurrentFunctions;
private String mDefaultFunctions;
private UsbAccessory mCurrentAccessory;
@@ -538,7 +534,6 @@
if (mConfigured && enteringAccessoryMode) {
// successfully entered accessory mode
- mAccessoryModeRequestTime = 0;
if (mAccessoryStrings != null) {
mCurrentAccessory = new UsbAccessory(mAccessoryStrings);
@@ -616,11 +611,6 @@
case MSG_UPDATE_STATE:
mConnected = (msg.arg1 == 1);
mConfigured = (msg.arg2 == 1);
-
- if (!mConnected) {
- mAccessoryStartPending = false;
- }
-
updateUsbNotification();
updateAdbNotification();
if (containsFunction(mCurrentFunctions,
@@ -634,10 +624,6 @@
updateUsbState();
updateAudioSourceFunction();
}
- if (mConnected && mConfigured && mAccessoryStartPending) {
- startAccessoryMode();
- mAccessoryStartPending = false;
- }
break;
case MSG_ENABLE_ADB:
setAdbEnabled(msg.arg1 == 1);
@@ -674,16 +660,6 @@
mCurrentUser = msg.arg1;
break;
}
- case MSG_START_ACCESSORY_MODE:
- if (mConnected && mConfigured) {
- startAccessoryMode();
- } else {
- // we sometimes receive the kernel "accessory start" uevent
- // before the "configured" uevent. In this case we need to defer
- // handling this event until after we received the configured event
- mAccessoryStartPending = true;
- }
- break;
}
}
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index dd2cbc1..743a26c 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -458,44 +458,8 @@
}
@Override
- public IBinder getFocusedWindowToken() {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void setInputFilter(IInputFilter filter) throws RemoteException {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void getWindowFrame(IBinder token, Rect outFrame) {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void setMagnificationCallbacks(IMagnificationCallbacks callbacks) {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void setMagnificationSpec(MagnificationSpec spec) {
- // TODO Auto-generated method stub
- }
-
- @Override
- public MagnificationSpec getCompatibleMagnificationSpecForWindow(IBinder windowToken) {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
public boolean isRotationFrozen() throws RemoteException {
// TODO Auto-generated method stub
return false;
}
-
- @Override
- public void setTouchExplorationEnabled(boolean enabled) {
- }
}