Merge "Add Transition for App -> Recents on TV." into nyc-dev

am: 29f6a9b

* commit '29f6a9be037d305b32b237d2637fced77d2bcc36':
  Add Transition for App -> Recents on TV.
This commit is contained in:
Sid Soundararajan
2016-03-17 18:29:44 +00:00
committed by android-build-merger
8 changed files with 161 additions and 16 deletions

View File

@@ -18,7 +18,6 @@
android:id="@+id/recents_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/recents_tv_background_gradient"
android:clipChildren="false"
android:clipToPadding="false"
android:layoutDirection="rtl">

View File

@@ -59,7 +59,7 @@
<ImageView
android:id="@+id/card_view_thumbnail"
android:layout_width="match_parent"
android:layout_height="@dimen/recents_tv_card_height"
android:layout_height="@dimen/recents_tv_screenshot_height"
android:scaleType="centerCrop"
android:gravity="center"
android:layout_alignParentTop="true"

View File

@@ -19,7 +19,7 @@
<resources>
<!-- Dimens for recents card in the recents view on tv -->
<dimen name="recents_tv_card_width">268dip</dimen>
<dimen name="recents_tv_card_height">151dip</dimen>
<dimen name="recents_tv_screenshot_height">151dip</dimen>
<dimen name="recents_tv_card_extra_badge_size">20dip</dimen>
<dimen name="recents_tv_banner_width">114dip</dimen>
<dimen name="recents_tv_banner_height">64dip</dimen>

View File

@@ -15,4 +15,5 @@ limitations under the License.
-->
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<item format="float" type="integer" name="unselected_scale">1.0</item>
<item format="float" type="integer" name="selected_scale">1.1</item>
</resources>

View File

