summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/ViewRootImpl.java18
-rw-r--r--core/java/android/view/WindowManager.java13
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/ExitRecentsWindowFirstAnimationFrameEvent.java28
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java8
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java4
-rw-r--r--packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java10
-rw-r--r--services/core/java/com/android/server/wm/AppTransition.java25
-rw-r--r--services/core/java/com/android/server/wm/AppWindowAnimator.java20
-rw-r--r--services/core/java/com/android/server/wm/WindowManagerService.java41
9 files changed, 117 insertions, 50 deletions
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index fdea1ba157f4..cd9dd97468b3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -16,6 +16,8 @@
package android.view;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
+
import android.Manifest;
import android.animation.LayoutTransition;
import android.app.ActivityManagerNative;
@@ -37,7 +39,6 @@ import android.graphics.Region;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
-import android.hardware.input.InputManager;
import android.media.AudioManager;
import android.os.Binder;
import android.os.Build;
@@ -74,7 +75,6 @@ import android.view.animation.AccelerateDecelerateInterpolator;
import android.view.animation.Interpolator;
import android.view.inputmethod.InputConnection;
import android.view.inputmethod.InputMethodManager;
-import android.view.WindowCallbacks;
import android.widget.Scroller;
import com.android.internal.R;
@@ -176,6 +176,11 @@ public final class ViewRootImpl implements ViewParent,
int mViewVisibility;
boolean mAppVisible = true;
+ // For recents to freeform transition we need to keep drawing after the app receives information
+ // that it became invisible. This will ignore that information and depend on the decor view
+ // visibility to control drawing. The decor view visibility will get adjusted when the app get
+ // stopped and that's when the app will stop drawing further frames.
+ private boolean mForceDecorViewVisibility = false;
int mOrigWindowType = -1;
/** Whether the window had focus during the most recent traversal. */
@@ -561,6 +566,8 @@ public final class ViewRootImpl implements ViewParent,
& WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
mInputChannel = new InputChannel();
}
+ mForceDecorViewVisibility = (mWindowAttributes.privateFlags
+ & PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY) != 0;
try {
mOrigWindowType = mWindowAttributes.type;
mAttachInfo.mRecomputeGlobalAttributes = true;
@@ -1063,7 +1070,7 @@ public final class ViewRootImpl implements ViewParent,
}
int getHostVisibility() {
- return mAppVisible ? mView.getVisibility() : View.GONE;
+ return (mAppVisible || mForceDecorViewVisibility) ? mView.getVisibility() : View.GONE;
}
/**
@@ -1568,7 +1575,7 @@ public final class ViewRootImpl implements ViewParent,
boolean insetsPending = false;
int relayoutResult = 0;
- boolean isViewVisible = viewVisibility == View.VISIBLE;
+ final boolean isViewVisible = viewVisibility == View.VISIBLE;
if (mFirst || windowShouldResize || insetsChanged ||
viewVisibilityChanged || params != null) {
@@ -2471,8 +2478,7 @@ public final class ViewRootImpl implements ViewParent,
if (callbacks != null) {
for (SurfaceHolder.Callback c : callbacks) {
if (c instanceof SurfaceHolder.Callback2) {
- ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(
- mSurfaceHolder);
+ ((SurfaceHolder.Callback2)c).surfaceRedrawNeeded(mSurfaceHolder);
}
}
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index edf4297afdea..1521f2ed07fe 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -118,8 +118,7 @@ public interface WindowManager extends ViewManager {
*/
public void removeViewImmediate(View view);
- public static class LayoutParams extends ViewGroup.LayoutParams
- implements Parcelable {
+ public static class LayoutParams extends ViewGroup.LayoutParams implements Parcelable {
/**
* X position for this window. With the default gravity it is ignored.
* When using {@link Gravity#LEFT} or {@link Gravity#START} or {@link Gravity#RIGHT} or
@@ -1149,13 +1148,21 @@ public interface WindowManager extends ViewManager {
/**
* Flag indicating that the x, y, width, and height members should be
- * ignored (and thus their previous value preserved). For example
+ * ignored (and thus their previous value preserved). For example
* because they are being managed externally through repositionChild.
*
* {@hide}
*/
public static final int PRIVATE_FLAG_PRESERVE_GEOMETRY = 0x00002000;
+ /**
+ * Flag that will make window ignore app visibility and instead depend purely on the decor
+ * view visibility for determining window visibility. This is used by recents to keep
+ * drawing after it launches an app.
+ * @hide
+ */
+ public static final int PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY = 0x00004000;
+
/**
* Control flags that are private to the platform.
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ExitRecentsWindowFirstAnimationFrameEvent.java b/packages/SystemUI/src/com/android/systemui/recents/ExitRecentsWindowFirstAnimationFrameEvent.java
new file mode 100644
index 000000000000..8ae8c53a9197
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/ExitRecentsWindowFirstAnimationFrameEvent.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.recents;
+
+import com.android.systemui.recents.events.EventBus;
+
+/**
+ * Event sent when the exit animation is started.
+ *
+ * This is sent so parts of UI can synchronize on this event and adjust their appearance. An example
+ * of that is hiding the tasks when the launched application window becomes visible.
+ */
+public class ExitRecentsWindowFirstAnimationFrameEvent extends EventBus.Event {
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 3ae8827b3fc6..1e46e6f54245 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -37,6 +37,7 @@ import android.view.KeyEvent;
import android.view.View;
import android.view.ViewStub;
import android.view.ViewTreeObserver;
+import android.view.WindowManager;
import com.android.internal.logging.MetricsLogger;
import com.android.systemui.R;
import com.android.systemui.recents.events.EventBus;
@@ -352,6 +353,8 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
mScrimViews = new SystemBarScrimViews(this);
+ getWindow().getAttributes().privateFlags |=
+ WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
// Create the home intent runnable
Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
@@ -648,6 +651,11 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
}
+ public final void onBusEvent(ExitRecentsWindowFirstAnimationFrameEvent event) {
+ mRecentsView.setStackViewVisibility(View.INVISIBLE);
+ mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
+ }
+
public final void onBusEvent(CancelEnterRecentsWindowAnimationEvent event) {
RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
int launchToTaskId = launchState.launchedToTaskId;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 50aa2f746f23..b491f943734d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -68,8 +68,8 @@ import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
* An implementation of the Recents component for the current user. For secondary users, this can
* be called remotely from the system user.
*/
-public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub
- implements ActivityOptions.OnAnimationFinishedListener {
+public class RecentsImpl extends IRecentsNonSystemUserCallbacks.Stub implements
+ ActivityOptions.OnAnimationFinishedListener {
private final static String TAG = "RecentsImpl";
private final static boolean DEBUG = false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 85b8fcfb4a7f..b2f716d2add5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -27,12 +27,12 @@ import android.os.Handler;
import android.os.IRemoteCallback;
import android.os.RemoteException;
import android.util.Log;
-import android.util.SparseArray;
import android.view.AppTransitionAnimationSpec;
import android.view.IAppTransitionAnimationSpecsFuture;
import android.view.WindowManagerGlobal;
import com.android.internal.annotations.GuardedBy;
import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.ExitRecentsWindowFirstAnimationFrameEvent;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
@@ -106,6 +106,7 @@ public class RecentsTransitionHelper {
// If we are launching into another task, cancel the previous task's
// window transition
EventBus.getDefault().send(new CancelEnterRecentsWindowAnimationEvent(task));
+ EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
if (lockToTask) {
// Request screen pinning after the animation runs
@@ -116,7 +117,12 @@ public class RecentsTransitionHelper {
} else {
// This is only the case if the task is not on screen (scrolled offscreen for example)
transitionFuture = null;
- animStartedListener = null;
+ animStartedListener = new ActivityOptions.OnAnimationStartedListener() {
+ @Override
+ public void onAnimationStarted() {
+ EventBus.getDefault().send(new ExitRecentsWindowFirstAnimationFrameEvent());
+ }
+ };
}
if (taskView == null) {
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 89f565816a62..943c9ed39262 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -139,7 +139,7 @@ public class AppTransition implements Dump {
private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
private final Context mContext;
- private final Handler mH;
+ private final WindowManagerService mService;
private int mNextAppTransition = TRANSIT_UNSET;
@@ -208,15 +208,10 @@ public class AppTransition implements Dump {
private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
- private final Object mServiceLock;
- private final WindowSurfacePlacer mWindowSurfacePlacer;
- AppTransition(Context context, Handler h, Object serviceLock,
- WindowSurfacePlacer windowSurfacePlacer) {
+ AppTransition(Context context, WindowManagerService service) {
mContext = context;
- mH = h;
- mServiceLock = serviceLock;
- mWindowSurfacePlacer = windowSurfacePlacer;
+ mService = service;
mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
com.android.internal.R.interpolator.linear_out_slow_in);
mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
@@ -971,7 +966,7 @@ public class AppTransition implements Dump {
@Override
public void onAnimationEnd(Animation animation) {
- mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget();
+ mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK, callback).sendToTarget();
}
@Override
@@ -1326,7 +1321,8 @@ public class AppTransition implements Dump {
void postAnimationCallback() {
if (mNextAppTransitionCallback != null) {
- mH.sendMessage(mH.obtainMessage(H.DO_ANIMATION_CALLBACK, mNextAppTransitionCallback));
+ mService.mH.sendMessage(mService.mH.obtainMessage(H.DO_ANIMATION_CALLBACK,
+ mNextAppTransitionCallback));
mNextAppTransitionCallback = null;
}
}
@@ -1478,14 +1474,15 @@ public class AppTransition implements Dump {
} catch (RemoteException e) {
Slog.w(TAG, "Failed to fetch app transition specs: " + e);
}
- synchronized (mServiceLock) {
+ synchronized (mService.mWindowMap) {
mNextAppTransitionAnimationsSpecsPending = false;
overridePendingAppTransitionMultiThumb(specs,
mNextAppTransitionFutureCallback, null /* finishedCallback */,
mNextAppTransitionScaleUp);
mNextAppTransitionFutureCallback = null;
- mWindowSurfacePlacer.requestTraversal();
+ mService.prolongAnimationsFromSpecs(specs, mNextAppTransitionScaleUp);
}
+ mService.requestTraversal();
}
});
}
@@ -1672,8 +1669,8 @@ public class AppTransition implements Dump {
}
boolean prepared = prepare();
if (isTransitionSet()) {
- mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
- mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
+ mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
+ mService.mH.sendEmptyMessageDelayed(H.APP_TRANSITION_TIMEOUT, APP_TRANSITION_TIMEOUT_MS);
}
return prepared;
}
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index 2905269eb21c..dfd01efe36d0 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -37,6 +37,10 @@ import java.util.ArrayList;
public class AppWindowAnimator {
static final String TAG = "AppWindowAnimator";
+ private static final int PROLONG_ANIMATION_DISABLED = 0;
+ static final int PROLONG_ANIMATION_AT_END = 1;
+ static final int PROLONG_ANIMATION_AT_START = 2;
+
final AppWindowToken mAppToken;
final WindowManagerService mService;
final WindowAnimator mAnimator;
@@ -85,7 +89,7 @@ public class AppWindowAnimator {
// If true when the animation hits the last frame, it will keep running on that last frame.
// This is used to synchronize animation with Recents and we wait for Recents to tell us to
// finish or for a new animation be set as fail-safe mechanism.
- private boolean mProlongAnimation;
+ private int mProlongAnimation;
// Whether the prolong animation can be removed when animation is set. The purpose of this is
// that if recents doesn't tell us to remove the prolonged animation, we will get rid of it
// when new animation is set.
@@ -142,7 +146,7 @@ public class AppWindowAnimator {
anim.setBackgroundColor(0);
}
if (mClearProlongedAnimation) {
- mProlongAnimation = false;
+ mProlongAnimation = PROLONG_ANIMATION_DISABLED;
} else {
mClearProlongedAnimation = true;
}
@@ -266,6 +270,10 @@ public class AppWindowAnimator {
return false;
}
transformation.clear();
+ if (mProlongAnimation == PROLONG_ANIMATION_AT_START) {
+ animation.setStartTime(currentTime);
+ currentTime += 1;
+ }
boolean hasMoreFrames = animation.getTransformation(currentTime, transformation);
if (!hasMoreFrames) {
if (deferThumbnailDestruction && !deferFinalFrameCleanup) {
@@ -278,7 +286,7 @@ public class AppWindowAnimator {
"Stepped animation in " + mAppToken + ": more=" + hasMoreFrames +
", xform=" + transformation + ", mProlongAnimation=" + mProlongAnimation);
deferFinalFrameCleanup = false;
- if (mProlongAnimation) {
+ if (mProlongAnimation == PROLONG_ANIMATION_AT_END) {
hasMoreFrames = true;
} else {
animation = null;
@@ -434,13 +442,13 @@ public class AppWindowAnimator {
}
}
- void startProlongAnimation() {
- mProlongAnimation = true;
+ void startProlongAnimation(int prolongType) {
+ mProlongAnimation = prolongType;
mClearProlongedAnimation = false;
}
void endProlongedAnimation() {
- mProlongAnimation = false;
+ mProlongAnimation = PROLONG_ANIMATION_DISABLED;
}
// This is an animation that does nothing: it just immediately finishes
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index c359c5306b4c..a9bd71ff703b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -50,6 +50,9 @@ import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
+import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
+
import android.Manifest;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
@@ -909,7 +912,7 @@ public class WindowManagerService extends IWindowManager.Stub
PowerManager.PARTIAL_WAKE_LOCK, "SCREEN_FROZEN");
mScreenFrozenLock.setReferenceCounted(false);
- mAppTransition = new AppTransition(context, mH, mWindowMap, mWindowPlacerLocked);
+ mAppTransition = new AppTransition(context, this);
mAppTransition.registerListenerLocked(mActivityManagerAppTransitionNotifier);
mActivityManager = ActivityManagerNative.getDefault();
@@ -3692,22 +3695,26 @@ public class WindowManagerService extends IWindowManager.Stub
synchronized (mWindowMap) {
mAppTransition.overridePendingAppTransitionMultiThumb(specs, onAnimationStartedCallback,
onAnimationFinishedCallback, scaleUp);
- if (!scaleUp) {
- // This is used by freeform to recents windows transition. We need to synchronize
- // the animation with the appearance of the content of recents, so we will make
- // animation stay on the last frame a little longer.
- mTmpTaskIds.clear();
- for (int i = specs.length - 1; i >= 0; i--) {
- mTmpTaskIds.put(specs[i].taskId, 0);
- }
- for (final WindowState win : mWindowMap.values()) {
- final Task task = win.getTask();
- if (task != null && mTmpTaskIds.get(task.mTaskId, -1) != -1) {
- final AppWindowToken appToken = win.mAppToken;
- if (appToken != null && appToken.mAppAnimator != null) {
- appToken.mAppAnimator.startProlongAnimation();
- }
- }
+ prolongAnimationsFromSpecs(specs, scaleUp);
+
+ }
+ }
+
+ void prolongAnimationsFromSpecs(AppTransitionAnimationSpec[] specs, boolean scaleUp) {
+ // This is used by freeform <-> recents windows transition. We need to synchronize
+ // the animation with the appearance of the content of recents, so we will make
+ // animation stay on the first or last frame a little longer.
+ mTmpTaskIds.clear();
+ for (int i = specs.length - 1; i >= 0; i--) {
+ mTmpTaskIds.put(specs[i].taskId, 0);
+ }
+ for (final WindowState win : mWindowMap.values()) {
+ final Task task = win.getTask();
+ if (task != null && mTmpTaskIds.get(task.mTaskId, -1) != -1) {
+ final AppWindowToken appToken = win.mAppToken;
+ if (appToken != null && appToken.mAppAnimator != null) {
+ appToken.mAppAnimator.startProlongAnimation(scaleUp ?
+ PROLONG_ANIMATION_AT_START : PROLONG_ANIMATION_AT_END);
}
}
}