diff options
28 files changed, 569 insertions, 432 deletions
diff --git a/packages/SystemUI/res/layout/recents_task_view_header.xml b/packages/SystemUI/res/layout/recents_task_view_header.xml index fa6575824552..59a2bd90e2b0 100644 --- a/packages/SystemUI/res/layout/recents_task_view_header.xml +++ b/packages/SystemUI/res/layout/recents_task_view_header.xml @@ -18,7 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/task_view_bar" android:layout_width="match_parent" - android:layout_height="@dimen/recents_task_bar_height" + android:layout_height="@dimen/recents_task_view_header_height" android:layout_gravity="top|center_horizontal"> <com.android.systemui.recents.views.FixedSizeImageView android:id="@+id/icon" @@ -28,8 +28,8 @@ android:layout_gravity="center_vertical|start" android:paddingTop="8dp" android:paddingBottom="8dp" - android:paddingStart="12dp" - android:paddingEnd="16dp" /> + android:paddingStart="16dp" + android:paddingEnd="12dp" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" @@ -71,7 +71,7 @@ android:layout_height="@dimen/recents_task_view_header_button_height" android:layout_marginEnd="@dimen/recents_task_view_header_button_width" android:layout_gravity="center_vertical|end" - android:padding="13dp" + android:padding="16dp" android:src="@drawable/star" android:background="?android:selectableItemBackground" android:alpha="0" @@ -81,7 +81,7 @@ android:layout_width="@dimen/recents_task_view_header_button_width" android:layout_height="@dimen/recents_task_view_header_button_height" android:layout_gravity="center_vertical|end" - android:padding="13dp" + android:padding="16dp" android:src="@drawable/recents_dismiss_light" android:background="?android:selectableItemBackground" android:alpha="0" diff --git a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml index 1becdab0e39f..433e69e4bd2c 100644 --- a/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml +++ b/packages/SystemUI/res/layout/recents_task_view_header_overlay.xml @@ -25,8 +25,8 @@ android:layout_gravity="center_vertical|start" android:paddingTop="8dp" android:paddingBottom="8dp" - android:paddingStart="12dp" - android:paddingEnd="16dp" /> + android:paddingStart="16dp" + android:paddingEnd="12dp" /> <TextView android:id="@+id/app_title" android:layout_width="match_parent" @@ -45,9 +45,9 @@ <com.android.systemui.recents.views.FixedSizeImageView android:id="@+id/app_info" android:layout_width="@dimen/recents_task_view_header_button_width" - android:layout_height="@dimen/recents_task_bar_height" + android:layout_height="@dimen/recents_task_view_header_button_height" android:layout_gravity="center_vertical|end" - android:padding="13dp" + android:padding="16dp" android:background="?android:selectableItemBackground" android:src="@drawable/recents_info_light" /> </FrameLayout>
\ No newline at end of file diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml index 43e7bacd3d41..f7e23449fa0a 100644 --- a/packages/SystemUI/res/values-land/config.xml +++ b/packages/SystemUI/res/values-land/config.xml @@ -28,14 +28,4 @@ <!-- We have only space for one notification on phone landscape layouts. --> <integer name="keyguard_max_notification_count">1</integer> - - <!-- Recents: The relative range of visible tasks from the current scroll position - while the stack is focused. --> - <item name="recents_layout_focused_range_min" format="float" type="integer">-3</item> - <item name="recents_layout_focused_range_max" format="float" type="integer">2</item> - - <!-- Recents: The relative range of visible tasks from the current scroll position - while the stack is not focused. --> - <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item> - <item name="recents_layout_unfocused_range_max" format="float" type="integer">1.5</item> </resources> diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml index 585984c9c99f..26a81c8d835c 100644 --- a/packages/SystemUI/res/values-land/dimens.xml +++ b/packages/SystemUI/res/values-land/dimens.xml @@ -22,9 +22,6 @@ <!-- Standard notification gravity --> <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer> - <!-- The size of the initial peek area at the bottom of the stack (above the nav bar). --> - <dimen name="recents_initial_bottom_peek_size">@dimen/recents_task_bar_height</dimen> - <dimen name="docked_divider_handle_width">2dp</dimen> <dimen name="docked_divider_handle_height">16dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml index db4da10756ed..1f6bbd342b39 100644 --- a/packages/SystemUI/res/values-sw600dp/config.xml +++ b/packages/SystemUI/res/values-sw600dp/config.xml @@ -33,16 +33,6 @@ <!-- Set to true to enable the user switcher on the keyguard. --> <bool name="config_keyguardUserSwitcher">true</bool> - <!-- Recents: The relative range of visible tasks from the current scroll position - while the stack is focused. --> - <item name="recents_layout_focused_range_min" format="float" type="integer">-3</item> - <item name="recents_layout_focused_range_max" format="float" type="integer">3</item> - - <!-- Recents: The relative range of visible tasks from the current scroll position - while the stack is not focused. --> - <item name="recents_layout_unfocused_range_min" format="float" type="integer">-2</item> - <item name="recents_layout_unfocused_range_max" format="float" type="integer">2.5</item> - <!-- Nav bar button default ordering/layout --> <string name="config_navBarLayout" translatable="false">space;back,home,recent;menu_ime</string> diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml index 66963c43e8dc..a2010be4f6a1 100644 --- a/packages/SystemUI/res/values-sw600dp/dimens.xml +++ b/packages/SystemUI/res/values-sw600dp/dimens.xml @@ -96,15 +96,6 @@ <dimen name="qs_expand_margin">0dp</dimen> - <!-- The top padding for the task stack. --> - <dimen name="recents_stack_top_padding">40dp</dimen> - - <!-- The size of the initial peek area at the bottom of the stack (above the nav bar). --> - <dimen name="recents_initial_bottom_peek_size">100dp</dimen> - - <!-- The side padding for the task stack. --> - <dimen name="recents_stack_left_right_padding">64dp</dimen> - <!-- Keyboard shortcuts helper --> <dimen name="ksh_layout_width">488dp</dimen> </resources> diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml index 8fe6be93917a..25e96c8848db 100644 --- a/packages/SystemUI/res/values-sw720dp/dimens.xml +++ b/packages/SystemUI/res/values-sw720dp/dimens.xml @@ -29,11 +29,6 @@ <!-- Bottom margin (from display edge) for status bar panels --> <dimen name="panel_float">56dp</dimen> - <!-- The radius of the rounded corners on a task view. --> - <dimen name="recents_task_view_rounded_corners_radius">3dp</dimen> - <!-- The radius of the rounded corners on a task view's shadow. --> - <dimen name="recents_task_view_shadow_rounded_corners_radius">12dp</dimen> - <!-- The fraction of the screen height where the clock on the Keyguard has its center. The max value is used when no notifications are displaying, and the min value is when the highest possible number of notifications are showing. --> diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml index 076ba0082ba1..4f3db05aca58 100644 --- a/packages/SystemUI/res/values/colors.xml +++ b/packages/SystemUI/res/values/colors.xml @@ -63,7 +63,7 @@ <!-- The recents task bar dark text color to be drawn on top of light backgrounds. --> <color name="recents_task_bar_dark_text_color">#cc000000</color> <!-- The recents task bar light dismiss icon color to be drawn on top of dark backgrounds. --> - <color name="recents_task_bar_light_icon_color">#ffeeeeee</color> + <color name="recents_task_bar_light_icon_color">#ccffffff</color> <!-- The recents task bar dark dismiss icon color to be drawn on top of light backgrounds. --> <color name="recents_task_bar_dark_icon_color">#99000000</color> <!-- The lock to task button background color. --> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 8cd21670f986..02458b95649d 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -234,85 +234,6 @@ <!-- Default distance from each snap target that GlowPadView considers a "hit" --> <dimen name="glowpadview_inner_radius">15dip</dimen> - <!-- The size of the icon in the recents task view header. --> - <dimen name="recents_task_view_header_icon_width">56dp</dimen> - <dimen name="recents_task_view_header_icon_height">@dimen/recents_task_bar_height</dimen> - - <!-- The size of a button in the recents task view header. --> - <dimen name="recents_task_view_header_button_width">@dimen/recents_task_bar_height</dimen> - <dimen name="recents_task_view_header_button_height">@dimen/recents_task_bar_height</dimen> - - <!-- The radius of the rounded corners on a task view. --> - <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen> - <!-- The radius of the rounded corners on a task view's shadow. --> - <dimen name="recents_task_view_shadow_rounded_corners_radius">12dp</dimen> - - <!-- The min translation in the Z index for the last task. --> - <dimen name="recents_task_view_z_min">3dp</dimen> - - <!-- The max translation in the Z index for the last task. --> - <dimen name="recents_task_view_z_max">24dp</dimen> - - <!-- The amount to translate when animating the removal of a task. --> - <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen> - - <!-- The amount of highlight to make on each task view. --> - <dimen name="recents_task_view_highlight">1dp</dimen> - - <!-- The amount to offset when animating into an affiliate group. --> - <dimen name="recents_task_view_affiliate_group_enter_offset">32dp</dimen> - - <!-- The height of a task view bar. --> - <dimen name="recents_task_bar_height">50dp</dimen> - - <!-- The height of the search bar space. --> - <dimen name="recents_search_bar_space_height">64dp</dimen> - - <!-- The overscroll percentage allowed on the stack. --> - <item name="recents_stack_overscroll_percentage" format="float" type="dimen">0.0875</item> - - <!-- The top padding for the task stack. --> - <dimen name="recents_stack_top_padding">16dp</dimen> - - <!-- The side padding for the task stack. --> - <dimen name="recents_stack_left_right_padding">16dp</dimen> - - <!-- The dimesnsions of the dismiss all recents button. --> - <dimen name="recents_dismiss_all_button_size">48dp</dimen> - - <!-- The min alpha to apply to a task affiliation group color. --> - <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item> - - <!-- The size of the lock-to-app button. --> - <dimen name="recents_lock_to_app_size">56dp</dimen> - - <!-- The size of the lock-to-app button icon. --> - <dimen name="recents_lock_to_app_icon_size">28dp</dimen> - - <!-- The amount to allow the stack to overscroll. --> - <dimen name="recents_stack_overscroll">24dp</dimen> - - <!-- The size of the initial peek area at the top of the stack (below the status bar). --> - <dimen name="recents_initial_top_peek_size">8dp</dimen> - - <!-- The size of the initial peek area at the bottom of the stack (above the nav bar). --> - <dimen name="recents_initial_bottom_peek_size">100dp</dimen> - - <!-- The size of the peek area at the top of the stack (below the status bar). --> - <dimen name="recents_layout_focused_top_peek_size">@dimen/recents_history_button_height</dimen> - - <!-- The size of each task peek area at the bottom of the stack (above the nav bar). --> - <dimen name="recents_layout_focused_bottom_task_peek_size">16dp</dimen> - - <!-- The height of the history button. --> - <dimen name="recents_history_button_height">48dp</dimen> - - <!-- The padding between freeform workspace tasks --> - <dimen name="recents_freeform_workspace_task_padding">8dp</dimen> - - <!-- The offsets the tasks animate from when recents is launched while docking --> - <dimen name="recents_task_view_launched_while_docking_offset">144dp</dimen> - <!-- Space reserved for the cards behind the top card in the bottom stack --> <dimen name="bottom_stack_peek_amount">12dp</dimen> @@ -639,4 +560,91 @@ <!-- Keyboard shortcuts helper --> <dimen name="ksh_layout_width">@dimen/match_parent</dimen> + +<!-- Recents Layout --> + + <!-- The amount to inset the stack, specifically at the top and the other sides. We also + don't want this to change across configurations that Recents can be opened in, so we + define them statically for all display sizes. --> + <dimen name="recents_layout_min_margin">16dp</dimen> + <dimen name="recents_layout_top_margin_phone">16dp</dimen> + <dimen name="recents_layout_top_margin_tablet">32dp</dimen> + <dimen name="recents_layout_top_margin_tablet_xlarge">40dp</dimen> + <dimen name="recents_layout_bottom_margin">16dp</dimen> + <dimen name="recents_layout_side_margin_phone">16dp</dimen> + <dimen name="recents_layout_side_margin_tablet">48dp</dimen> + <dimen name="recents_layout_side_margin_tablet_xlarge">64dp</dimen> + + <!-- The amount to give to the search bar. We also don't want this to change across + configurations that Recents can be opened in, so we define them statically for all + display sizes. --> + <dimen name="recents_layout_search_bar_height_phone">64dp</dimen> + <dimen name="recents_layout_search_bar_height_tablet">72dp</dimen> + + <!-- The height between the top margin and the top of the focused task. --> + <dimen name="recents_layout_top_peek_size">56dp</dimen> + <!-- The height between the bottom margin and the top of task in front of the focused task. --> + <dimen name="recents_layout_bottom_peek_size">56dp</dimen> + + <!-- The offset from the top and bottom of the stack of the focused task. The bottom offset + will be additionally offset by the bottom system insets since it goes under the nav bar + in certain orientations. --> + <dimen name="recents_layout_initial_top_offset_phone_port">128dp</dimen> + <dimen name="recents_layout_initial_bottom_offset_phone_port">80dp</dimen> + <dimen name="recents_layout_initial_top_offset_phone_land">72dp</dimen> + <dimen name="recents_layout_initial_bottom_offset_phone_land">72dp</dimen> + <dimen name="recents_layout_initial_top_offset_tablet">160dp</dimen> + <dimen name="recents_layout_initial_bottom_offset_tablet">112dp</dimen> + + <!-- The min/max translationZ for the tasks in the stack. --> + <dimen name="recents_layout_z_min">3dp</dimen> + <dimen name="recents_layout_z_max">24dp</dimen> + + <!-- The margin between the freeform and stack. We also don't want this to change across + configurations that Recents can be opened in, so we define them statically for all + display sizes. --> + <dimen name="recents_freeform_layout_bottom_margin">16dp</dimen> + + <!-- The padding between each freeform task. --> + <dimen name="recents_freeform_layout_task_padding">8dp</dimen> + +<!-- Recents Views --> + + <!-- The height of a task view bar. --> + <dimen name="recents_task_view_header_height">56dp</dimen> + + <!-- The size of the icon in the recents task view header. --> + <dimen name="recents_task_view_header_icon_width">@dimen/recents_task_view_header_height</dimen> + <dimen name="recents_task_view_header_icon_height">@dimen/recents_task_view_header_height</dimen> + + <!-- The size of a button in the recents task view header. --> + <dimen name="recents_task_view_header_button_width">@dimen/recents_task_view_header_height</dimen> + <dimen name="recents_task_view_header_button_height">@dimen/recents_task_view_header_height</dimen> + + <!-- The radius of the rounded corners on a task view and its shadow (which can be larger + to create a softer corner effect. --> + <dimen name="recents_task_view_rounded_corners_radius">2dp</dimen> + <dimen name="recents_task_view_shadow_rounded_corners_radius">6dp</dimen> + + <!-- The amount of highlight to make on each task view. --> + <dimen name="recents_task_view_highlight">1dp</dimen> + + <!-- The size of the lock-to-app button and its icon. --> + <dimen name="recents_lock_to_app_size">56dp</dimen> + <dimen name="recents_lock_to_app_icon_size">28dp</dimen> + + <!-- The amount of overscroll allowed when flinging to the end of the stack. --> + <dimen name="recents_fling_overscroll_distance">24dp</dimen> + + <!-- The min alpha to apply to a task affiliation group color. --> + <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item> + + <!-- The amount to offset when animating into an affiliate group. --> + <dimen name="recents_task_stack_animation_affiliate_enter_offset">32dp</dimen> + + <!-- The offsets the tasks animate from when recents is launched while docking --> + <dimen name="recents_task_stack_animation_launched_while_docking_offset">144dp</dimen> + + <!-- The amount to translate when animating the removal of a task. --> + <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen> </resources> diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java index aab45b5d02f6..7c0899eb0a8a 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java @@ -55,8 +55,8 @@ import com.android.systemui.recents.events.activity.HideRecentsEvent; import com.android.systemui.recents.events.activity.IterateRecentsEvent; import com.android.systemui.recents.events.activity.LaunchTaskFailedEvent; import com.android.systemui.recents.events.activity.LaunchTaskSucceededEvent; -import com.android.systemui.recents.events.activity.ShowHistoryEvent; import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent; +import com.android.systemui.recents.events.activity.ShowHistoryEvent; import com.android.systemui.recents.events.activity.ToggleRecentsEvent; import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent; import com.android.systemui.recents.events.component.ScreenPinningRequestEvent; @@ -372,7 +372,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails; loader.loadTasks(this, loadPlan, loadOpts); TaskStack stack = loadPlan.getTaskStack(); - mRecentsView.onResume(mIsVisible, stack); + mRecentsView.onResume(mIsVisible, false /* multiWindowChange */, stack); // Animate the SystemUI scrims into view Task launchTarget = stack.getLaunchTarget(); @@ -439,7 +439,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); - EventBus.getDefault().send(new ConfigurationChangedEvent()); + EventBus.getDefault().post(new ConfigurationChangedEvent()); } @Override @@ -541,7 +541,7 @@ public class RecentsActivity extends Activity implements ViewTreeObserver.OnPreD loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails; loader.loadTasks(this, loadPlan, loadOpts); - mRecentsView.onResume(mIsVisible, loadPlan.getTaskStack()); + mRecentsView.onResume(mIsVisible, true /* multiWindowChange */, loadPlan.getTaskStack()); EventBus.getDefault().send(new MultiWindowStateChangedEvent(inMultiWindow)); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java index eec0411f3590..399f1ba2de05 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java @@ -32,13 +32,6 @@ public class RecentsConfiguration { private static final int LARGE_SCREEN_MIN_DP = 600; private static final int XLARGE_SCREEN_MIN_DP = 720; - // Variables that are used for global calculations - private static final float STACK_SIDE_PADDING_PHONES_PCT = 0.03333f; - private static final float STACK_SIZE_PADDING_TABLETS_PCT = 0.075f; - private static final float STACK_SIZE_PADDING_LARGE_TABLETS_PCT = 0.15f; - private static final int SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS = 64; - private static final int SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS = 72; - /** Levels of svelte in increasing severity/austerity. */ // No svelting. public static final int SVELTE_NONE = 0; @@ -57,9 +50,8 @@ public class RecentsConfiguration { // TODO: Values determined by the current context, needs to be refactored into something that is // agnostic of the activity context, but still calculable from the Recents component for // the transition into recents - boolean hasTransposedSearchBar; - boolean hasTransposedNavBar; - public float taskStackWidthPaddingPct; + public boolean hasTransposedSearchBar; + public boolean hasTransposedNavBar; // Since the positions in Recents has to be calculated globally (before the RecentsActivity // starts), we need to calculate some resource values ourselves, instead of relying on framework @@ -71,7 +63,6 @@ public class RecentsConfiguration { /** Misc **/ public boolean fakeShadows; public int svelteLevel; - public int searchBarSpaceHeightPx; public RecentsConfiguration(Context context) { // Load only resources that can not change after the first load either through developer @@ -82,20 +73,10 @@ public class RecentsConfiguration { fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows); svelteLevel = res.getInteger(R.integer.recents_svelte_level); - float density = context.getResources().getDisplayMetrics().density; + float screenDensity = context.getResources().getDisplayMetrics().density; smallestWidth = ssp.getDeviceSmallestWidth(); - isLargeScreen = smallestWidth >= (int) (density * LARGE_SCREEN_MIN_DP); - isXLargeScreen = smallestWidth >= (int) (density * XLARGE_SCREEN_MIN_DP); - searchBarSpaceHeightPx = isLargeScreen ? - (int) (density * SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS) : - (int) (density * SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS); - if (isLargeScreen) { - taskStackWidthPaddingPct = STACK_SIZE_PADDING_TABLETS_PCT; - } else if (isXLargeScreen) { - taskStackWidthPaddingPct = STACK_SIZE_PADDING_LARGE_TABLETS_PCT; - } else { - taskStackWidthPaddingPct = STACK_SIDE_PADDING_PHONES_PCT; - } + isLargeScreen = smallestWidth >= (int) (screenDensity * LARGE_SCREEN_MIN_DP); + isXLargeScreen = smallestWidth >= (int) (screenDensity * XLARGE_SCREEN_MIN_DP); } /** @@ -121,40 +102,4 @@ public class RecentsConfiguration { public void updateOnConfigurationChange() { mLaunchState.updateOnConfigurationChange(); } - - /** - * Returns the task stack bounds in the current orientation. These bounds do not account for - * the system insets. - */ - public void getTaskStackBounds(Rect windowBounds, int topInset, - int rightInset, Rect searchBarBounds, Rect taskStackBounds) { - if (hasTransposedNavBar) { - // In landscape phones, the search bar appears on the left, but we overlay it on top - taskStackBounds.set(windowBounds.left, windowBounds.top + topInset, - windowBounds.right - rightInset, windowBounds.bottom); - } else { - // In portrait, the search bar appears on the top (which already has the inset) - int top = searchBarBounds.isEmpty() ? topInset : 0; - taskStackBounds.set(windowBounds.left, windowBounds.top + searchBarBounds.bottom + top, - windowBounds.right - rightInset, windowBounds.bottom); - } - } - - /** - * Returns the search bar bounds in the current orientation. These bounds do not account for - * the system insets. - */ - public void getSearchBarBounds(Rect windowBounds, int topInset, Rect searchBarSpaceBounds) { - // Return empty rects if search is not enabled - int searchBarSize = searchBarSpaceHeightPx; - if (hasTransposedSearchBar) { - // In landscape phones, the search bar appears on the left - searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset, - windowBounds.left + searchBarSize, windowBounds.bottom); - } else { - // In portrait, the search bar appears on the top - searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset, - windowBounds.right, windowBounds.top + topInset + searchBarSize); - } - } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java index 9e27d3e689c5..39c0cd25d63b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java +++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java @@ -562,7 +562,7 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener mNavBarWidth = res.getDimensionPixelSize( com.android.internal.R.dimen.navigation_bar_width); mTaskBarHeight = res.getDimensionPixelSize( - R.dimen.recents_task_bar_height); + R.dimen.recents_task_view_header_height); mDummyStackView = new TaskStackView(mContext); mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header, null, false); @@ -577,7 +577,6 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener * @param stack the stack to initialize the stack layout with */ private void updateHeaderBarLayout(boolean tryAndBindSearchWidget, TaskStack stack) { - RecentsConfiguration config = Recents.getConfiguration(); SystemServicesProxy ssp = Recents.getSystemServices(); Rect systemInsets = new Rect(); ssp.getStableInsets(systemInsets); @@ -586,28 +585,28 @@ public class RecentsImpl implements ActivityOptions.OnAnimationFinishedListener windowRect.offsetTo(0, 0); // Update the configuration for the current state - config.update(systemInsets); + Recents.getConfiguration().update(systemInsets); + TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm(); if (RecentsDebugFlags.Static.EnableSearchBar && tryAndBindSearchWidget) { // Try and pre-emptively bind the search widget on startup to ensure that we // have the right thumbnail bounds to animate to. // Note: We have to reload the widget id before we get the task stack bounds below if (ssp.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) { - config.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds); + stackLayout.getSearchBarBounds(windowRect, mStatusBarHeight, mSearchBarBounds); } } - config.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right, + stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right, mSearchBarBounds, mTaskStackBounds); // Rebind the header bar and draw it for the transition - TaskStackLayoutAlgorithm stackLayout = mDummyStackView.getStackAlgorithm(); Rect taskStackBounds = new Rect(mTaskStackBounds); stackLayout.setSystemInsets(systemInsets); if (stack != null) { - stackLayout.initialize(taskStackBounds, + stackLayout.initialize(windowRect, taskStackBounds, TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack)); mDummyStackView.setTasks(stack, false /* notifyStackChanges */, - false /* relayoutTaskStack */); + false /* relayoutTaskStack */, false /* multiWindowChange */); } Rect taskViewBounds = stackLayout.getUntransformedTaskViewBounds(); if (!taskViewBounds.equals(mLastTaskViewBounds)) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java index 3c4adb23e77a..324991e92259 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/history/RecentsHistoryView.java @@ -32,9 +32,7 @@ import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto.MetricsEvent; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.recents.Recents; import com.android.systemui.recents.RecentsActivity; -import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.events.EventBus; import com.android.systemui.recents.events.activity.ClearHistoryEvent; import com.android.systemui.recents.events.activity.PackagesChangedEvent; @@ -42,6 +40,7 @@ import com.android.systemui.recents.events.ui.ResetBackgroundScrimEvent; import com.android.systemui.recents.events.ui.UpdateBackgroundScrimEvent; import com.android.systemui.recents.model.TaskStack; import com.android.systemui.recents.views.AnimateableViewBounds; +import com.android.systemui.recents.views.TaskStackLayoutAlgorithm; /** * A list of the recent tasks that are not in the stack. @@ -56,6 +55,7 @@ public class RecentsHistoryView extends LinearLayout private RecentsHistoryAdapter mAdapter; private RecentsHistoryItemTouchCallbacks mItemTouchHandler; private AnimateableViewBounds mViewBounds; + private TaskStackLayoutAlgorithm mLayoutAlgorithm; private boolean mIsVisible; private Rect mSystemInsets = new Rect(); private int mHeaderHeight; @@ -166,10 +166,11 @@ public class RecentsHistoryView extends LinearLayout } /** - * Updates the header height to account for the history button bar. + * Updates the the stack layout and header height to account for the history button bar. */ - public void setHeaderHeight(int height) { - mHeaderHeight = height; + public void update(TaskStackLayoutAlgorithm layoutAlgorithm, int headerHeight) { + mLayoutAlgorithm = layoutAlgorithm; + mHeaderHeight = headerHeight; requestLayout(); } @@ -193,20 +194,23 @@ public class RecentsHistoryView extends LinearLayout @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - RecentsConfiguration config = Recents.getConfiguration(); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); // Pad the view to align the history with the stack layout Rect taskStackBounds = new Rect(); - config.getTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top, - mSystemInsets.right, new Rect() /* searchBarSpaceBounds */, taskStackBounds); - int stackWidthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width()); - int stackHeightPadding = mContext.getResources().getDimensionPixelSize( - R.dimen.recents_stack_top_padding); - mRecyclerView.setPadding(stackWidthPadding + mSystemInsets.left, - stackHeightPadding + mSystemInsets.top + mHeaderHeight, - stackWidthPadding + mSystemInsets.right, mSystemInsets.bottom); + mLayoutAlgorithm.getTaskStackBounds(new Rect(0, 0, width, height), + mSystemInsets.top, mSystemInsets.right, new Rect() /* searchBarSpaceBounds */, + taskStackBounds); + int stackTopPadding = TaskStackLayoutAlgorithm.getDimensionForDevice( + getResources(), + R.dimen.recents_layout_top_margin_phone, + R.dimen.recents_layout_top_margin_tablet, + R.dimen.recents_layout_top_margin_tablet_xlarge + ); + mRecyclerView.setPadding(taskStackBounds.left, + taskStackBounds.top + stackTopPadding + mHeaderHeight, + taskStackBounds.right, mSystemInsets.bottom); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java index 002f6707e5fa..5664d3710df3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java @@ -16,6 +16,12 @@ package com.android.systemui.recents.misc; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.HOME_STACK_ID; +import static android.app.ActivityManager.StackId.PINNED_STACK_ID; +import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; + import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.ActivityOptions; @@ -34,6 +40,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.BitmapFactory; @@ -63,6 +70,7 @@ import android.util.MutableBoolean; import android.util.Pair; import android.view.Display; import android.view.IDockedStackListener; +import android.view.Surface; import android.view.View; import android.view.WindowManager; import android.view.WindowManager.KeyboardShortcutsReceiver; @@ -83,12 +91,6 @@ import java.util.Iterator; import java.util.List; import java.util.Random; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.HOME_STACK_ID; -import static android.app.ActivityManager.StackId.PINNED_STACK_ID; -import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT; - /** * Acts as a shim around the real system services that we need to access data from, and provides * a point of injection when testing UI. @@ -985,28 +987,40 @@ public class SystemServicesProxy { * Returns the smallest width/height. */ public int getDeviceSmallestWidth() { - if (mWm == null) return 0; + if (mDisplay == null) return 0; Point smallestSizeRange = new Point(); Point largestSizeRange = new Point(); - mWm.getDefaultDisplay().getCurrentSizeRange(smallestSizeRange, largestSizeRange); + mDisplay.getCurrentSizeRange(smallestSizeRange, largestSizeRange); return smallestSizeRange.x; } /** - * Returns the display rect. + * Returns the current display rect in the current display orientation. */ public Rect getDisplayRect() { Rect displayRect = new Rect(); - if (mWm == null) return displayRect; + if (mDisplay == null) return displayRect; Point p = new Point(); - mWm.getDefaultDisplay().getRealSize(p); + mDisplay.getRealSize(p); displayRect.set(0, 0, p.x, p.y); return displayRect; } /** + * Returns the current display orientation. + */ + public int getDisplayOrientation() { + // Because of multi-window, the configuration orientation does not necessarily reflect the + // orientation of the display, instead we just use the display's real-size. + Rect displayRect = getDisplayRect(); + return displayRect.width() > displayRect.height() + ? Configuration.ORIENTATION_LANDSCAPE + : Configuration.ORIENTATION_PORTRAIT; + } + + /** * Returns the window rect for the RecentsActivity, based on the dimensions of the home stack. */ public Rect getWindowRect() { diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java index 72b1cab5af22..e28612a3cff6 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -19,6 +19,7 @@ package com.android.systemui.recents.misc; import android.animation.Animator; import android.animation.AnimatorSet; import android.annotation.FloatRange; +import android.content.res.Resources; import android.graphics.Color; import android.graphics.Rect; import android.graphics.RectF; @@ -26,6 +27,7 @@ import android.graphics.drawable.Drawable; import android.util.ArraySet; import android.util.IntProperty; import android.util.Property; +import android.util.TypedValue; import android.view.View; import android.view.ViewParent; @@ -67,6 +69,8 @@ public class Utilities { public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator(); + public static final Rect EMPTY_RECT = new Rect(); + /** * @return the first parent walking up the view hierarchy that has the given class type. * @@ -232,4 +236,11 @@ public class Utilities { transforms.subList(taskCount, taskTransformCount).clear(); } } + + /** + * Used for debugging, converts DP to PX. + */ + public static float dpToPx(Resources res, float dp) { + return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, res.getDisplayMetrics()); + } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java index 6ae07fc89a5a..196667539fcf 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java @@ -39,7 +39,6 @@ import com.android.systemui.recents.misc.SystemServicesProxy; import java.util.ArrayList; import java.util.Collections; -import java.util.Formatter; import java.util.List; diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java index 193bfffffd9f..12b315ab661e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java +++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java @@ -16,6 +16,16 @@ package com.android.systemui.recents.model; +import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; +import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.view.WindowManager.DOCKED_BOTTOM; +import static android.view.WindowManager.DOCKED_INVALID; +import static android.view.WindowManager.DOCKED_LEFT; +import static android.view.WindowManager.DOCKED_RIGHT; +import static android.view.WindowManager.DOCKED_TOP; + import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; @@ -37,13 +47,13 @@ import android.view.animation.Interpolator; import com.android.internal.policy.DockedDividerUtils; import com.android.systemui.R; import com.android.systemui.recents.Recents; -import com.android.systemui.recents.RecentsConfiguration; import com.android.systemui.recents.RecentsDebugFlags; import com.android.systemui.recents.misc.NamedCounter; import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; -import com.android.systemui.recents.views.DropTarget; import com.android.systemui.recents.views.AnimationProps; +import com.android.systemui.recents.views.DropTarget; +import com.android.systemui.recents.views.TaskStackLayoutAlgorithm; import java.util.ArrayList; import java.util.Collections; @@ -51,16 +61,6 @@ import java.util.Comparator; import java.util.List; import java.util.Random; -import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT; -import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.view.WindowManager.DOCKED_BOTTOM; -import static android.view.WindowManager.DOCKED_INVALID; -import static android.view.WindowManager.DOCKED_LEFT; -import static android.view.WindowManager.DOCKED_RIGHT; -import static android.view.WindowManager.DOCKED_TOP; - /** * An interface for a task filter to query whether a particular task should show in a stack. @@ -375,17 +375,14 @@ public class TaskStack { * {@param height}. */ public Rect getDockedTaskStackBounds(int width, int height, int dividerSize, Rect insets, - Resources res) { - RecentsConfiguration config = Recents.getConfiguration(); - + TaskStackLayoutAlgorithm layoutAlgorithm, Resources res, Rect windowRectOut) { // Calculate the inverse docked task bounds boolean isHorizontalDivision = res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT; int position = DockedDividerUtils.calculateMiddlePosition(isHorizontalDivision, insets, width, height, dividerSize); - Rect newWindowBounds = new Rect(); DockedDividerUtils.calculateBoundsForPosition(position, - DockedDividerUtils.invertDockSide(dockSide), newWindowBounds, width, height, + DockedDividerUtils.invertDockSide(dockSide), windowRectOut, width, height, dividerSize); // Calculate the task stack bounds from the new window bounds @@ -396,7 +393,7 @@ public class TaskStack { int top = dockArea.bottom < 1f ? 0 : insets.top; - config.getTaskStackBounds(newWindowBounds, top, insets.right, + layoutAlgorithm.getTaskStackBounds(windowRectOut, top, insets.right, searchBarSpaceBounds, taskStackBounds); return taskStackBounds; } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java index 72b914c6874e..035c058c7e8d 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/FreeformWorkspaceLayoutAlgorithm.java @@ -46,7 +46,7 @@ public class FreeformWorkspaceLayoutAlgorithm { public void reloadOnConfigurationChange(Context context) { // This is applied to the edges of each task mTaskPadding = context.getResources().getDimensionPixelSize( - R.dimen.recents_freeform_workspace_task_padding) / 2; + R.dimen.recents_freeform_layout_task_padding) / 2; } /** 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 a91bbd4b6d45..29da476db955 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java @@ -16,6 +16,11 @@ package com.android.systemui.recents.views; +import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; +import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; + import android.annotation.Nullable; import android.app.ActivityManager.StackId; import android.app.ActivityOptions; @@ -49,11 +54,6 @@ import com.android.systemui.recents.model.TaskStack; import java.util.ArrayList; import java.util.List; -import static android.app.ActivityManager.StackId.DOCKED_STACK_ID; -import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; - /** * A helper class to create transitions to/from Recents */ 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 db97e8f95b55..d58fa095c464 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java @@ -166,14 +166,17 @@ public class RecentsView extends FrameLayout { } /** Set/get the bsp root node */ - public void onResume(boolean isResumingFromVisible, TaskStack stack) { + public void onResume(boolean isResumingFromVisible, boolean multiWindowChange, + TaskStack stack) { RecentsConfiguration config = Recents.getConfiguration(); RecentsActivityLaunchState launchState = config.getLaunchState(); - if (mTaskStackView == null || !launchState.launchedReuseTaskStackViews) { + if (!multiWindowChange && + (mTaskStackView == null || !launchState.launchedReuseTaskStackViews)) { isResumingFromVisible = false; removeView(mTaskStackView); mTaskStackView = new TaskStackView(getContext()); + mTaskStackView.setSystemInsets(mSystemInsets); mStack = mTaskStackView.getStack(); addView(mTaskStackView); } @@ -185,7 +188,7 @@ public class RecentsView extends FrameLayout { // Update the stack mTaskStackView.onResume(isResumingFromVisible); mTaskStackView.setTasks(stack, isResumingFromVisible /* notifyStackChanges */, - true /* relayoutTaskStack */); + true /* relayoutTaskStack */, multiWindowChange); if (isResumingFromVisible) { // If we are already visible, then restore the background scrim @@ -377,25 +380,20 @@ public class RecentsView extends FrameLayout { */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - RecentsConfiguration config = Recents.getConfiguration(); int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); // Get the search bar bounds and measure the search bar layout - Rect searchBarSpaceBounds = new Rect(); if (mSearchBar != null) { - config.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top, - searchBarSpaceBounds); + Rect searchBarSpaceBounds = new Rect(); + mTaskStackView.getStackAlgorithm().getSearchBarBounds(new Rect(0, 0, width, height), + mSystemInsets.top, searchBarSpaceBounds); mSearchBar.measure( MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY), MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.height(), MeasureSpec.EXACTLY)); } - Rect taskStackBounds = new Rect(); - config.getTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top, - mSystemInsets.right, searchBarSpaceBounds, taskStackBounds); - if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) { - mTaskStackView.setTaskStackBounds(taskStackBounds, mSystemInsets); + if (mTaskStackView.getVisibility() != GONE) { mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec); } @@ -432,19 +430,17 @@ public class RecentsView extends FrameLayout { */ @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - RecentsConfiguration config = Recents.getConfiguration(); - // Get the search bar bounds so that we lay it out Rect measuredRect = new Rect(0, 0, getMeasuredWidth(), getMeasuredHeight()); Rect searchBarSpaceBounds = new Rect(); if (mSearchBar != null) { - config.getSearchBarBounds(measuredRect, - mSystemInsets.top, searchBarSpaceBounds); + mTaskStackView.getStackAlgorithm().getSearchBarBounds(measuredRect, mSystemInsets.top, + searchBarSpaceBounds); mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top, searchBarSpaceBounds.right, searchBarSpaceBounds.bottom); } - if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) { + if (mTaskStackView.getVisibility() != GONE) { mTaskStackView.layout(left, top, left + getMeasuredWidth(), top + getMeasuredHeight()); } @@ -511,6 +507,7 @@ public class RecentsView extends FrameLayout { @Override public WindowInsets onApplyWindowInsets(WindowInsets insets) { mSystemInsets.set(insets.getSystemWindowInsets()); + mTaskStackView.setSystemInsets(mSystemInsets); requestLayout(); return insets; } @@ -733,7 +730,8 @@ public class RecentsView extends FrameLayout { // been applied, we have to set them ourselves initial from the insets that were last // provided. mHistoryView.setSystemInsets(mSystemInsets); - mHistoryView.setHeaderHeight(mHistoryButton.getMeasuredHeight()); + mHistoryView.update(mTaskStackView.getStackAlgorithm(), + mHistoryButton.getMeasuredHeight()); mHistoryButton.bringToFront(); mHistoryClearAllButton.bringToFront(); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java index 19b219a49b2c..6bdaaf96829e 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java @@ -16,11 +16,9 @@ package com.android.systemui.recents.views; -import android.animation.AnimatorListenerAdapter; import android.app.Activity; import android.content.Context; import android.view.View; -import android.view.ViewPropertyAnimator; import com.android.systemui.Interpolators; import com.android.systemui.R; diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java index b36d5d195138..532b6eac13dc 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java @@ -65,6 +65,12 @@ public class TaskStackAnimationHelper { */ void onStartLaunchTargetLaunchAnimation(int duration, boolean screenPinningRequested, ReferenceCountedTrigger postAnimationTrigger); + + /** + * Callback to start the animation for the front {@link TaskView} if there is no launch + * target. + */ + void onStartFrontTaskEnterAnimation(boolean screenPinningEnabled); } private static final int FRAME_OFFSET_MS = 16; @@ -126,9 +132,9 @@ public class TaskStackAnimationHelper { int offscreenYOffset = stackLayout.mStackRect.height(); int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize( - R.dimen.recents_task_view_affiliate_group_enter_offset); + R.dimen.recents_task_stack_animation_affiliate_enter_offset); int launchedWhileDockingOffset = res.getDimensionPixelSize( - R.dimen.recents_task_view_launched_while_docking_offset); + R.dimen.recents_task_stack_animation_launched_while_docking_offset); // Prepare each of the task views for their enter animation from front to back List<TaskView> taskViews = mStackView.getTaskViews(); @@ -164,6 +170,7 @@ public class TaskStackAnimationHelper { // Move the task view off screen (below) so we can animate it in RectF bounds = new RectF(mTmpTransform.rect); bounds.offset(0, offscreenYOffset); + tv.setAlpha(0f); tv.setLeftTopRightBottom((int) bounds.left, (int) bounds.top, (int) bounds.right, (int) bounds.bottom); } else if (launchState.launchedWhileDocking) { @@ -232,7 +239,7 @@ public class TaskStackAnimationHelper { @Override public void onAnimationEnd(Animator animation) { postAnimationTrigger.decrement(); - tv.setClipViewInStack(false); + tv.setClipViewInStack(true); } }); postAnimationTrigger.increment(); @@ -254,6 +261,9 @@ public class TaskStackAnimationHelper { .setListener(postAnimationTrigger.decrementOnAnimationEnd()); postAnimationTrigger.increment(); mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); + if (i == taskViewCount - 1) { + tv.onStartFrontTaskEnterAnimation(mStackView.mScreenPinningEnabled); + } } else if (launchState.launchedWhileDocking) { // Animate the tasks up AnimationProps taskAnimation = new AnimationProps() @@ -312,6 +322,7 @@ public class TaskStackAnimationHelper { stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, null); + mTmpTransform.alpha = 0f; mTmpTransform.rect.offset(0, offscreenYOffset); mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation); } @@ -330,7 +341,7 @@ public class TaskStackAnimationHelper { int taskViewExitToAppDuration = res.getInteger( R.integer.recents_task_exit_to_app_duration); int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize( - R.dimen.recents_task_view_affiliate_group_enter_offset); + R.dimen.recents_task_stack_animation_affiliate_enter_offset); Task launchingTask = launchingTaskView.getTask(); List<TaskView> taskViews = mStackView.getTaskViews(); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java index 6df5884328b3..c34d093522c9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -16,7 +16,9 @@ package com.android.systemui.recents.views; +import android.annotation.IntDef; import android.content.Context; +import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Path; import android.graphics.Rect; @@ -36,6 +38,8 @@ import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.List; @@ -97,8 +101,10 @@ class Range { } /** - * The layout logic for a TaskStackView. This layout can have two states focused and unfocused, - * and in the focused state, there is a task that is displayed more prominently in the stack. + * The layout logic for a TaskStackView. This layout needs to be able to calculate the stack layout + * without an activity-specific context only with the information passed in. This layout can have + * two states focused and unfocused, and in the focused state, there is a task that is displayed + * more prominently in the stack. */ public class TaskStackLayoutAlgorithm { @@ -107,13 +113,28 @@ public class TaskStackLayoutAlgorithm { public static final float OUTLINE_ALPHA_MIN_VALUE = 0f; public static final float OUTLINE_ALPHA_MAX_VALUE = 2f; - // The maximum dim on the tasks + // The medium/maximum dim on the tasks + private static final float MED_DIM = 0.15f; private static final float MAX_DIM = 0.25f; // The various focus states public static final int STATE_FOCUSED = 1; public static final int STATE_UNFOCUSED = 0; + // The side that an offset is anchored + @Retention(RetentionPolicy.SOURCE) + @IntDef({FROM_TOP, FROM_BOTTOM}) + public @interface AnchorSide {} + private static final int FROM_TOP = 0; + private static final int FROM_BOTTOM = 1; + + // The extent that we care about when calculating fractions + @Retention(RetentionPolicy.SOURCE) + @IntDef({WIDTH, HEIGHT}) + public @interface Extent {} + private static final int WIDTH = 0; + private static final int HEIGHT = 1; + public interface TaskStackLayoutAlgorithmCallbacks { void onFocusStateChanged(int prevFocusState, int curFocusState); } @@ -165,22 +186,24 @@ public class TaskStackLayoutAlgorithm { * @param taskStackBounds the full rect that the freeform rect can take up */ public void computeRects(Rect freeformRectOut, Rect stackRectOut, - Rect taskStackBounds, int widthPadding, int heightPadding, int stackBottomOffset) { - int availableHeight = taskStackBounds.height() - stackBottomOffset; + Rect taskStackBounds, int topMargin, int freeformGap, int stackBottomOffset) { + // The freeform height is the visible height (not including system insets) - padding + // above freeform and below stack - gap between the freeform and stack + int availableHeight = taskStackBounds.height() - topMargin - stackBottomOffset; int ffPaddedHeight = (int) (availableHeight * freeformHeightPct); - int ffHeight = Math.max(0, ffPaddedHeight - (2 * heightPadding)); - freeformRectOut.set(taskStackBounds.left + widthPadding, - taskStackBounds.top + heightPadding, - taskStackBounds.right - widthPadding, - taskStackBounds.top + heightPadding + ffHeight); - stackRectOut.set(taskStackBounds.left + widthPadding, + int ffHeight = Math.max(0, ffPaddedHeight - freeformGap); + freeformRectOut.set(taskStackBounds.left, + taskStackBounds.top + topMargin, + taskStackBounds.right, + taskStackBounds.top + topMargin + ffHeight); + stackRectOut.set(taskStackBounds.left, taskStackBounds.top, - taskStackBounds.right - widthPadding, + taskStackBounds.right, taskStackBounds.bottom); if (ffPaddedHeight > 0) { stackRectOut.top += ffPaddedHeight; } else { - stackRectOut.top += heightPadding; + stackRectOut.top += topMargin; } } } @@ -222,26 +245,38 @@ public class TaskStackLayoutAlgorithm { private Range mUnfocusedRange; private Range mFocusedRange; - // The initial offset from the top and bottom of the stack + // The base top margin for the stack from the system insets @ViewDebug.ExportedProperty(category="recents") - private int mInitialTopPeekHeight; + private int mBaseTopMargin; + // The base side margin for the stack from the system insets @ViewDebug.ExportedProperty(category="recents") - private int mInitialBottomPeekHeight; - - // The offset from the top when scrolled to the top of the stack + private int mBaseSideMargin; + // The base bottom margin for the stack from the system insets @ViewDebug.ExportedProperty(category="recents") - private int mFocusedTopPeekHeight; + private int mBaseBottomMargin; + private int mMinMargin; + // The height of the search bar @ViewDebug.ExportedProperty(category="recents") - private int mFocusedBottomTaskPeekHeight; + private int mSearchBarHeight; + // The gap between the freeform and stack layouts + @ViewDebug.ExportedProperty(category="recents") + private int mFreeformStackGap; - // The offset from the top of the stack to the top of the bounds when the stack is scrolled to - // the end + // The initial offset that the focused task is from the top + @ViewDebug.ExportedProperty(category="recents") + private int mInitialTopOffset; + private int mBaseInitialTopOffset; + // The initial offset that the launch-from task is from the bottom @ViewDebug.ExportedProperty(category="recents") - private int mStackTopOffset; + private int mInitialBottomOffset; + private int mBaseInitialBottomOffset; - // The height of the header bar + // The height between the top margin and the top of the focused task + @ViewDebug.ExportedProperty(category="recents") + private int mFocusedTopPeekHeight; + // The height between the bottom margin and the top of task in front of the focused task @ViewDebug.ExportedProperty(category="recents") - private int mHeaderBarHeight; + private int mFocusedBottomPeekHeight; // The offset from the bottom of the stack to the bottom of the bounds when the stack is // scrolled to the front @@ -307,9 +342,27 @@ public class TaskStackLayoutAlgorithm { TaskViewTransform mFrontOfStackTransform = new TaskViewTransform(); public TaskStackLayoutAlgorithm(Context context, TaskStackLayoutAlgorithmCallbacks cb) { + Resources res = context.getResources(); mContext = context; mCb = cb; mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context); + mMinMargin = res.getDimensionPixelSize(R.dimen.recents_layout_min_margin); + mBaseTopMargin = getDimensionForDevice(res, + R.dimen.recents_layout_top_margin_phone, + R.dimen.recents_layout_top_margin_tablet, + R.dimen.recents_layout_top_margin_tablet_xlarge); + mBaseSideMargin = getDimensionForDevice(res, + R.dimen.recents_layout_side_margin_phone, + R.dimen.recents_layout_side_margin_tablet, + R.dimen.recents_layout_side_margin_tablet_xlarge); + mBaseBottomMargin = res.getDimensionPixelSize(R.dimen.recents_layout_bottom_margin); + mSearchBarHeight = getDimensionForDevice(res, + R.dimen.recents_layout_search_bar_height_phone, + R.dimen.recents_layout_search_bar_height_tablet, + R.dimen.recents_layout_search_bar_height_tablet); + mFreeformStackGap = + res.getDimensionPixelSize(R.dimen.recents_freeform_layout_bottom_margin); + reloadOnConfigurationChange(context); } @@ -323,17 +376,25 @@ public class TaskStackLayoutAlgorithm { mUnfocusedRange = new Range(res.getFloat(R.integer.recents_layout_unfocused_range_min), res.getFloat(R.integer.recents_layout_unfocused_range_max)); mFocusState = getInitialFocusState(); - mInitialTopPeekHeight = res.getDimensionPixelSize(R.dimen.recents_initial_top_peek_size); - mInitialBottomPeekHeight = - res.getDimensionPixelSize(R.dimen.recents_initial_bottom_peek_size); - mFocusedTopPeekHeight = - res.getDimensionPixelSize(R.dimen.recents_layout_focused_top_peek_size); - mFocusedBottomTaskPeekHeight = - res.getDimensionPixelSize(R.dimen.recents_layout_focused_bottom_task_peek_size); - mHeaderBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height); - - mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min); - mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max); + mFocusedTopPeekHeight = res.getDimensionPixelSize(R.dimen.recents_layout_top_peek_size); + mFocusedBottomPeekHeight = + res.getDimensionPixelSize(R.dimen.recents_layout_bottom_peek_size); + mMinTranslationZ = res.getDimensionPixelSize(R.dimen.recents_layout_z_min); + mMaxTranslationZ = res.getDimensionPixelSize(R.dimen.recents_layout_z_max); + mBaseInitialTopOffset = getDimensionForDevice(res, + R.dimen.recents_layout_initial_top_offset_phone_port, + R.dimen.recents_layout_initial_top_offset_phone_land, + R.dimen.recents_layout_initial_top_offset_tablet, + R.dimen.recents_layout_initial_top_offset_tablet, + R.dimen.recents_layout_initial_top_offset_tablet, + R.dimen.recents_layout_initial_top_offset_tablet); + mBaseInitialBottomOffset = getDimensionForDevice(res, + R.dimen.recents_layout_initial_bottom_offset_phone_port, + R.dimen.recents_layout_initial_bottom_offset_phone_land, + R.dimen.recents_layout_initial_bottom_offset_tablet, + R.dimen.recents_layout_initial_bottom_offset_tablet, + R.dimen.recents_layout_initial_bottom_offset_tablet, + R.dimen.recents_layout_initial_bottom_offset_tablet); mFreeformLayoutAlgorithm.reloadOnConfigurationChange(context); } @@ -372,52 +433,52 @@ public class TaskStackLayoutAlgorithm { } /** - * Computes the stack and task rects. The given task stack bounds is the whole bounds not - * including the search bar. + * Computes the stack and task rects. The given task stack bounds already has the top/right + * insets and left/right padding already applied. */ - public void initialize(Rect taskStackBounds, StackState state) { - RecentsConfiguration config = Recents.getConfiguration(); - int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width()); - int heightPadding = mContext.getResources().getDimensionPixelSize( - R.dimen.recents_stack_top_padding); + public void initialize(Rect windowRect, Rect taskStackBounds, StackState state) { + SystemServicesProxy ssp = Recents.getSystemServices(); Rect lastStackRect = new Rect(mStackRect); + Rect displayRect = ssp.getDisplayRect(); - // The freeform height is the visible height (not including system insets) - padding above - // freeform and below stack - gap between the freeform and stack + int topMargin = getScaleForExtent(windowRect, displayRect, mBaseTopMargin, mMinMargin, HEIGHT); + int bottomMargin = getScaleForExtent(windowRect, displayRect, mBaseBottomMargin, mMinMargin, + HEIGHT); + mInitialTopOffset = getScaleForExtent(windowRect, displayRect, mBaseInitialTopOffset, + mMinMargin, HEIGHT); + mInitialBottomOffset = mBaseInitialBottomOffset; + + // Compute the stack bounds mState = state; - mStackTopOffset = mFocusedTopPeekHeight + heightPadding; - mStackBottomOffset = mSystemInsets.bottom + heightPadding; - state.computeRects(mFreeformRect, mStackRect, taskStackBounds, widthPadding, heightPadding, - mStackBottomOffset); + mStackBottomOffset = mSystemInsets.bottom + bottomMargin; + state.computeRects(mFreeformRect, mStackRect, taskStackBounds, topMargin, + mFreeformStackGap, mStackBottomOffset); + // The history button will take the full un-padded header space above the stack - mHistoryButtonRect.set(mStackRect.left, mStackRect.top - heightPadding, + mHistoryButtonRect.set(mStackRect.left, mStackRect.top - topMargin, mStackRect.right, mStackRect.top + mFocusedTopPeekHeight); - // Anchor the task rect to the top-center of the non-freeform stack rect - float aspect = (float) (taskStackBounds.width() - mSystemInsets.left - mSystemInsets.right) - / (taskStackBounds.height() - mSystemInsets.bottom); - int width = mStackRect.width(); - int minHeight = mStackRect.height() - mFocusedTopPeekHeight - mStackBottomOffset; - int height = (int) Math.min(width / aspect, minHeight); - mTaskRect.set(mStackRect.left, mStackRect.top, - mStackRect.left + width, mStackRect.top + height); + // Anchor the task rect top aligned to the non-freeform stack rect + float aspect = (float) (windowRect.width() - (mSystemInsets.left + mSystemInsets.right)) / + (windowRect.height() - (mSystemInsets.top + mSystemInsets.bottom)); + int minHeight = mStackRect.height() - mInitialTopOffset - mStackBottomOffset; + int height = (int) Math.min(mStackRect.width() / aspect, minHeight); + mTaskRect.set(mStackRect.left, mStackRect.top, mStackRect.right, mStackRect.top + height); // Short circuit here if the stack rects haven't changed so we don't do all the work below - if (lastStackRect.equals(mStackRect)) { - return; + if (!lastStackRect.equals(mStackRect)) { + // Reinitialize the focused and unfocused curves + mUnfocusedCurve = constructUnfocusedCurve(); + mUnfocusedCurveInterpolator = new FreePathInterpolator(mUnfocusedCurve); + mFocusedCurve = constructFocusedCurve(); + mFocusedCurveInterpolator = new FreePathInterpolator(mFocusedCurve); + mUnfocusedDimCurve = constructUnfocusedDimCurve(); + mUnfocusedDimCurveInterpolator = new FreePathInterpolator(mUnfocusedDimCurve); + mFocusedDimCurve = constructFocusedDimCurve(); + mFocusedDimCurveInterpolator = new FreePathInterpolator(mFocusedDimCurve); + + updateFrontBackTransforms(); } - - // Reinitialize the focused and unfocused curves - mUnfocusedCurve = constructUnfocusedCurve(); - mUnfocusedCurveInterpolator = new FreePathInterpolator(mUnfocusedCurve); - mFocusedCurve = constructFocusedCurve(); - mFocusedCurveInterpolator = new FreePathInterpolator(mFocusedCurve); - mUnfocusedDimCurve = constructUnfocusedDimCurve(); - mUnfocusedDimCurveInterpolator = new FreePathInterpolator(mUnfocusedDimCurve); - mFocusedDimCurve = constructFocusedDimCurve(); - mFocusedDimCurveInterpolator = new FreePathInterpolator(mFocusedDimCurve); - - updateFrontBackTransforms(); } /** @@ -435,7 +496,7 @@ public class TaskStackLayoutAlgorithm { ArrayList<Task> tasks = stack.getStackTasks(); if (tasks.isEmpty()) { mFrontMostTaskP = 0; - mMinScrollP = mMaxScrollP = 0; + mMinScrollP = mMaxScrollP = mInitialScrollP = 0; mNumStackTasks = mNumFreeformTasks = 0; return; } @@ -492,8 +553,7 @@ public class TaskStackLayoutAlgorithm { // Set the max scroll to be the point where the front most task is visible with the // stack bottom offset int maxBottomOffset = mStackBottomOffset + mTaskRect.height(); - float maxBottomOffsetPct = (float) maxBottomOffset / mStackRect.height(); - float maxBottomNormX = mUnfocusedCurveInterpolator.getX(maxBottomOffsetPct); + float maxBottomNormX = getNormalizedXFromUnfocusedY(maxBottomOffset, FROM_BOTTOM); mUnfocusedRange.offset(0f); mMinScrollP = 0; mMaxScrollP = Math.max(mMinScrollP, (mNumStackTasks - 1) - @@ -502,34 +562,19 @@ public class TaskStackLayoutAlgorithm { launchState.launchedFromAppDocked; if (scrollToFront) { mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP); + mInitialNormX = null; } else { - mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP); + float normX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP); + mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, (mNumStackTasks - 2)) - + Math.max(0, mUnfocusedRange.getAbsoluteX(normX))); + + // Set the initial scroll to the predefined state (which differs from the stack) + mInitialNormX = new float[] { + getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset, + FROM_BOTTOM), + normX + }; } - - // Set the initial scroll to the predefined state (which differs from the stack) - int initialPeekOffset = mStackRect.height() - mInitialTopPeekHeight; - float initialPeekOffsetPct = (float) initialPeekOffset / mStackRect.height(); - float initialPeekOffsetNormX = mUnfocusedCurveInterpolator.getX(initialPeekOffsetPct); - float initialFocusedOffset = mStackRect.height() - mInitialTopPeekHeight - - (mHeaderBarHeight * 1f) + 1; - float initialFocusedOffsetPct = initialFocusedOffset / mStackRect.height(); - float initialFocusedNormX = mUnfocusedCurveInterpolator.getX(initialFocusedOffsetPct); - float initialBottomOffset = mStackBottomOffset + - (ssp.hasDockedTask() - ? mHeaderBarHeight - : mInitialBottomPeekHeight); - float initialBottomOffsetPct = initialBottomOffset / mStackRect.height(); - float initialBottomNormX = mUnfocusedCurveInterpolator.getX(initialBottomOffsetPct); - /* - // If we want to offset the top card slightly - mInitialNormX = scrollToFront - ? new float[] { initialFocusedNormX, initialPeekOffsetNormX, 0f } - : new float[] { initialBottomNormX, initialFocusedNormX, - initialPeekOffsetNormX, 0f }; - */ - mInitialNormX = scrollToFront - ? new float[] { initialFocusedNormX, initialPeekOffsetNormX, 0f } - : new float[] { initialBottomNormX, 0.5f, 0f }; } } @@ -669,7 +714,7 @@ public class TaskStackLayoutAlgorithm { Range currentRange = getInitialFocusState() > 0f ? mFocusedRange : mUnfocusedRange; currentRange.offset(mInitialScrollP); int taskBarHeight = mContext.getResources().getDimensionPixelSize( - R.dimen.recents_task_bar_height); + R.dimen.recents_task_view_header_height); int numVisibleTasks = Math.max(mNumFreeformTasks, 1); int numVisibleThumbnails = Math.max(mNumFreeformTasks, 1); float prevScreenY = Integer.MAX_VALUE; @@ -869,6 +914,25 @@ public class TaskStackLayoutAlgorithm { } /** + * Returns the original scroll progress to scroll to such that the top of the task is at the top + * of the stack. + */ + float getStackScrollForTaskIgnoreOverrides(Task t) { + return (float) mTaskIndexMap.get(t.key.id, 0); + } + + /** + * Returns the scroll progress to scroll to such that the top of the task at the initial top + * offset (which is at the task's brightest point). + */ + float getStackScrollForTaskAtInitialOffset(Task t) { + float normX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP); + mUnfocusedRange.offset(0f); + return (float) mTaskIndexMap.get(t.key.id, 0) - Math.max(0, + mUnfocusedRange.getAbsoluteX(normX)); + } + + /** * Maps a movement in screen y, relative to {@param downY}, to a movement in along the arc * length of the curve. We know the curve is mostly flat, so we just map the length of the * screen along the arc-length proportionally (1/arclength). @@ -890,6 +954,95 @@ public class TaskStackLayoutAlgorithm { } /** + * Returns the task stack bounds in the current orientation. This rect takes into account the + * top and right system insets (but not the bottom inset) and left/right paddings, but _not_ + * the top/bottom padding or insets. + */ + public void getTaskStackBounds(Rect windowRect, int topInset, int rightInset, + Rect searchBarBounds, Rect taskStackBounds) { + RecentsConfiguration config = Recents.getConfiguration(); + if (config.hasTransposedNavBar) { + taskStackBounds.set(windowRect.left, windowRect.top + topInset, + windowRect.right - rightInset, windowRect.bottom); + } else { + // In portrait, the search bar appears on the top (which already has the inset) + int top = searchBarBounds.isEmpty() ? topInset : 0; + taskStackBounds.set(windowRect.left, windowRect.top + searchBarBounds.bottom + top, + windowRect.right - rightInset, windowRect.bottom); + } + + // Ensure that the new width is at most the smaller display edge size + Rect displayRect = Recents.getSystemServices().getDisplayRect(); + int sideMargin = getScaleForExtent(windowRect, displayRect, mBaseSideMargin, mMinMargin, + WIDTH); + int targetStackWidth = Math.min(taskStackBounds.width() - 2 * sideMargin, + Math.min(displayRect.width(), displayRect.height())); + taskStackBounds.inset((taskStackBounds.width() - targetStackWidth) / 2, 0); + } + + /** + * Returns the search bar bounds in the current orientation. These bounds do not account for + * the system insets. + */ + public void getSearchBarBounds(Rect windowBounds, int topInset, Rect searchBarSpaceBounds) { + RecentsConfiguration config = Recents.getConfiguration(); + if (config.hasTransposedSearchBar) { + // In landscape phones, the search bar appears on the left + searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset, + windowBounds.left + mSearchBarHeight, windowBounds.bottom); + } else { + // In portrait, the search bar appears on the top + searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset, + windowBounds.right, windowBounds.top + topInset + mSearchBarHeight); + } + } + + /** + * Retrieves resources that are constant regardless of the current configuration of the device. + */ + public static int getDimensionForDevice(Resources res, int phoneResId, + int tabletResId, int xlargeTabletResId) { + return getDimensionForDevice(res, phoneResId, phoneResId, tabletResId, tabletResId, + xlargeTabletResId, xlargeTabletResId); + } + + /** + * Retrieves resources that are constant regardless of the current configuration of the device. + */ + public static int getDimensionForDevice(Resources res, int phonePortResId, int phoneLandResId, + int tabletPortResId, int tabletLandResId, int xlargeTabletPortResId, + int xlargeTabletLandResId) { + RecentsConfiguration config = Recents.getConfiguration(); + boolean isLandscape = Recents.getSystemServices().getDisplayOrientation() == + Configuration.ORIENTATION_LANDSCAPE; + if (config.isXLargeScreen) { + return res.getDimensionPixelSize(isLandscape + ? xlargeTabletLandResId + : xlargeTabletPortResId); + } else if (config.isLargeScreen) { + return res.getDimensionPixelSize(isLandscape + ? tabletLandResId + : tabletPortResId); + } else { + return res.getDimensionPixelSize(isLandscape + ? phoneLandResId + : phonePortResId); + } + } + + /** + * Returns the normalized x on the unfocused curve given an absolute Y position (relative to the + * stack height). + */ + private float getNormalizedXFromUnfocusedY(float y, @AnchorSide int fromSide) { + float offset = (fromSide == FROM_TOP) + ? mStackRect.height() - y + : y; + float offsetPct = offset / mStackRect.height(); + return mUnfocusedCurveInterpolator.getX(offsetPct); + } + + /** * Creates a new path for the focused curve. */ private Path constructFocusedCurve() { @@ -897,13 +1050,12 @@ public class TaskStackLayoutAlgorithm { // linear pieces that goes from (0,1) through (0.5, peek height offset), // (0.5, bottom task offsets), and (1,0). float topPeekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height(); - float bottomPeekHeightPct = Math.max( - mSystemInsets.bottom + mFocusedRange.relativeMax * mFocusedBottomTaskPeekHeight, - mStackBottomOffset + mFocusedBottomTaskPeekHeight) / mStackRect.height(); + float bottomPeekHeightPct = (float) (mStackBottomOffset + mFocusedBottomPeekHeight) / + mStackRect.height(); Path p = new Path(); p.moveTo(0f, 1f); p.lineTo(0.5f, 1f - topPeekHeightPct); - p.lineTo(0.5f + (0.5f / mFocusedRange.relativeMax), bottomPeekHeightPct); + p.lineTo(1f - (0.5f / mFocusedRange.relativeMax), bottomPeekHeightPct); p.lineTo(1f, 0f); return p; } @@ -919,16 +1071,16 @@ public class TaskStackLayoutAlgorithm { // the control point of the second bezier such that between it and a first known point, // there is a tangent at (0.5, peek height offset). float cpoint1X = 0.4f; - float cpoint1Y = 1f; - float peekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height(); - float slope = ((1f - peekHeightPct) - cpoint1Y) / (0.5f - cpoint1X); + float cpoint1Y = 0.975f; + float topPeekHeightPct = (float) mFocusedTopPeekHeight / mStackRect.height(); + float slope = ((1f - topPeekHeightPct) - cpoint1Y) / (0.5f - cpoint1X); float b = 1f - slope * cpoint1X; float cpoint2X = 0.65f; float cpoint2Y = slope * cpoint2X + b; Path p = new Path(); p.moveTo(0f, 1f); - p.cubicTo(0f, 1f, cpoint1X, cpoint1Y, 0.5f, 1f - peekHeightPct); - p.cubicTo(0.5f, 1f - peekHeightPct, cpoint2X, cpoint2Y, 1f, 0f); + p.cubicTo(0f, 1f, cpoint1X, cpoint1Y, 0.5f, 1f - topPeekHeightPct); + p.cubicTo(0.5f, 1f - topPeekHeightPct, cpoint2X, cpoint2Y, 1f, 0f); return p; } @@ -950,15 +1102,30 @@ public class TaskStackLayoutAlgorithm { * Creates a new path for the unfocused dim curve. */ private Path constructUnfocusedDimCurve() { + float focusX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP); + float cpoint2X = focusX + (1f - focusX) / 2; Path p = new Path(); // The unfocused dim interpolator starts at max dim, reduces to zero at 0.5 (the focused // task), then goes back to max dim towards the front of the stack p.moveTo(0f, MAX_DIM); - p.cubicTo(0.1f, MAX_DIM, 0.4f, 0.0f, 0.5f, 0f); - p.cubicTo(0.6f, 0f, 0.9f, MAX_DIM / 2f, 1f, MAX_DIM / 2f); + p.cubicTo(focusX * 0.5f, MAX_DIM, focusX * 0.75f, MAX_DIM * 0.75f, focusX, 0f); + p.cubicTo(cpoint2X, 0f, cpoint2X, MED_DIM, 1f, MED_DIM); return p; } + /** + * Scales the given {@param value} to the scale of the {@param instance} rect relative to the + * {@param other} rect in the {@param extent} side. + */ + private int getScaleForExtent(Rect instance, Rect other, int value, int minValue, + @Extent int extent) { + if (extent == WIDTH) { + return Math.max(minValue, (int) (((float) instance.width() / other.width()) * value)); + } else if (extent == HEIGHT) { + return Math.max(minValue, (int) (((float) instance.height() / other.height()) * value)); + } + return value; + } /** * Updates the current transforms that would put a TaskView at the front and back of the stack. diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 0b20d21d806c..4cd296d034eb 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -165,11 +165,18 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // The current stack bounds are dynamic and may change as the user drags and drops @ViewDebug.ExportedProperty(category="recents") private Rect mStackBounds = new Rect(); + // The current window bounds at the point we were measured + @ViewDebug.ExportedProperty(category="recents") + private Rect mStableWindowRect = new Rect(); + // The current window bounds are dynamic and may change as the user drags and drops + @ViewDebug.ExportedProperty(category="recents") + private Rect mWindowRect = new Rect(); private Rect mTmpRect = new Rect(); private ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>(); private List<TaskView> mTmpTaskViews = new ArrayList<>(); private TaskViewTransform mTmpTransform = new TaskViewTransform(); + private ArrayList<TaskViewTransform> mTmpTaskTransforms = new ArrayList<>(); private int[] mTmpIntPair = new int[2]; // A convenience update listener to request updating clipping of tasks @@ -302,7 +309,8 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal /** * Sets the stack tasks of this TaskStackView from the given TaskStack. */ - public void setTasks(TaskStack stack, boolean notifyStackChanges, boolean relayoutTaskStack) { + public void setTasks(TaskStack stack, boolean notifyStackChanges, boolean relayoutTaskStack, + boolean multiWindowChange) { boolean isInitialized = mLayoutAlgorithm.isInitialized(); mStack.setTasks(getContext(), stack.computeAllTasksList(), notifyStackChanges && isInitialized); @@ -310,7 +318,9 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Only update the layout if we are notifying, otherwise, we will update it in the next // measure/layout pass updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET); - updateToInitialState(); + if (!multiWindowChange) { + updateToInitialState(); + } if (relayoutTaskStack) { relayoutTaskViews(AnimationProps.IMMEDIATE); @@ -622,15 +632,17 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } /** - * Relayout the the visible {@link TaskView}s to their current transforms as specified by the - * {@link TaskStackLayoutAlgorithm} with the given {@param animation}. This call cancels any - * animations that are current running on those task views, and will ensure that the children - * {@link TaskView}s will match the set of visible tasks in the stack. - * - * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>) + * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean) */ void relayoutTaskViews(AnimationProps animation) { - relayoutTaskViews(animation, mIgnoreTasks); + relayoutTaskViews(animation, mIgnoreTasks, false /* ignoreTaskOverrides */); + } + + /** + * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean) + */ + void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet) { + relayoutTaskViews(animation, ignoreTasksSet, false /* ignoreTaskOverrides */); } /** @@ -641,13 +653,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal * * @param ignoreTasksSet the set of tasks to ignore in the relayout */ - void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet) { + void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet, + boolean ignoreTaskOverrides) { // If we had a deferred animation, cancel that mDeferredTaskViewLayoutAnimation = null; // Synchronize the current set of TaskViews bindVisibleTaskViews(mStackScroller.getStackScroll(), ignoreTasksSet, - false /* ignoreTaskOverrides */); + ignoreTaskOverrides /* ignoreTaskOverrides */); // Animate them to their final transforms with the given animation List<TaskView> taskViews = getTaskViews(); @@ -1059,8 +1072,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal event.setContentDescription(frontMostTask.getTask().title); } event.setItemCount(mStack.getTaskCount()); - event.setScrollY(mStackScroller.mScroller.getCurrY()); - event.setMaxScrollY(mStackScroller.progressToScrollRange(mLayoutAlgorithm.mMaxScrollP)); + + int stackHeight = mLayoutAlgorithm.mStackRect.height(); + event.setScrollY((int) (mStackScroller.getStackScroll() * stackHeight)); + event.setMaxScrollY((int) (mLayoutAlgorithm.mMaxScrollP * stackHeight)); } @Override @@ -1161,23 +1176,11 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } /** - * Updates the expected task stack bounds for this stack view. + * Updates the system insets. */ - public void setTaskStackBounds(Rect taskStackBounds, Rect systemInsets) { - // We can get spurious measure passes with the old bounds when docking, and since we are - // using the current stack bounds during drag and drop, don't overwrite them until we - // actually get new bounds - boolean requiresLayout = false; - if (!taskStackBounds.equals(mStableStackBounds)) { - mStableStackBounds.set(taskStackBounds); - mStackBounds.set(taskStackBounds); - requiresLayout = true; - } + public void setSystemInsets(Rect systemInsets) { if (!systemInsets.equals(mLayoutAlgorithm.mSystemInsets)) { mLayoutAlgorithm.setSystemInsets(systemInsets); - requiresLayout = true; - } - if (requiresLayout) { requestLayout(); } } @@ -1192,8 +1195,21 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal int width = MeasureSpec.getSize(widthMeasureSpec); int height = MeasureSpec.getSize(heightMeasureSpec); + // Update the stable stack bounds, but only update the current stack bounds if the stable + // bounds have changed. This is because we may get spurious measures while dragging where + // our current stack bounds reflect the target drop region. + mLayoutAlgorithm.getTaskStackBounds(new Rect(0, 0, width, height), + mLayoutAlgorithm.mSystemInsets.top, mLayoutAlgorithm.mSystemInsets.right, + Utilities.EMPTY_RECT, mTmpRect); + if (!mTmpRect.equals(mStableStackBounds)) { + mStableStackBounds.set(mTmpRect); + mStackBounds.set(mTmpRect); + mStableWindowRect.set(0, 0, width, height); + mWindowRect.set(0, 0, width, height); + } + // Compute the rects in the stack algorithm - mLayoutAlgorithm.initialize(mStackBounds, + mLayoutAlgorithm.initialize(mWindowRect, mStackBounds, TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack)); updateLayoutAlgorithm(false /* boundScroll */, EMPTY_TASK_SET); @@ -1282,6 +1298,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal mTmpRect.setEmpty(); } Rect taskRect = mLayoutAlgorithm.mTaskRect; + tv.cancelTransformAnimation(); tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top, taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom); } @@ -1757,32 +1774,38 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public final void onBusEvent(DragDropTargetChangedEvent event) { AnimationProps animation = new AnimationProps(250, Interpolators.FAST_OUT_SLOW_IN); + boolean ignoreTaskOverrides = false; if (event.dropTarget instanceof TaskStack.DockState) { // Calculate the new task stack bounds that matches the window size that Recents will // have after the drop final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; mStackBounds.set(dockState.getDockedTaskStackBounds(getMeasuredWidth(), getMeasuredHeight(), mDividerSize, mLayoutAlgorithm.mSystemInsets, - getResources())); - mLayoutAlgorithm.initialize(mStackBounds, + mLayoutAlgorithm, getResources(), mWindowRect)); + mLayoutAlgorithm.initialize(mWindowRect, mStackBounds, TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack)); updateLayoutAlgorithm(true /* boundScroll */); + ignoreTaskOverrides = true; } else { // Restore the pre-drag task stack bounds, but ensure that we don't layout the dragging // task view, so add it back to the ignore set after updating the layout + mWindowRect.set(mStableWindowRect); mStackBounds.set(mStableStackBounds); removeIgnoreTask(event.task); - mLayoutAlgorithm.initialize(mStackBounds, + mLayoutAlgorithm.initialize(mWindowRect, mStackBounds, TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack)); updateLayoutAlgorithm(true /* boundScroll */); addIgnoreTask(event.task); } - relayoutTaskViews(animation); + relayoutTaskViews(animation, mIgnoreTasks, ignoreTaskOverrides); } public final void onBusEvent(final DragEndEvent event) { // We don't handle drops on the dock regions if (event.dropTarget instanceof TaskStack.DockState) { + // However, we do need to reset the overrides, since the last state of this task stack + // view layout was ignoring task overrides (see DragDropTargetChangedEvent handler) + mLayoutAlgorithm.clearUnfocusedTaskOverrides(); return; } @@ -1924,7 +1947,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal public final void onBusEvent(ConfigurationChangedEvent event) { mLayoutAlgorithm.reloadOnConfigurationChange(getContext()); - mLayoutAlgorithm.initialize(mStackBounds, + mLayoutAlgorithm.initialize(mWindowRect, mStackBounds, TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack)); } diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java index 9be3542bf59e..583fb88e4069 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java @@ -28,8 +28,6 @@ import android.widget.OverScroller; import com.android.systemui.Interpolators; import com.android.systemui.R; -import com.android.systemui.recents.Recents; -import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; /* The scrolling logic for a TaskStackView */ @@ -189,7 +187,7 @@ public class TaskStackViewScroller { // Finish any current scrolling animations if (mScrollAnimator != null && mScrollAnimator.isRunning()) { setStackScroll(mFinalAnimatedScroll); - mScroller.startScroll(0, progressToScrollRange(mFinalAnimatedScroll), 0, 0, 0); + mScroller.forceFinished(true); } stopScroller(); stopBoundScrollAnimation(); @@ -223,12 +221,6 @@ public class TaskStackViewScroller { /**** OverScroller ****/ - // TODO: Remove - @Deprecated - int progressToScrollRange(float p) { - return (int) (p * mLayoutAlgorithm.mStackRect.height()); - } - /** Called from the view draw, computes the next scroll. */ boolean computeScroll() { if (mScroller.computeScrollOffset()) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index 863591124ff7..e7acc07b76be 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -121,7 +121,7 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { mScrollTouchSlop = configuration.getScaledTouchSlop(); mWindowTouchSlop = configuration.getScaledWindowTouchSlop(); mFlingAnimUtils = new FlingAnimationUtils(context, 0.2f); - mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_stack_overscroll); + mOverscrollSize = res.getDimensionPixelSize(R.dimen.recents_fling_overscroll_distance); mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, context) { @Override protected float getSize(View v) { @@ -458,7 +458,8 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { newStackScroll = stackScroller.getBoundedStackScroll(newStackScroll); } else if (pullStackForward) { // Otherwise, offset the scroll by the movement of the anchor task - float anchorTaskScroll = layoutAlgorithm.getStackScrollForTask(anchorTask); + float anchorTaskScroll = + layoutAlgorithm.getStackScrollForTaskIgnoreOverrides(anchorTask); float stackScrollOffset = (anchorTaskScroll - prevAnchorTaskScroll); if (layoutAlgorithm.getFocusState() != TaskStackLayoutAlgorithm.STATE_FOCUSED) { // If we are focused, we don't want the front task to move, but otherwise, we diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 7584a2e08f85..107d8d41e9a3 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -16,13 +16,14 @@ package com.android.systemui.recents.views; +import static android.app.ActivityManager.StackId.INVALID_STACK_ID; + import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; import android.content.Context; import android.content.res.Resources; -import android.graphics.Color; import android.graphics.Outline; import android.graphics.Paint; import android.graphics.Point; @@ -59,8 +60,6 @@ import com.android.systemui.recents.model.TaskStack; import java.util.ArrayList; -import static android.app.ActivityManager.StackId.INVALID_STACK_ID; - /** * A {@link TaskView} represents a fixed view of a task. Because the TaskView's layout is directed * solely by the {@link TaskStackView}, we make it a fixed size layout which allows relayouts down @@ -559,6 +558,13 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks postAnimationTrigger.decrementOnAnimationEnd()); } + @Override + public void onStartFrontTaskEnterAnimation(boolean screenPinningEnabled) { + if (screenPinningEnabled) { + showActionButton(false /* fadeIn */, 0 /* fadeInDuration */); + } + } + /**** TaskCallbacks Implementation ****/ public void onTaskBound(Task t) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java index b2a7d902f002..cdff16d1a0b5 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java @@ -350,6 +350,7 @@ public class TaskViewHeader extends FrameLayout public void setDimAlpha(float dimAlpha) { if (Float.compare(mDimAlpha, dimAlpha) != 0) { mDimAlpha = dimAlpha; + mTitleView.setAlpha(1f - dimAlpha); updateBackgroundColor(mBackground.getColor(), dimAlpha); } } |