Fixing issues with dim not animating, adding dismiss button delay, tweaking empty recents text. (Bug 15431590, 15573497)

Change-Id: I9c11e04cd52f9e000d8ba3e443f2500c9aa7edbb
This commit is contained in:
Winson Chung
2014-06-12 17:52:39 -07:00
parent 9214eff52a
commit a26fb7822d
10 changed files with 201 additions and 8 deletions

View File

@@ -21,7 +21,6 @@
android:gravity="center"
android:textSize="20sp"
android:textColor="#ffffffff"
android:textStyle="italic"
android:text="@string/recents_empty_message"
android:fontFamily="sans-serif-light"
android:visibility="gone" />

View File

@@ -56,6 +56,7 @@
android:layout_marginEnd="4dp"
android:layout_gravity="center_vertical|end"
android:padding="18dp"
android:visibility="invisible"
android:src="@drawable/recents_dismiss_light" />
</com.android.systemui.recents.views.TaskBarView>
</com.android.systemui.recents.views.TaskView>

View File

@@ -108,6 +108,8 @@
<!-- milliseconds before the heads up notification accepts touches. -->
<integer name="heads_up_sensitivity_delay">700</integer>
<!-- The duration in seconds to wait before the dismiss buttons are shown. -->
<integer name="recents_task_bar_dismiss_delay_seconds">3</integer>
<!-- The min animation duration for animating views that are currently visible. -->
<integer name="recents_filter_animate_current_views_min_duration">175</integer>
<!-- The min animation duration for animating views that are newly visible. -->

View File

@@ -0,0 +1,72 @@
/*
* 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.systemui.recents;
import android.os.Handler;
/**
* A dozer is a class that fires a trigger after it falls asleep. You can occasionally poke it to
* wake it up, but it will fall asleep if left untouched.
*/
public class DozeTrigger {
Handler mHandler;
boolean mIsDozing;
boolean mHasTriggered;
int mDozeDurationSeconds;
Runnable mSleepRunnable;
// Sleep-runnable
Runnable mDozeRunnable = new Runnable() {
@Override
public void run() {
mSleepRunnable.run();
mIsDozing = false;
mHasTriggered = true;
}
};
public DozeTrigger(int dozeDurationSeconds, Runnable sleepRunnable) {
mHandler = new Handler();
mDozeDurationSeconds = dozeDurationSeconds;
mSleepRunnable = sleepRunnable;
}
/** Starts dozing. This also resets the trigger flag. */
public void startDozing() {
poke();
mHasTriggered = false;
}
/** Poke this dozer to wake it up for a little bit. */
public void poke() {
mHandler.removeCallbacks(mDozeRunnable);
mHandler.postDelayed(mDozeRunnable, mDozeDurationSeconds * 1000);
mIsDozing = true;
}
/** Returns whether we are dozing or not. */
public boolean isDozing() {
return mIsDozing;
}
/** Returns whether the trigger has fired at least once. */
public boolean hasTriggered() {
return mHasTriggered;
}
}

View File