@@ -66,6 +66,7 @@ import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskGrouping;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.tv.views.TaskCardView;
import com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
import com.android.systemui.recents.views.TaskStackView;
import com.android.systemui.recents.views.TaskStackViewScroller;
@@ -166,6 +167,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
boolean mCanReuseTaskStackViews = true;
boolean mDraggingInRecents;
boolean mLaunchedWhileDocking;
private boolean mIsRunningOnTv;
// Task launching
Rect mSearchBarBounds = new Rect();
@@ -230,8 +232,10 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
UiModeManager uiModeManager = (UiModeManager) mContext.getSystemService(Context.UI_MODE_SERVICE);
if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
mRecentsIntentActivityName = RECENTS_TV_ACTIVITY;
mIsRunningOnTv = true;
} else {
mRecentsIntentActivityName = RECENTS_ACTIVITY;
mIsRunningOnTv = false;
}
}
@@ -793,6 +797,22 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
}
}
/**
* Creates the activity options for an app->recents transition on TV.
*/
private ActivityOptions getThumbnailTransitionActivityOptionsForTV(
ActivityManager.RunningTaskInfo topTask) {
Bitmap thumbnail = mThumbnailTransitionBitmapCache;
Rect rect = TaskCardView.getStartingCardThumbnailRect(mContext);
if (thumbnail != null) {
return ActivityOptions.makeThumbnailAspectScaleDownAnimation(mDummyStackView,
null, (int) rect.left, (int) rect.top,
(int) rect.width(), (int) rect.height(), mHandler, null);
}
// If both the screenshot and thumbnail fails, then just fall back to the default transition
return getUnknownTransitionActivityOptions();
}
private Bitmap getThumbnailBitmap(ActivityManager.RunningTaskInfo topTask, Task toTask,
TaskViewTransform toTransform) {
Bitmap thumbnail;
@@ -872,6 +892,11 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
boolean isTopTaskHome, boolean animate) {
RecentsTaskLoader loader = Recents.getTaskLoader();
// If we are on TV, divert to a different helper method
if (mIsRunningOnTv) {
setUpAndStartTvRecents(topTask, isTopTaskHome, animate);
return;
}
// In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
// should always preload the tasks now. If we are dragging in recents, reload them as
// the stacks might have changed.
@@ -946,6 +971,90 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener
mLastToggleTime = SystemClock.elapsedRealtime();
}
/**
* Used to set up the animations of Tv Recents, then start the Recents Activity.
* TODO: Add the Transitions for Home -> Recents TV
* TODO: Shift Transition code to separate class under /tv directory and access
* from here
*/
private void setUpAndStartTvRecents(ActivityManager.RunningTaskInfo topTask,
boolean isTopTaskHome, boolean animate) {
RecentsTaskLoader loader = Recents.getTaskLoader();
// In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
// should always preload the tasks now. If we are dragging in recents, reload them as
// the stacks might have changed.
if (mLaunchedWhileDocking || mTriggeredFromAltTab || sInstanceLoadPlan == null) {
// Create a new load plan if preloadRecents() was never triggered
sInstanceLoadPlan = loader.createLoadPlan(mContext);
}
if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
loader.preloadTasks(sInstanceLoadPlan, topTask.id, isTopTaskHome);
}
TaskStack stack = sInstanceLoadPlan.getTaskStack();
// Update the header bar if necessary
updateHeaderBarLayout(false /* tryAndBindSearchWidget */, stack);
// Prepare the dummy stack for the transition
TaskStackLayoutAlgorithm.VisibilityReport stackVr =
mDummyStackView.computeStackVisibilityReport();
if (!animate) {
ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1);
startRecentsActivity(topTask, opts, false /* fromHome */,
false /* fromSearchHome */, false /* fromThumbnail*/, stackVr);
return;
}
boolean hasRecentTasks = stack.getTaskCount() > 0;
boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
if (useThumbnailTransition) {
// Try starting with a thumbnail transition
ActivityOptions opts = getThumbnailTransitionActivityOptionsForTV(topTask);
if (opts != null) {
startRecentsActivity(topTask, opts, false /* fromHome */,
false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
} else {
// Fall through below to the non-thumbnail transition
useThumbnailTransition = false;
}
}
if (!useThumbnailTransition) {
// If there is no thumbnail transition, but is launching from home into recents, then
// use a quick home transition and do the animation from home
if (hasRecentTasks) {
SystemServicesProxy ssp = Recents.getSystemServices();
String homeActivityPackage = ssp.getHomeActivityPackageName();
String searchWidgetPackage = null;
if (RecentsDebugFlags.Static.EnableSearchBar) {
searchWidgetPackage = Prefs.getString(mContext,
Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
} else {
AppWidgetProviderInfo searchWidgetInfo = ssp.resolveSearchAppWidget();
if (searchWidgetInfo != null) {
searchWidgetPackage = searchWidgetInfo.provider.getPackageName();
}
}
// Determine whether we are coming from a search owned home activity
boolean fromSearchHome = (homeActivityPackage != null) &&
homeActivityPackage.equals(searchWidgetPackage);
ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
false /* fromThumbnail */, stackVr);
} else {
// Otherwise we do the normal fade from an unknown source
ActivityOptions opts = getUnknownTransitionActivityOptions();
startRecentsActivity(topTask, opts, true /* fromHome */,
false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
}
}
mLastToggleTime = SystemClock.elapsedRealtime();
}
/**
* Starts the recents activity.
*/

View File

@@ -29,6 +29,7 @@ import com.android.systemui.R;
public class ViewFocusAnimator implements View.OnFocusChangeListener {
private final float mUnselectedScale;
private final float mSelectedScale;
private final float mSelectedScaleDelta;
private final float mUnselectedZ;
private final float mSelectedZDelta;
@@ -49,8 +50,9 @@ public class ViewFocusAnimator implements View.OnFocusChangeListener {
TypedValue out = new TypedValue();
res.getValue(R.integer.unselected_scale, out, true);
mUnselectedScale = out.getFloat();
mSelectedScaleDelta = res.getFraction(R.fraction.lb_focus_zoom_factor_medium, 1, 1) -
mUnselectedScale;
res.getValue(R.integer.selected_scale, out, true);
mSelectedScale = out.getFloat();
mSelectedScaleDelta = mSelectedScale - mUnselectedScale;
mUnselectedZ = res.getDimensionPixelOffset(R.dimen.recents_tv_unselected_item_z);
mSelectedZDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_selected_item_z_delta);

View File

@@ -16,10 +16,8 @@
package com.android.systemui.recents.tv.views;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.Handler;
@@ -121,10 +119,10 @@ public class RecentsTvTransitionHelper {
};
}
try {
Rect taskRect = taskView.getGlobalRect();
Rect taskRect = taskView.getFocusedThumbnailRect();
WindowManagerGlobal.getWindowManagerService()
.overridePendingAppTransitionThumb(task.thumbnail, taskRect.left,
taskRect.top, callback, true);
.overridePendingAppTransitionAspectScaledThumb(task.thumbnail, taskRect.left,
taskRect.top, taskRect.width(), taskRect.height(), callback, true);
} catch (RemoteException e) {
Log.w(TAG, "Failed to override transition: " + e);
}

View File

@@ -16,8 +16,13 @@
package com.android.systemui.recents.tv.views;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.TypedValue;
import android.view.Display;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -71,15 +76,46 @@ public class TaskCardView extends LinearLayout {
mThumbnailView.getFocusedRect(r);
}
public Rect getFocusedRect() {
public Rect getFocusedThumbnailRect() {
Rect r = new Rect();
getFocusedRect(r);
mThumbnailView.getGlobalVisibleRect(r);
TypedValue out = new TypedValue();
getContext().getResources().getValue(R.integer.selected_scale, out, true);
float deltaScale = (out.getFloat() - 1.0f) / 2;
r.set((int) (r.left - r.left * deltaScale),
(int) (r.top - r.top * deltaScale),
(int) (r.right + r.right * deltaScale),
(int) (r.bottom + r.bottom * deltaScale));
return r;
}
public Rect getGlobalRect() {
Rect r = new Rect();
getGlobalVisibleRect(r);
return r;
public static Rect getStartingCardThumbnailRect(Context context) {
Resources res = context.getResources();
TypedValue out = new TypedValue();
res.getValue(R.integer.selected_scale, out, true);
float scale = out.getFloat();
int width = res.getDimensionPixelOffset(R.dimen.recents_tv_card_width);
int widthDelta = (int) (width * scale - width);
int height = (int) (res.getDimensionPixelOffset(
R.dimen.recents_tv_screenshot_height) * scale);
int padding = res.getDimensionPixelOffset(R.dimen.recents_tv_grid_row_padding);
int headerHeight = (int) ((res.getDimensionPixelOffset(
R.dimen.recents_tv_card_extra_badge_size) +
res.getDimensionPixelOffset(R.dimen.recents_tv_icon_padding_bottom)) * scale);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int screenWidth = size.x;
int screenHeight = size.y;
return new Rect(screenWidth - width - padding - widthDelta / 2,
screenHeight / 2 - height / 2 + headerHeight / 2,
screenWidth - padding + widthDelta / 2,
screenHeight / 2 + height / 2 + headerHeight / 2);
}
}