Methods Summary |
---|
void | computeMinMaxScroll(java.util.ArrayList tasks, boolean launchedWithAltTab, boolean launchedFromHome)Computes the minimum and maximum scroll progress values. This method may be called before
the RecentsConfiguration is set, so we need to pass in the alt-tab state.
// Clear the progress map
mTaskProgressMap.clear();
// Return early if we have no tasks
if (tasks.isEmpty()) {
mMinScrollP = mMaxScrollP = 0;
return;
}
// Note that we should account for the scale difference of the offsets at the screen bottom
int taskHeight = mTaskRect.height();
float pAtBottomOfStackRect = screenYToCurveProgress(mStackVisibleRect.bottom);
float pWithinAffiliateTop = screenYToCurveProgress(mStackVisibleRect.bottom -
mWithinAffiliationOffset);
float scale = curveProgressToScale(pWithinAffiliateTop);
int scaleYOffset = (int) (((1f - scale) * taskHeight) / 2);
pWithinAffiliateTop = screenYToCurveProgress(mStackVisibleRect.bottom -
mWithinAffiliationOffset + scaleYOffset);
float pWithinAffiliateOffset = pAtBottomOfStackRect - pWithinAffiliateTop;
float pBetweenAffiliateOffset = pAtBottomOfStackRect -
screenYToCurveProgress(mStackVisibleRect.bottom - mBetweenAffiliationOffset);
float pTaskHeightOffset = pAtBottomOfStackRect -
screenYToCurveProgress(mStackVisibleRect.bottom - taskHeight);
float pNavBarOffset = pAtBottomOfStackRect -
screenYToCurveProgress(mStackVisibleRect.bottom - (mStackVisibleRect.bottom -
mStackRect.bottom));
// Update the task offsets
float pAtBackMostCardTop = 0.5f;
float pAtFrontMostCardTop = pAtBackMostCardTop;
int taskCount = tasks.size();
for (int i = 0; i < taskCount; i++) {
Task task = tasks.get(i);
mTaskProgressMap.put(task.key, pAtFrontMostCardTop);
if (i < (taskCount - 1)) {
// Increment the peek height
float pPeek = task.group.isFrontMostTask(task) ?
pBetweenAffiliateOffset : pWithinAffiliateOffset;
pAtFrontMostCardTop += pPeek;
}
}
mMaxScrollP = pAtFrontMostCardTop - ((1f - pTaskHeightOffset - pNavBarOffset));
mMinScrollP = tasks.size() == 1 ? Math.max(mMaxScrollP, 0f) : 0f;
if (launchedWithAltTab && launchedFromHome) {
// Center the top most task, since that will be focused first
mInitialScrollP = mMaxScrollP;
} else {
mInitialScrollP = pAtFrontMostCardTop - 0.825f;
}
mInitialScrollP = Math.min(mMaxScrollP, Math.max(0, mInitialScrollP));
|
public void | computeRects(int windowWidth, int windowHeight, android.graphics.Rect taskStackBounds)Computes the stack and task rects
// Compute the stack rects
mViewRect.set(0, 0, windowWidth, windowHeight);
mStackRect.set(taskStackBounds);
mStackVisibleRect.set(taskStackBounds);
mStackVisibleRect.bottom = mViewRect.bottom;
int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * mStackRect.width());
int heightPadding = mConfig.taskStackTopPaddingPx;
mStackRect.inset(widthPadding, heightPadding);
// Compute the task rect
int size = mStackRect.width();
int left = mStackRect.left + (mStackRect.width() - size) / 2;
mTaskRect.set(left, mStackRect.top,
left + size, mStackRect.top + size);
// Update the affiliation offsets
float visibleTaskPct = 0.5f;
mWithinAffiliationOffset = mConfig.taskBarHeight;
mBetweenAffiliationOffset = (int) (visibleTaskPct * mTaskRect.height());
|
public com.android.systemui.recents.views.TaskStackViewLayoutAlgorithm$VisibilityReport | computeStackVisibilityReport(java.util.ArrayList tasks)Computes the maximum number of visible tasks and thumbnails. Requires that
computeMinMaxScroll() is called first.
if (tasks.size() <= 1) {
return new VisibilityReport(1, 1);
}
// Walk backwards in the task stack and count the number of tasks and visible thumbnails
int taskHeight = mTaskRect.height();
int numVisibleTasks = 1;
int numVisibleThumbnails = 1;
float progress = mTaskProgressMap.get(tasks.get(tasks.size() - 1).key) - mInitialScrollP;
int prevScreenY = curveProgressToScreenY(progress);
for (int i = tasks.size() - 2; i >= 0; i--) {
Task task = tasks.get(i);
progress = mTaskProgressMap.get(task.key) - mInitialScrollP;
if (progress < 0) {
break;
}
boolean isFrontMostTaskInGroup = task.group.isFrontMostTask(task);
if (isFrontMostTaskInGroup) {
float scaleAtP = curveProgressToScale(progress);
int scaleYOffsetAtP = (int) (((1f - scaleAtP) * taskHeight) / 2);
int screenY = curveProgressToScreenY(progress) + scaleYOffsetAtP;
boolean hasVisibleThumbnail = (prevScreenY - screenY) > mConfig.taskBarHeight;
if (hasVisibleThumbnail) {
numVisibleThumbnails++;
numVisibleTasks++;
prevScreenY = screenY;
} else {
// Once we hit the next front most task that does not have a visible thumbnail,
// walk through remaining visible set
for (int j = i; j >= 0; j--) {
numVisibleTasks++;
progress = mTaskProgressMap.get(tasks.get(j).key) - mInitialScrollP;
if (progress < 0) {
break;
}
}
break;
}
} else if (!isFrontMostTaskInGroup) {
// Affiliated task, no thumbnail
numVisibleTasks++;
}
}
return new VisibilityReport(numVisibleTasks, numVisibleThumbnails);
|
float | curveProgressToScale(float p)Converts from the progress along the curve to a scale.
if (p < 0) return StackPeekMinScale;
if (p > 1) return 1f;
float scaleRange = (1f - StackPeekMinScale);
float scale = StackPeekMinScale + (p * scaleRange);
return scale;
|
int | curveProgressToScreenY(float p)Converts from the progress along the curve to a screen coordinate.
if (p < 0 || p > 1) return mStackVisibleRect.top + (int) (p * mStackVisibleRect.height());
float pIndex = p * PrecisionSteps;
int pFloorIndex = (int) Math.floor(pIndex);
int pCeilIndex = (int) Math.ceil(pIndex);
float xFraction = 0;
if (pFloorIndex < PrecisionSteps && (pCeilIndex != pFloorIndex)) {
float pFraction = (pIndex - pFloorIndex) / (pCeilIndex - pFloorIndex);
xFraction = (xp[pCeilIndex] - xp[pFloorIndex]) * pFraction;
}
float x = xp[pFloorIndex] + xFraction;
return mStackVisibleRect.top + (int) (x * mStackVisibleRect.height());
|
float | getStackScrollForTask(com.android.systemui.recents.model.Task t)Returns the scroll to such task top = 1f;
if (!mTaskProgressMap.containsKey(t.key)) return 0f;
return mTaskProgressMap.get(t.key);
|
public TaskViewTransform | getStackTransform(com.android.systemui.recents.model.Task task, float stackScroll, TaskViewTransform transformOut, TaskViewTransform prevTransform)Update/get the transform
// Return early if we have an invalid index
if (task == null || !mTaskProgressMap.containsKey(task.key)) {
transformOut.reset();
return transformOut;
}
return getStackTransform(mTaskProgressMap.get(task.key), stackScroll, transformOut,
prevTransform);
|
public TaskViewTransform | getStackTransform(float taskProgress, float stackScroll, TaskViewTransform transformOut, TaskViewTransform prevTransform)Update/get the transform
float pTaskRelative = taskProgress - stackScroll;
float pBounded = Math.max(0, Math.min(pTaskRelative, 1f));
// If the task top is outside of the bounds below the screen, then immediately reset it
if (pTaskRelative > 1f) {
transformOut.reset();
transformOut.rect.set(mTaskRect);
return transformOut;
}
// The check for the top is trickier, since we want to show the next task if it is at all
// visible, even if p < 0.
if (pTaskRelative < 0f) {
if (prevTransform != null && Float.compare(prevTransform.p, 0f) <= 0) {
transformOut.reset();
transformOut.rect.set(mTaskRect);
return transformOut;
}
}
float scale = curveProgressToScale(pBounded);
int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2);
int minZ = mConfig.taskViewTranslationZMinPx;
int maxZ = mConfig.taskViewTranslationZMaxPx;
transformOut.scale = scale;
transformOut.translationY = curveProgressToScreenY(pBounded) - mStackVisibleRect.top -
scaleYOffset;
transformOut.translationZ = Math.max(minZ, minZ + (pBounded * (maxZ - minZ)));
transformOut.rect.set(mTaskRect);
transformOut.rect.offset(0, transformOut.translationY);
Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
transformOut.visible = true;
transformOut.p = pTaskRelative;
return transformOut;
|
public android.graphics.Rect | getUntransformedTaskViewSize()Returns the untransformed task view size.
Rect tvSize = new Rect(mTaskRect);
tvSize.offsetTo(0, 0);
return tvSize;
|
public static void | initializeCurve()Initializes the curve.
if (xp != null && px != null) return;
xp = new float[PrecisionSteps + 1];
px = new float[PrecisionSteps + 1];
// Approximate f(x)
float[] fx = new float[PrecisionSteps + 1];
float step = 1f / PrecisionSteps;
float x = 0;
for (int xStep = 0; xStep <= PrecisionSteps; xStep++) {
fx[xStep] = logFunc(x);
x += step;
}
// Calculate the arc length for x:1->0
float pLength = 0;
float[] dx = new float[PrecisionSteps + 1];
dx[0] = 0;
for (int xStep = 1; xStep < PrecisionSteps; xStep++) {
dx[xStep] = (float) Math.sqrt(Math.pow(fx[xStep] - fx[xStep - 1], 2) + Math.pow(step, 2));
pLength += dx[xStep];
}
// Approximate p(x), a function of cumulative progress with x, normalized to 0..1
float p = 0;
px[0] = 0f;
px[PrecisionSteps] = 1f;
for (int xStep = 1; xStep <= PrecisionSteps; xStep++) {
p += Math.abs(dx[xStep] / pLength);
px[xStep] = p;
}
// Given p(x), calculate the inverse function x(p). This assumes that x(p) is also a valid
// function.
int xStep = 0;
p = 0;
xp[0] = 0f;
xp[PrecisionSteps] = 1f;
for (int pStep = 0; pStep < PrecisionSteps; pStep++) {
// Walk forward in px and find the x where px <= p && p < px+1
while (xStep < PrecisionSteps) {
if (px[xStep] > p) break;
xStep++;
}
// Now, px[xStep-1] <= p < px[xStep]
if (xStep == 0) {
xp[pStep] = 0;
} else {
// Find x such that proportionally, x is correct
float fraction = (p - px[xStep - 1]) / (px[xStep] - px[xStep - 1]);
x = (xStep - 1 + fraction) * step;
xp[pStep] = x;
}
p += step;
}
|
float | invLogFunc(float y)The inverse of the log function describing the curve.
return (float) (Math.log((1f - reverse(y)) * (LogBase - 1) + 1) / Math.log(LogBase));
|
static float | logFunc(float x)The log function describing the curve.
return 1f - (float) (Math.pow(LogBase, reverse(x))) / (LogBase);
|
static float | reverse(float x)Reverses and scales out x.
return (-x * XScale) + 1;
|
float | screenYToCurveProgress(int screenY)Converts from a screen coordinate to the progress along the curve.
float x = (float) (screenY - mStackVisibleRect.top) / mStackVisibleRect.height();
if (x < 0 || x > 1) return x;
float xIndex = x * PrecisionSteps;
int xFloorIndex = (int) Math.floor(xIndex);
int xCeilIndex = (int) Math.ceil(xIndex);
float pFraction = 0;
if (xFloorIndex < PrecisionSteps && (xCeilIndex != xFloorIndex)) {
float xFraction = (xIndex - xFloorIndex) / (xCeilIndex - xFloorIndex);
pFraction = (px[xCeilIndex] - px[xFloorIndex]) * xFraction;
}
return px[xFloorIndex] + pFraction;
|