@@ -526,6 +526,11 @@ public class RecentsActivity extends Activity implements RecentsView.RecentsView
return super.onKeyDown(keyCode, event);
}
@Override
public void onUserInteraction() {
mRecentsView.onUserInteraction();
}
@Override
public void onBackPressed() {
// If we are mid-animation into Recents, then reverse it and finish

View File

@@ -89,6 +89,7 @@ public class RecentsConfiguration {
public int taskBarEnterAnimDuration;
public int taskBarEnterAnimDelay;
public int taskBarExitAnimDuration;
public int taskBarDismissDozeDelaySeconds;
/** Nav bar scrim */
public int navBarScrimEnterDuration;
@@ -205,6 +206,8 @@ public class RecentsConfiguration {
res.getInteger(R.integer.recents_animate_task_bar_enter_delay);
taskBarExitAnimDuration =
res.getInteger(R.integer.recents_animate_task_bar_exit_duration);
taskBarDismissDozeDelaySeconds =
res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds);
// Nav bar scrim
navBarScrimEnterDuration =

View File

@@ -307,6 +307,20 @@ public class RecentsView extends FrameLayout implements TaskStackView.TaskStackV
}
}
/** Notifies each task view of the user interaction. */
public void onUserInteraction() {
// Get the first stack view
TaskStackView stackView = null;
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child instanceof TaskStackView) {
stackView = (TaskStackView) child;
stackView.onUserInteraction();
}
}
}
/** Focuses the next task in the first stack view */
public void focusNextTask(boolean forward) {
// Get the first stack view

View File

@@ -105,7 +105,7 @@ class TaskBarView extends FrameLayout {
/** Synchronizes this bar view's properties with the task's transform */
void updateViewPropertiesToTaskTransform(TaskViewTransform animateFromTransform,
TaskViewTransform toTransform, int duration) {
if (duration > 0) {
if (duration > 0 && (mDismissButton.getVisibility() == View.VISIBLE)) {
if (animateFromTransform != null) {
mDismissButton.setAlpha(animateFromTransform.dismissAlpha);
}
@@ -169,7 +169,7 @@ class TaskBarView extends FrameLayout {
setTranslationY(-getMeasuredHeight());
animate()
.translationY(0)
.setStartDelay(delay > -1 ? delay : mConfig.taskBarEnterAnimDelay)
.setStartDelay(delay)
.setInterpolator(mConfig.fastOutSlowInInterpolator)
.setDuration(mConfig.taskBarEnterAnimDuration)
.withLayer()
@@ -178,6 +178,7 @@ class TaskBarView extends FrameLayout {
/** Animates this task bar as it exits recents */
public void animateOnLaunchingTask(final Runnable r) {
// Animate the task bar out of the first task view
animate()
.translationY(-getMeasuredHeight())
.setStartDelay(0)
@@ -193,6 +194,28 @@ class TaskBarView extends FrameLayout {
.start();
}
/** Animates this task bar if the user does not interact with the stack after a certain time. */
public void animateOnNoUserInteraction() {
mDismissButton.setVisibility(View.VISIBLE);
mDismissButton.setAlpha(0f);
mDismissButton.animate()
.alpha(1f)
.setStartDelay(0)
.setInterpolator(mConfig.fastOutLinearInInterpolator)
.setDuration(mConfig.taskBarEnterAnimDuration)
.withLayer()
.start();
}
/** Mark this task view that the user does has not interacted with the stack after a certain time. */
public void setOnNoUserInteraction() {
if (mDismissButton.getVisibility() != View.VISIBLE) {
mDismissButton.animate().cancel();
mDismissButton.setVisibility(View.VISIBLE);
mDismissButton.setAlpha(1f);
}
}
/** Enable the hw layers on this task view */
void enableHwLayers() {
mDismissButton.setLayerType(View.LAYER_TYPE_HARDWARE, null);

View File

@@ -38,6 +38,7 @@ import android.widget.OverScroller;
import com.android.systemui.R;
import com.android.systemui.recents.Console;
import com.android.systemui.recents.Constants;
import com.android.systemui.recents.DozeTrigger;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsPackageMonitor;
import com.android.systemui.recents.RecentsTaskLoader;
@@ -70,6 +71,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
TaskStackViewCallbacks mCb;
ViewPool<TaskView, Task> mViewPool;
ArrayList<TaskViewTransform> mTaskTransforms = new ArrayList<TaskViewTransform>();
DozeTrigger mDozeTrigger;
// The various rects that define the stack view
Rect mRect = new Rect();
@@ -107,6 +109,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
mTouchHandler = new TaskStackViewTouchHandler(context, this);
mViewPool = new ViewPool<TaskView, Task>(context, this);
mInflater = LayoutInflater.from(context);
mDozeTrigger = new DozeTrigger(mConfig.taskBarDismissDozeDelaySeconds, new Runnable() {
@Override
public void run() {
// Show the task bar dismiss buttons
int childCount = getChildCount();
for (int i = 0; i < childCount; i++) {
TaskView tv = (TaskView) getChildAt(i);
tv.animateOnNoUserInteraction();
}
}
});
mHwLayersTrigger = new ReferenceCountedTrigger(getContext(), new Runnable() {
@Override
public void run() {
@@ -797,6 +810,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// Mark that we have completely the first layout
mAwaitingFirstLayout = false;
// Start dozing
mDozeTrigger.startDozing();
// Prepare the first view for its enter animation
int offsetTopAlign = -mTaskRect.top;
int offscreenY = mRect.bottom - (mTaskRect.top - mRect.top);
@@ -867,6 +883,15 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
return isTransformedTouchPointInView(x, y, child, null);
}
/** Pokes the dozer on user interaction. */
void onUserInteraction() {
// If the dozer is not running, then either we have not yet laid out, or it has already
// fallen asleep, so just let it rest.
if (mDozeTrigger.isDozing()) {
mDozeTrigger.poke();
}
}
/**** TaskStackCallbacks Implementation ****/
@Override
@@ -1152,6 +1177,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal
// but just in case, re-enable it here
tv.setClipViewInStack(true);
// If the doze trigger has already fired, then update the state for this task view
if (mDozeTrigger.hasTriggered()) {
tv.setOnNoUserInteraction();
}
// Add/attach the view to the hierarchy
if (Console.Enabled) {
Console.log(Constants.Log.ViewPool.PoolCallbacks, " [TaskStackView|insertIndex]",

View File

@@ -16,6 +16,7 @@
package com.android.systemui.recents.views;
import android.animation.ObjectAnimator;
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context;
@@ -93,6 +94,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On
super(context, attrs, defStyleAttr, defStyleRes);
mConfig = RecentsConfiguration.getInstance();
setWillNotDraw(false);
setDim(getDim());
}
@Override
@@ -206,7 +208,7 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On
setScaleX(1f);
setScaleY(1f);
setAlpha(1f);
mDim = 0;
setDim(0);
invalidate();
}
@@ -251,6 +253,8 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On
if (isTaskViewFrontMost) {
// Hide the front most task bar view so we can animate it in
mBarView.prepareAnimateEnterRecents();
// Set the dim to 0 so we can animate it in
setDim(0);
}
} else if (mConfig.launchedFromHome) {
@@ -292,7 +296,13 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On
} else if (mConfig.launchedFromAppWithThumbnail) {
if (ctx.isFrontMost) {
// Animate the task bar of the first task view
mBarView.animateOnEnterRecents(-1);
mBarView.animateOnEnterRecents(mConfig.taskBarEnterAnimDelay);
// Animate the dim into view as well
ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", getDimOverlayFromScale());
anim.setStartDelay(mConfig.taskBarEnterAnimDelay);
anim.setDuration(mConfig.taskBarEnterAnimDuration);
anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
anim.start();
}
} else if (mConfig.launchedFromHome) {
@@ -325,9 +335,27 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On
ctx.postAnimationTrigger.increment();
}
/** Animates this task view if the user does not interact with the stack after a certain time. */
public void animateOnNoUserInteraction() {
mBarView.animateOnNoUserInteraction();
}
/** Mark this task view that the user does has not interacted with the stack after a certain time. */
public void setOnNoUserInteraction() {
mBarView.setOnNoUserInteraction();
}
/** Animates this task view as it exits recents */
public void animateOnLaunchingTask(final Runnable r) {
mBarView.animateOnLaunchingTask(r);
// Animate the dim
if (mDim > 0) {
ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
anim.setDuration(mConfig.taskBarExitAnimDuration);
anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
anim.start();
}
}
/** Animates the deletion of this task view */
@@ -398,13 +426,29 @@ public class TaskView extends FrameLayout implements Task.TaskCallbacks, View.On
}
}
/** Update the dim as a function of the scale of this view. */
void updateDimOverlayFromScale() {
/** Returns the current dim. */
public void setDim(int dim) {
mDim = dim;
postInvalidateOnAnimation();
}
/** Returns the current dim. */
public int getDim() {
return mDim;
}
/** Compute the dim as a function of the scale of this view. */
int getDimOverlayFromScale() {
float minScale = Constants.Values.TaskStackView.StackPeekMinScale;
float scaleRange = 1f - minScale;
float dim = (1f - getScaleX()) / scaleRange;
dim = mDimInterpolator.getInterpolation(Math.min(dim, 1f));
mDim = Math.max(0, Math.min(mMaxDim, (int) (dim * 255)));
return Math.max(0, Math.min(mMaxDim, (int) (dim * 255)));
}
/** Update the dim as a function of the scale of this view. */
void updateDimOverlayFromScale() {
setDim(getDimOverlayFromScale());
}
@Override