Snap for 8283941 from fec75c5a0e to tm-release
Change-Id: Ib40be74466fcfa0737331eacb8a314b78ea972d4
This commit is contained in:
@@ -14,7 +14,8 @@
|
||||
limitations under the License.
|
||||
-->
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
|
||||
android:shape="rectangle">
|
||||
<corners android:radius="28dp"/>
|
||||
<solid android:color="?android:attr/colorBackgroundFloating"/>
|
||||
<solid android:color="?androidprv:attr/colorSurface"/>
|
||||
</shape>
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2022 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:paddingTop="26dp"
|
||||
android:paddingBottom="26dp"
|
||||
android:paddingStart="56dp"
|
||||
android:paddingEnd="56dp">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_1"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_1"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintVertical_chainStyle="spread_inside"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/hotseat_icon_2"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_2"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_2"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_1"
|
||||
app:layout_constraintBottom_toTopOf="@id/hotseat_icon_3"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_3"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_3"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_2"
|
||||
app:layout_constraintBottom_toTopOf="@id/hotseat_icon_4"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_4"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_4"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toBottomOf="@id/hotseat_icon_3"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,123 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2022 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="32dp"
|
||||
android:paddingStart="@dimen/gesture_tutorial_hotseat_padding_start_end"
|
||||
android:paddingEnd="@dimen/gesture_tutorial_hotseat_padding_start_end">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_search_bar"
|
||||
android:layout_width="200dp"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
|
||||
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_search_bar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_1"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_1"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_1"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_search_bar"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_2"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_2"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_3"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_3"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_4"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_1"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_5"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_5"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_4"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_icon_4"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_6"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_6"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_2"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_icon_5"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -60,7 +60,7 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/title"
|
||||
style="@style/TextAppearance.GestureTutorial.Feedback.Title"
|
||||
style="@style/TextAppearance.GestureTutorial.Feedback.Title.AllSet"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/allset_title_margin_top"
|
||||
@@ -71,15 +71,14 @@
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subtitle"
|
||||
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
|
||||
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle.AllSet"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/allset_subtitle_margin_top"
|
||||
app:layout_constraintTop_toBottomOf="@id/title"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintWidth_max="@dimen/allset_subtitle_width_max"
|
||||
android:gravity="start"
|
||||
android:text="@string/allset_description"/>
|
||||
android:gravity="start"/>
|
||||
|
||||
<androidx.constraintlayout.widget.Guideline
|
||||
android:id="@+id/navigation_settings_guideline_bottom"
|
||||
|
||||
@@ -1,12 +1,26 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2022 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="32dp"
|
||||
android:paddingStart="170dp"
|
||||
android:paddingEnd="170dp">
|
||||
android:paddingStart="@dimen/gesture_tutorial_hotseat_padding_start_end"
|
||||
android:paddingEnd="@dimen/gesture_tutorial_hotseat_padding_start_end">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_search_bar"
|
||||
|
||||
@@ -27,10 +27,8 @@
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/gesture_tutorial_fake_hotseat_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_alignParentBottom="true"/>
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_width"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_height"/>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
@@ -102,7 +100,7 @@
|
||||
android:background="@drawable/gesture_tutorial_ripple"/>
|
||||
|
||||
<include
|
||||
layout="@layout/gesture_tutorial_foldable_mock_taskbar"
|
||||
layout="@layout/gesture_tutorial_tablet_mock_taskbar"
|
||||
android:id="@+id/gesture_tutorial_fake_taskbar_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/gesture_tutorial_mock_taskbar_height"
|
||||
@@ -121,33 +119,23 @@
|
||||
android:scaleType="fitXY"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/gesture_tutorial_finger_dot"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/gesture_tutorial_finger_dot"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/gesture_tutorial_fragment_feedback_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_marginTop="24dp"
|
||||
android:paddingTop="24dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingStart="24dp"
|
||||
android:paddingEnd="24dp"
|
||||
android:background="@drawable/bg_sandbox_feedback">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/gesture_tutorial_fragment_feedback_title"
|
||||
style="@style/TextAppearance.GestureTutorial.Feedback.Title"
|
||||
android:layout_width="0dp"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -158,9 +146,7 @@
|
||||
style="@style/TextAppearance.GestureTutorial.Feedback.Subtitle"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginTop="16dp"
|
||||
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
@@ -182,7 +168,6 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingStart="26dp"
|
||||
@@ -201,11 +186,8 @@
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="32dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:paddingTop="16dp"
|
||||
android:paddingBottom="16dp"
|
||||
android:paddingStart="26dp"
|
||||
android:paddingEnd="26dp"
|
||||
android:text="@string/gesture_tutorial_action_button_label_skip"
|
||||
android:background="?android:attr/selectableItemBackgroundBorderless"
|
||||
|
||||
@@ -214,4 +196,13 @@
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/gesture_tutorial_finger_dot"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:src="@drawable/gesture_tutorial_finger_dot"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:visibility="gone"/>
|
||||
|
||||
</com.android.quickstep.interaction.RootSandboxLayout>
|
||||
@@ -34,8 +34,8 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="43dp"
|
||||
android:layout_marginBottom="22dp"
|
||||
android:layout_marginStart="34dp"
|
||||
android:layout_marginEnd="211dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_top_bar_margin_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_top_bar_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
@@ -84,7 +84,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="@color/mock_conversation_background"
|
||||
android:paddingBottom="66dp"
|
||||
android:paddingBottom="@dimen/gesture_tutorial_conversation_bottom_padding"
|
||||
|
||||
app:layout_constraintTop_toBottomOf="@id/top_bar"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
@@ -108,6 +108,7 @@
|
||||
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
|
||||
android:layout_marginStart="124dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_message_padding_end"
|
||||
android:visibility="@integer/gesture_tutorial_extra_messages_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="18dp"
|
||||
@@ -122,6 +123,7 @@
|
||||
android:layout_height="@dimen/gesture_tutorial_message_icon_size"
|
||||
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_message_padding_start"
|
||||
android:visibility="@integer/gesture_tutorial_extra_messages_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_message_icon_corner_radius"
|
||||
@@ -135,6 +137,7 @@
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="17dp"
|
||||
android:layout_marginEnd="112dp"
|
||||
android:visibility="@integer/gesture_tutorial_extra_messages_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="18dp"
|
||||
@@ -151,6 +154,7 @@
|
||||
android:layout_marginBottom="@dimen/gesture_tutorial_message_small_margin_bottom"
|
||||
android:layout_marginStart="280dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_message_padding_end"
|
||||
android:visibility="@integer/gesture_tutorial_extra_messages_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="18dp"
|
||||
@@ -164,7 +168,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="74dp"
|
||||
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
|
||||
android:layout_marginStart="124dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_message_margin_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_message_padding_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
@@ -192,7 +196,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="17dp"
|
||||
android:layout_marginEnd="144dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_reply_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="18dp"
|
||||
@@ -206,7 +210,7 @@
|
||||
android:id="@+id/message_4"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="74dp"
|
||||
android:layout_marginStart="124dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_message_margin_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_message_padding_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
android:layout_marginTop="43dp"
|
||||
android:layout_marginBottom="22dp"
|
||||
android:layout_marginStart="34dp"
|
||||
android:layout_marginEnd="35dp"
|
||||
android:layout_marginEnd="34dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
@@ -51,337 +51,336 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:background="@color/mock_list_background"
|
||||
android:paddingBottom="66dp"
|
||||
android:paddingTop="@dimen/gesture_tutorial_conversation_list_padding_top"
|
||||
android:paddingStart="26dp"
|
||||
|
||||
app:layout_constraintTop_toBottomOf="@id/top_bar"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:paddingTop="@dimen/gesture_tutorial_conversation_list_padding_top"
|
||||
android:paddingStart="26dp"
|
||||
android:paddingBottom="14dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_1"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/mock_button">
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_1"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_1_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_1"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_2"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="217dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_2_margin_end"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_1"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_2"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_1"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_1"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_2"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="142dp"
|
||||
android:layout_marginTop="4dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_2"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_1"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_1"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_1"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_1"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_2"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_3_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_1"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_2"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_4"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_3"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="190dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_4"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_4_margin_end"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_2"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_4"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_3"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_2"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_4"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="171dp"
|
||||
android:layout_marginTop="4dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_3"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_3"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_2"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_2"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_2"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_3"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_5"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_5_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_2"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_3"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_3"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_6"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_5"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="198dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_6"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_6_margin_end"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_3"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_3"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_6"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_5"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_3"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_3"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_6"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="79dp"
|
||||
android:layout_marginTop="4dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_4"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_5"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_3"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_3"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_3"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_4"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_7"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_7_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_3"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_4"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_4"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_8"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_7"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="174dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_8"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_conversation_line_8_margin_end"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_4"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_4"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_8"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_7"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_4"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_4"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_8"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="117dp"
|
||||
android:layout_marginTop="4dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_5"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_7"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_4"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_4"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_4"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_5"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_9"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="244dp"
|
||||
android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_4"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_5"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_5"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_10"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_9"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="244dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_10"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="143dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_5"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_5"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_10"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_9"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_5"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_5"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_10"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="143dp"
|
||||
android:layout_marginTop="4dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_6"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_9"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_5"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_5"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_5"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_6"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_11"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="177dp"
|
||||
android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_5"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_6"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_6"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_12"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_11"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="177dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_12"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="117dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_6"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_6"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_12"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_11"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_6"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_6"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_12"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="117dp"
|
||||
android:layout_marginTop="4dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_7"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_11"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_6"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_6"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_6"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_7"
|
||||
android:layout_width="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_conversation_icon_size"
|
||||
android:layout_marginTop="32dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_13"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="189dp"
|
||||
android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_conversation_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_list_profile_icon"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_icon_6"
|
||||
app:layout_constraintStart_toStartOf="parent"/>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_7"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_7"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_14"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_13"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="18dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="189dp"
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_14"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="166dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:visibility="@integer/gesture_tutorial_extra_conversations_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
app:layout_constraintTop_toTopOf="@id/conversation_icon_7"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_7"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toTopOf="@id/conversation_line_14"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_line_14"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="166dp"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_13"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_7"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_7"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="4dp"
|
||||
app:cardBackgroundColor="@color/mock_list_preview_message"
|
||||
app:layout_constraintTop_toBottomOf="@id/conversation_line_13"
|
||||
app:layout_constraintStart_toEndOf="@id/conversation_icon_7"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_7"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/mock_button"
|
||||
android:layout_width="149dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_mock_button_margin_end"
|
||||
android:layout_marginBottom="@dimen/gesture_tutorial_mock_button_margin_bottom"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="164dp"
|
||||
|
||||
@@ -34,8 +34,8 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="48dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_webpage_url_margin_start_end"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_webpage_url_margin_start_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="100dp"
|
||||
@@ -63,7 +63,7 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="22dp"
|
||||
android:layout_marginBottom="22dp"
|
||||
android:layout_marginStart="24dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_webpage_top_bar_button_margin_start"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="8dp"
|
||||
@@ -78,8 +78,8 @@
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="28dp"
|
||||
android:layout_marginBottom="28dp"
|
||||
android:layout_marginStart="97dp"
|
||||
android:layout_marginEnd="97dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_webpage_top_bar_margin_start"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_webpage_top_bar_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="2dp"
|
||||
@@ -107,7 +107,7 @@
|
||||
android:id="@+id/mock_line_1"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/gesture_tutorial_webpage_large_line_height"
|
||||
android:layout_marginEnd="126dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_webpage_line_1_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_small_corner_radius"
|
||||
@@ -121,7 +121,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/gesture_tutorial_webpage_large_line_height"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
|
||||
android:layout_marginEnd="64dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_webpage_line_2_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_small_corner_radius"
|
||||
@@ -135,7 +135,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/gesture_tutorial_webpage_large_line_height"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
|
||||
android:layout_marginEnd="151dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_webpage_line_3_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_small_corner_radius"
|
||||
@@ -174,7 +174,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="240dp"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_webpage_large_margin_top"
|
||||
android:layout_marginEnd="24dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_webpage_block_margin_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_large_corner_radius"
|
||||
@@ -189,6 +189,7 @@
|
||||
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_webpage_large_margin_top"
|
||||
android:layout_marginEnd="52dp"
|
||||
android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
|
||||
@@ -203,6 +204,7 @@
|
||||
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
|
||||
android:layout_marginEnd="41dp"
|
||||
android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
|
||||
@@ -217,6 +219,7 @@
|
||||
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
|
||||
android:layout_marginEnd="71dp"
|
||||
android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
|
||||
@@ -231,6 +234,7 @@
|
||||
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
|
||||
android:layout_marginEnd="198dp"
|
||||
android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
|
||||
@@ -245,6 +249,7 @@
|
||||
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_webpage_large_margin_top"
|
||||
android:layout_marginEnd="64dp"
|
||||
android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
|
||||
@@ -258,6 +263,7 @@
|
||||
android:layout_height="@dimen/gesture_tutorial_webpage_small_line_height"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_webpage_small_margin_top"
|
||||
android:layout_marginEnd="71dp"
|
||||
android:visibility="@integer/gesture_tutorial_webpage_extra_lines_visibility"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_webpage_medium_corner_radius"
|
||||
|
||||
+12
-12
@@ -106,8 +106,8 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="112dp"
|
||||
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
|
||||
android:layout_marginStart="445dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_foldable_message_padding_start_end"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_tablet_message_1_margin"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_tablet_message_padding_start_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="18dp"
|
||||
@@ -121,7 +121,7 @@
|
||||
android:layout_width="@dimen/gesture_tutorial_message_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_message_icon_size"
|
||||
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_foldable_message_padding_start_end"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_tablet_message_padding_start_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_message_icon_corner_radius"
|
||||
@@ -134,7 +134,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="17dp"
|
||||
android:layout_marginEnd="441dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_tablet_reply_1_margin"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="18dp"
|
||||
@@ -149,8 +149,8 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginBottom="@dimen/gesture_tutorial_message_small_margin_bottom"
|
||||
android:layout_marginStart="601dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_foldable_message_padding_start_end"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_tablet_message_2_margin"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_tablet_message_padding_start_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="18dp"
|
||||
@@ -164,8 +164,8 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="74dp"
|
||||
android:layout_marginBottom="@dimen/gesture_tutorial_message_large_margin_bottom"
|
||||
android:layout_marginStart="445dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_foldable_message_padding_start_end"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_tablet_message_3_margin"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_tablet_message_padding_start_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="18dp"
|
||||
@@ -179,7 +179,7 @@
|
||||
android:layout_width="@dimen/gesture_tutorial_message_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_message_icon_size"
|
||||
android:layout_marginBottom="32dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_foldable_message_padding_start_end"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_tablet_message_padding_start_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_message_icon_corner_radius"
|
||||
@@ -192,7 +192,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="36dp"
|
||||
android:layout_marginStart="17dp"
|
||||
android:layout_marginEnd="473dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_tablet_reply_2_margin"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="18dp"
|
||||
@@ -206,8 +206,8 @@
|
||||
android:id="@+id/message_4"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="74dp"
|
||||
android:layout_marginStart="445dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_foldable_message_padding_start_end"
|
||||
android:layout_marginStart="345dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_tablet_message_padding_start_end"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="18dp"
|
||||
+17
-17
@@ -67,7 +67,7 @@
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/mock_button">
|
||||
app:layout_constraintEnd_toEndOf="parent">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/conversation_icon_1"
|
||||
@@ -189,7 +189,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="15dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_tablet_conversation_line_6_margin_end"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
@@ -233,7 +233,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="72dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_tablet_conversation_line_8_margin_end"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
@@ -277,7 +277,7 @@
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="16dp"
|
||||
android:layout_marginStart="@dimen/gesture_tutorial_conversation_line_padding_start"
|
||||
android:layout_marginEnd="111dp"
|
||||
android:layout_marginEnd="@dimen/gesture_tutorial_tablet_conversation_line_10_margin_end"
|
||||
android:layout_marginTop="4dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
@@ -376,21 +376,21 @@
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="@id/conversation_icon_7"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/mock_button"
|
||||
android:layout_width="149dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginEnd="126dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="164dp"
|
||||
app:cardBackgroundColor="@color/mock_list_button"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/mock_button"
|
||||
android:layout_width="149dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_marginEnd="126dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="164dp"
|
||||
app:cardBackgroundColor="@color/mock_list_button"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -0,0 +1,122 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2022 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingBottom="32dp"
|
||||
android:paddingStart="@dimen/gesture_tutorial_hotseat_padding_start_end"
|
||||
android:paddingEnd="@dimen/gesture_tutorial_hotseat_padding_start_end">
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_search_bar"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_search_height"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_search_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_search_bar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_1"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_1"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_2"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_2"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_2"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_icon_1"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_3"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_3"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_3"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_icon_2"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_4"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_4"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_1"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_icon_3"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_5"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_5"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_4"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_icon_4"
|
||||
app:layout_constraintEnd_toStartOf="@id/hotseat_icon_6"/>
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/hotseat_icon_6"
|
||||
android:layout_width="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_height="@dimen/gesture_tutorial_hotseat_icon_size"
|
||||
android:layout_marginTop="@dimen/gesture_tutorial_hotseat_icon_search_margin"
|
||||
|
||||
app:cardElevation="0dp"
|
||||
app:cardCornerRadius="@dimen/gesture_tutorial_hotseat_icon_corner_radius"
|
||||
app:cardBackgroundColor="@color/mock_app_icon_2"
|
||||
app:layout_constraintDimensionRatio="1:1"
|
||||
app:layout_constraintTop_toBottomOf="@id/hotseat_search_bar"
|
||||
app:layout_constraintStart_toEndOf="@id/hotseat_icon_5"
|
||||
app:layout_constraintEnd_toEndOf="parent"/>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
@@ -16,4 +16,61 @@
|
||||
-->
|
||||
<resources>
|
||||
<dimen name="overview_task_margin">8dp</dimen>
|
||||
|
||||
<!-- Tips Gesture Tutorial -->
|
||||
<dimen name="gesture_tutorial_feedback_margin_start_end">126dp</dimen>
|
||||
<dimen name="gesture_tutorial_feedback_margin_top">24dp</dimen>
|
||||
|
||||
<!-- Gesture Tutorial mock conversations -->
|
||||
<dimen name="gesture_tutorial_message_padding_start">42dp</dimen>
|
||||
<dimen name="gesture_tutorial_message_padding_end">60dp</dimen>
|
||||
<dimen name="gesture_tutorial_top_bar_margin_start">42dp</dimen>
|
||||
<dimen name="gesture_tutorial_top_bar_margin_end">683dp</dimen>
|
||||
<dimen name="gesture_tutorial_top_bar_button_margin_end">42dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_bottom_padding">35dp</dimen>
|
||||
<integer name="gesture_tutorial_extra_messages_visibility">2</integer> <!-- GONE -->
|
||||
<dimen name="gesture_tutorial_message_margin_start">505dp</dimen>
|
||||
<dimen name="gesture_tutorial_reply_margin_end">462dp</dimen>
|
||||
<dimen name="gesture_tutorial_input_margin_start">103dp</dimen>
|
||||
<dimen name="gesture_tutorial_input_margin_end">103dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_message_1_margin">345dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_reply_1_margin">341dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_message_2_margin">501dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_message_3_margin">345dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_reply_2_margin">373dp</dimen>
|
||||
|
||||
<!-- Gesture Tutorial mock conversation lists -->
|
||||
<dimen name="gesture_tutorial_conversation_line_1_margin_end">607dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_2_margin_end">460dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_3_margin_end">554dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_4_margin_end">517dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_5_margin_end">570dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_6_margin_end">336dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_7_margin_end">523dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_8_margin_end">500dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_conversation_line_6_margin_end">15dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_conversation_line_8_margin_end">72dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_conversation_line_10_margin_end">111dp</dimen>
|
||||
<integer name="gesture_tutorial_extra_conversations_visibility">2</integer> <!-- GONE -->
|
||||
<dimen name="gesture_tutorial_mock_button_margin_end">34dp</dimen>
|
||||
<dimen name="gesture_tutorial_mock_button_margin_bottom">42dp</dimen>
|
||||
|
||||
<!-- Gesture Tutorial mock hotseats -->
|
||||
<dimen name="gesture_tutorial_hotseat_width">-2px</dimen> <!-- wrap_content -->
|
||||
<dimen name="gesture_tutorial_hotseat_height">-1px</dimen> <!-- match_parent -->
|
||||
<dimen name="gesture_tutorial_hotseat_padding_start_end">170dp</dimen>
|
||||
|
||||
<!-- Gesture Tutorial mock webpages -->
|
||||
<dimen name="gesture_tutorial_webpage_url_margin_start_end">24dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_top_bar_button_margin_start">48dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_top_bar_margin_start">121dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_top_bar_margin_end">355dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_line_1_margin_end">355dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_line_2_margin_end">208dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_line_3_margin_end">439dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_block_margin_end">311dp</dimen>
|
||||
<integer name="gesture_tutorial_webpage_extra_lines_visibility">2</integer> <!-- GONE -->
|
||||
|
||||
<!-- Gesture Tutorial mock taskbar -->
|
||||
<dimen name="gesture_tutorial_taskbar_padding_start_end">218dp</dimen>
|
||||
</resources>
|
||||
@@ -23,8 +23,8 @@
|
||||
</string-array>
|
||||
|
||||
<string name="stats_log_manager_class" translatable="false">com.android.quickstep.logging.StatsLogCompatManager</string>
|
||||
|
||||
<string name="test_information_handler_class" translatable="false">com.android.quickstep.QuickstepTestInformationHandler</string>
|
||||
<string name="window_manager_proxy_class" translatable="false">com.android.quickstep.util.SystemWindowManagerProxy</string>
|
||||
|
||||
<!-- The number of thumbnails and icons to keep in the cache. The thumbnail cache size also
|
||||
determines how many thumbnails will be fetched in the background. -->
|
||||
|
||||
@@ -110,8 +110,10 @@
|
||||
<dimen name="gestures_overscroll_finish_threshold">136dp</dimen>
|
||||
|
||||
<!-- Tips Gesture Tutorial -->
|
||||
<dimen name="gesture_tutorial_feedback_margin_start_end">24dp</dimen>
|
||||
<dimen name="gesture_tutorial_foldable_feedback_margin_start_end">140dp</dimen>
|
||||
<dimen name="gesture_tutorial_feedback_margin_start_end">8dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_feedback_margin_start_end">140dp</dimen>
|
||||
<dimen name="gesture_tutorial_feedback_margin_top">16dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_feedback_margin_top">24dp</dimen>
|
||||
<dimen name="gesture_tutorial_multi_row_task_view_spacing">72dp</dimen>
|
||||
<dimen name="gesture_tutorial_small_task_view_corner_radius">18dp</dimen>
|
||||
<dimen name="gesture_tutorial_mock_taskbar_height">80dp</dimen>
|
||||
@@ -124,15 +126,46 @@
|
||||
<dimen name="gesture_tutorial_message_small_margin_bottom">4dp</dimen>
|
||||
<dimen name="gesture_tutorial_message_padding_start">26dp</dimen>
|
||||
<dimen name="gesture_tutorial_message_padding_end">18dp</dimen>
|
||||
<dimen name="gesture_tutorial_foldable_message_padding_start_end">126dp</dimen>
|
||||
<dimen name="gesture_tutorial_top_bar_margin_start">34dp</dimen>
|
||||
<dimen name="gesture_tutorial_top_bar_margin_end">211dp</dimen>
|
||||
<dimen name="gesture_tutorial_top_bar_button_margin_end">24dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_bottom_padding">66dp</dimen>
|
||||
<integer name="gesture_tutorial_extra_messages_visibility">0</integer> <!-- VISIBLE -->
|
||||
<dimen name="gesture_tutorial_message_margin_start">124dp</dimen>
|
||||
<dimen name="gesture_tutorial_reply_margin_end">144dp</dimen>
|
||||
<dimen name="gesture_tutorial_input_margin_start">34dp</dimen>
|
||||
<dimen name="gesture_tutorial_input_margin_end">24dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_message_padding_start_end">126dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_message_1_margin">245dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_reply_1_margin">241dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_message_2_margin">401dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_message_3_margin">245dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_reply_2_margin">273dp</dimen>
|
||||
|
||||
<!-- Gesture Tutorial mock conversation lists -->
|
||||
<dimen name="gesture_tutorial_conversation_icon_size">56dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_icon_corner_radius">100dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_list_padding_top">28dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_padding_start">20dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_1_margin_end">217dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_2_margin_end">142dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_3_margin_end">190dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_4_margin_end">171dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_5_margin_end">198dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_6_margin_end">79dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_7_margin_end">174dp</dimen>
|
||||
<dimen name="gesture_tutorial_conversation_line_8_margin_end">117dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_conversation_line_6_margin_end">65dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_conversation_line_8_margin_end">132dp</dimen>
|
||||
<dimen name="gesture_tutorial_tablet_conversation_line_10_margin_end">161dp</dimen>
|
||||
<integer name="gesture_tutorial_extra_conversations_visibility">0</integer> <!-- VISIBLE -->
|
||||
<dimen name="gesture_tutorial_mock_button_margin_end">24dp</dimen>
|
||||
<dimen name="gesture_tutorial_mock_button_margin_bottom">66dp</dimen>
|
||||
|
||||
<!-- Gesture Tutorial mock hotseats -->
|
||||
<dimen name="gesture_tutorial_hotseat_width">-1px</dimen> <!-- match_parent -->
|
||||
<dimen name="gesture_tutorial_hotseat_height">-2px</dimen> <!-- wrap_content -->
|
||||
<dimen name="gesture_tutorial_hotseat_padding_start_end">26dp</dimen>
|
||||
<dimen name="gesture_tutorial_hotseat_icon_size">60dp</dimen>
|
||||
<dimen name="gesture_tutorial_hotseat_icon_corner_radius">100dp</dimen>
|
||||
<dimen name="gesture_tutorial_hotseat_search_height">50dp</dimen>
|
||||
@@ -148,11 +181,20 @@
|
||||
<dimen name="gesture_tutorial_webpage_small_corner_radius">4dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_large_line_height">36dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_small_line_height">22dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_url_margin_start_end">16dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_top_bar_button_margin_start">24dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_top_bar_margin_start">97dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_top_bar_margin_end">97dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_line_1_margin_end">126dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_line_2_margin_end">64dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_line_3_margin_end">151dp</dimen>
|
||||
<dimen name="gesture_tutorial_webpage_block_margin_end">24dp</dimen>
|
||||
<integer name="gesture_tutorial_webpage_extra_lines_visibility">0</integer> <!-- VISIBLE -->
|
||||
|
||||
<!-- Gesture Tutorial mock taskbar -->
|
||||
<dimen name="gesture_tutorial_taskbar_icon_size">44dp</dimen>
|
||||
<dimen name="gesture_tutorial_taskbar_icon_corner_radius">100dp</dimen>
|
||||
<dimen name="gesture_tutorial_taskbar_padding_start_end">218dp</dimen>
|
||||
<dimen name="gesture_tutorial_taskbar_padding_start_end">52dp</dimen>
|
||||
|
||||
<!-- All Set page -->
|
||||
<dimen name="allset_page_margin_horizontal">40dp</dimen>
|
||||
@@ -217,6 +259,7 @@
|
||||
<dimen name="taskbar_contextual_buttons_size">35dp</dimen>
|
||||
<dimen name="taskbar_stashed_size">24dp</dimen>
|
||||
<dimen name="taskbar_stashed_handle_width">220dp</dimen>
|
||||
<dimen name="taskbar_unstash_input_area">316dp</dimen>
|
||||
<dimen name="taskbar_stashed_handle_height">4dp</dimen>
|
||||
<dimen name="taskbar_edu_wave_anim_trans_y">25dp</dimen>
|
||||
<dimen name="taskbar_edu_wave_anim_trans_y_return_overshoot">4dp</dimen>
|
||||
|
||||
@@ -182,8 +182,10 @@
|
||||
<string name="allset_title">All set!</string>
|
||||
<!-- Hint string at the bottom of "All Set" page [CHAR LIMIT=NONE] -->
|
||||
<string name="allset_hint">Swipe up to go Home</string>
|
||||
<!-- Description of "All Set" page [CHAR LIMIT=NONE] -->
|
||||
<!-- Description of "All Set" page on phones [CHAR LIMIT=NONE] -->
|
||||
<string name="allset_description">You\u2019re ready to start using your phone</string>
|
||||
<!-- Description of "All Set" page on tablets [CHAR LIMIT=NONE] -->
|
||||
<string name="allset_description_tablet">You\u2019re ready to start using your tablet</string>
|
||||
<!-- String linking to navigation settings on "All Set" page [CHAR LIMIT=NONE] -->
|
||||
<string name="allset_navigation_settings"><annotation id="link">System navigation settings</annotation></string>
|
||||
|
||||
|
||||
@@ -47,6 +47,12 @@
|
||||
<item name="android:lineHeight">44sp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.GestureTutorial.Feedback.Title.AllSet"
|
||||
parent="TextAppearance.GestureTutorial.Feedback.Title">
|
||||
<item name="android:letterSpacing">0.03</item>
|
||||
<item name="android:lineHeight">44sp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.GestureTutorial.Dialog.Title"
|
||||
parent="TextAppearance.GestureTutorial.Feedback.Title">
|
||||
<item name="android:gravity">center_horizontal</item>
|
||||
@@ -61,6 +67,12 @@
|
||||
<item name="android:textColor">?android:attr/textColorPrimary</item>
|
||||
<item name="android:fontFamily">google-sans-text</item>
|
||||
<item name="android:letterSpacing">0.03</item>
|
||||
<item name="android:textSize">14sp</item>
|
||||
<item name="android:lineHeight">20sp</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.GestureTutorial.Feedback.Subtitle.AllSet"
|
||||
parent="TextAppearance.GestureTutorial.Feedback.Subtitle">
|
||||
<item name="android:textSize">18sp</item>
|
||||
<item name="android:lineHeight">24sp</item>
|
||||
</style>
|
||||
@@ -76,9 +88,8 @@
|
||||
|
||||
<style name="TextAppearance.GestureTutorial.Feedback.Subtext"
|
||||
parent="TextAppearance.GestureTutorial.Feedback.Subtitle">
|
||||
<item name="android:textSize">16sp</item>
|
||||
<item name="android:textColor">@color/gesture_tutorial_primary_color</item>
|
||||
<item name="android:gravity">center</item>
|
||||
<item name="android:gravity">start</item>
|
||||
</style>
|
||||
|
||||
<style name="TextAppearance.GestureTutorial.Feedback.Subtext.Dark"
|
||||
|
||||
@@ -26,7 +26,6 @@ import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
|
||||
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
|
||||
import static com.android.launcher3.util.DisplayController.CHANGE_ACTIVE_SCREEN;
|
||||
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
|
||||
import static com.android.launcher3.util.DisplayController.NavigationMode.NO_BUTTON;
|
||||
import static com.android.launcher3.util.DisplayController.NavigationMode.TWO_BUTTONS;
|
||||
import static com.android.launcher3.util.Executors.THREAD_POOL_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
@@ -38,7 +37,6 @@ import android.app.ActivityOptions;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.graphics.Insets;
|
||||
import android.hardware.SensorManager;
|
||||
import android.hardware.devicestate.DeviceStateManager;
|
||||
import android.os.Bundle;
|
||||
@@ -46,7 +44,6 @@ import android.os.CancellationSignal;
|
||||
import android.os.IBinder;
|
||||
import android.view.Display;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
import android.window.SplashScreen;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -614,17 +611,4 @@ public abstract class BaseQuickstepLauncher extends Launcher {
|
||||
mDepthController.dump(prefix, writer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateWindowInsets(WindowInsets.Builder updatedInsetsBuilder,
|
||||
WindowInsets oldInsets) {
|
||||
// Override the tappable insets to be 0 on the bottom for gesture nav (otherwise taskbar
|
||||
// would count towards it). This is used for the bottom protection in All Apps for example.
|
||||
if (DisplayController.getNavigationMode(this) == NO_BUTTON) {
|
||||
Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement());
|
||||
Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top,
|
||||
oldTappableInsets.right, 0);
|
||||
updatedInsetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -579,8 +579,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
}
|
||||
}
|
||||
|
||||
// Pause page indicator animations as they lead to layer trashing.
|
||||
mLauncher.getWorkspace().getPageIndicator().pauseAnimations();
|
||||
// Pause expensive view updates as they can lead to layer thrashing and skipped frames.
|
||||
mLauncher.pauseExpensiveViewUpdates();
|
||||
|
||||
endListener = () -> {
|
||||
viewsToAnimate.forEach(view -> {
|
||||
@@ -590,7 +590,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
if (scrimEnabled) {
|
||||
mLauncher.getScrimView().setBackgroundColor(Color.TRANSPARENT);
|
||||
}
|
||||
mLauncher.getWorkspace().getPageIndicator().skipAnimationsToEnd();
|
||||
mLauncher.resumeExpensiveViewUpdates();
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1186,6 +1186,19 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasMultipleTargetsWithMode(RemoteAnimationTargetCompat[] targets, int mode) {
|
||||
int numTargets = 0;
|
||||
for (RemoteAnimationTargetCompat target : targets) {
|
||||
if (target.mode == mode) {
|
||||
numTargets++;
|
||||
}
|
||||
if (numTargets > 1) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Runner that plays when user goes to Launcher
|
||||
* ie. pressing home, swiping up from nav bar.
|
||||
@@ -1580,7 +1593,8 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener
|
||||
View launcherView = findLauncherView(appTargets);
|
||||
boolean playFallBackAnimation = (launcherView == null
|
||||
&& launcherIsForceInvisibleOrOpening)
|
||||
|| mLauncher.getWorkspace().isOverlayShown();
|
||||
|| mLauncher.getWorkspace().isOverlayShown()
|
||||
|| hasMultipleTargetsWithMode(appTargets, MODE_CLOSING);
|
||||
|
||||
boolean playWorkspaceReveal = true;
|
||||
boolean skipAllAppsScale = false;
|
||||
|
||||
@@ -49,6 +49,7 @@ import android.view.Gravity;
|
||||
import android.view.RoundedCorner;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowManagerGlobal;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
@@ -185,8 +186,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
new TaskbarDragLayerController(this, mDragLayer),
|
||||
new TaskbarViewController(this, taskbarView),
|
||||
new TaskbarScrimViewController(this, taskbarScrimView),
|
||||
new TaskbarUnfoldAnimationController(unfoldTransitionProgressProvider,
|
||||
mWindowManager),
|
||||
new TaskbarUnfoldAnimationController(this, unfoldTransitionProgressProvider,
|
||||
mWindowManager, WindowManagerGlobal.getWindowManagerService()),
|
||||
new TaskbarKeyguardController(this),
|
||||
new StashedHandleViewController(this, stashedHandleView),
|
||||
new TaskbarStashController(this),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING;
|
||||
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DEVICE_DOZING;
|
||||
@@ -14,6 +15,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
|
||||
import com.android.launcher3.AbstractFloatingView;
|
||||
import com.android.systemui.shared.system.QuickStepContract;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -39,6 +41,7 @@ public class TaskbarKeyguardController implements TaskbarControllers.LoggableTas
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
mIsScreenOff = true;
|
||||
AbstractFloatingView.closeOpenViews(mContext, false, TYPE_ALL);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -71,6 +74,10 @@ public class TaskbarKeyguardController implements TaskbarControllers.LoggableTas
|
||||
mNavbarButtonsViewController.setKeyguardVisible(keyguardShowing || dozing,
|
||||
keyguardOccluded);
|
||||
updateIconsForBouncer();
|
||||
|
||||
if (keyguardShowing) {
|
||||
AbstractFloatingView.closeOpenViews(mContext, true, TYPE_ALL);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isScreenOff() {
|
||||
|
||||
@@ -42,6 +42,7 @@ import com.android.launcher3.BaseQuickstepLauncher;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.statemanager.StatefulActivity;
|
||||
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.DisplayController.Info;
|
||||
import com.android.launcher3.util.SettingsCache;
|
||||
@@ -74,8 +75,11 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen
|
||||
private final SimpleBroadcastReceiver mShutdownReceiver;
|
||||
|
||||
// The source for this provider is set when Launcher is available
|
||||
// We use 'non-destroyable' version here so the original provider won't be destroyed
|
||||
// as it is tied to the activity lifecycle, not the taskbar lifecycle.
|
||||
// It's destruction/creation will be managed by the activity.
|
||||
private final ScopedUnfoldTransitionProgressProvider mUnfoldProgressProvider =
|
||||
new ScopedUnfoldTransitionProgressProvider();
|
||||
new NonDestroyableScopedUnfoldTransitionProgressProvider();
|
||||
|
||||
private TaskbarActivityContext mTaskbarActivityContext;
|
||||
private StatefulActivity mActivity;
|
||||
|
||||
@@ -250,7 +250,11 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
|
||||
* Returns whether the taskbar is currently visible and in an app.
|
||||
*/
|
||||
public boolean isInAppAndNotStashed() {
|
||||
return !mIsStashed && (mState & FLAG_IN_APP) != 0;
|
||||
return !mIsStashed && isInApp();
|
||||
}
|
||||
|
||||
private boolean isInApp() {
|
||||
return hasAnyFlag(FLAG_IN_APP);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -266,8 +270,15 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba
|
||||
return mUnstashedHeight;
|
||||
}
|
||||
boolean isAnimating = mAnimator != null && mAnimator.isStarted();
|
||||
return mControllers.stashedHandleViewController.isStashedHandleVisible() || isAnimating
|
||||
? mStashedHeight : 0;
|
||||
if (!mControllers.stashedHandleViewController.isStashedHandleVisible()
|
||||
&& isInApp()
|
||||
&& !isAnimating) {
|
||||
// We are in a settled state where we're not showing the handle even though taskbar
|
||||
// is stashed. This can happen for example when home button is disabled (see
|
||||
// StashedHandleViewController#setIsHomeButtonDisabled()).
|
||||
return 0;
|
||||
}
|
||||
return mStashedHeight;
|
||||
}
|
||||
return mUnstashedHeight;
|
||||
}
|
||||
|
||||
@@ -15,12 +15,14 @@
|
||||
*/
|
||||
package com.android.launcher3.taskbar;
|
||||
|
||||
import android.view.IWindowManager;
|
||||
import android.view.View;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import com.android.quickstep.util.LauncherViewsMoveFromCenterTranslationApplier;
|
||||
import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator;
|
||||
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener;
|
||||
import com.android.systemui.unfold.util.NaturalRotationUnfoldProgressProvider;
|
||||
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -31,14 +33,18 @@ import java.io.PrintWriter;
|
||||
public class TaskbarUnfoldAnimationController implements
|
||||
TaskbarControllers.LoggableTaskbarController {
|
||||
|
||||
private final ScopedUnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider;
|
||||
private final ScopedUnfoldTransitionProgressProvider mScopedUnfoldTransitionProgressProvider;
|
||||
private final NaturalRotationUnfoldProgressProvider mNaturalUnfoldTransitionProgressProvider;
|
||||
private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimator;
|
||||
private final TransitionListener mTransitionListener = new TransitionListener();
|
||||
private TaskbarViewController mTaskbarViewController;
|
||||
|
||||
public TaskbarUnfoldAnimationController(ScopedUnfoldTransitionProgressProvider
|
||||
unfoldTransitionProgressProvider, WindowManager windowManager) {
|
||||
mUnfoldTransitionProgressProvider = unfoldTransitionProgressProvider;
|
||||
public TaskbarUnfoldAnimationController(BaseTaskbarContext context,
|
||||
ScopedUnfoldTransitionProgressProvider source,
|
||||
WindowManager windowManager, IWindowManager iWindowManager) {
|
||||
mScopedUnfoldTransitionProgressProvider = source;
|
||||
mNaturalUnfoldTransitionProgressProvider =
|
||||
new NaturalRotationUnfoldProgressProvider(context, iWindowManager, source);
|
||||
mMoveFromCenterAnimator = new UnfoldMoveFromCenterAnimator(windowManager,
|
||||
new LauncherViewsMoveFromCenterTranslationApplier());
|
||||
}
|
||||
@@ -48,18 +54,21 @@ public class TaskbarUnfoldAnimationController implements
|
||||
* @param taskbarControllers references to all other taskbar controllers
|
||||
*/
|
||||
public void init(TaskbarControllers taskbarControllers) {
|
||||
mNaturalUnfoldTransitionProgressProvider.init();
|
||||
mTaskbarViewController = taskbarControllers.taskbarViewController;
|
||||
mTaskbarViewController.addOneTimePreDrawListener(() ->
|
||||
mUnfoldTransitionProgressProvider.setReadyToHandleTransition(true));
|
||||
mUnfoldTransitionProgressProvider.addCallback(mTransitionListener);
|
||||
mScopedUnfoldTransitionProgressProvider.setReadyToHandleTransition(true));
|
||||
mNaturalUnfoldTransitionProgressProvider.addCallback(mTransitionListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroys the controller
|
||||
*/
|
||||
public void onDestroy() {
|
||||
mUnfoldTransitionProgressProvider.setReadyToHandleTransition(false);
|
||||
mUnfoldTransitionProgressProvider.removeCallback(mTransitionListener);
|
||||
mScopedUnfoldTransitionProgressProvider.setReadyToHandleTransition(false);
|
||||
mNaturalUnfoldTransitionProgressProvider.removeCallback(mTransitionListener);
|
||||
mNaturalUnfoldTransitionProgressProvider.destroy();
|
||||
mTaskbarViewController = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -20,13 +20,14 @@ import static com.android.launcher3.Utilities.squaredHypot;
|
||||
import static com.android.launcher3.anim.Interpolators.LINEAR;
|
||||
import static com.android.quickstep.AnimatedFloat.VALUE;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.graphics.Rect;
|
||||
import android.util.FloatProperty;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.view.ViewTreeObserver.OnPreDrawListener;
|
||||
|
||||
import androidx.core.view.OneShotPreDrawListener;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
@@ -143,18 +144,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar
|
||||
* drawing a frame and invoked only once
|
||||
* @param listener callback that will be invoked before drawing the next frame
|
||||
*/
|
||||
public void addOneTimePreDrawListener(Runnable listener) {
|
||||
mTaskbarView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() {
|
||||
@Override
|
||||
public boolean onPreDraw() {
|
||||
final ViewTreeObserver viewTreeObserver = mTaskbarView.getViewTreeObserver();
|
||||
if (viewTreeObserver.isAlive()) {
|
||||
listener.run();
|
||||
viewTreeObserver.removeOnPreDrawListener(this);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
});
|
||||
public void addOneTimePreDrawListener(@NonNull Runnable listener) {
|
||||
OneShotPreDrawListener.add(mTaskbarView, listener);
|
||||
}
|
||||
|
||||
public Rect getIconLayoutBounds() {
|
||||
|
||||
@@ -25,6 +25,9 @@ import android.view.WindowInsets;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter;
|
||||
import com.android.launcher3.allapps.AlphabeticalAppsList;
|
||||
import com.android.launcher3.allapps.BaseAdapterProvider;
|
||||
import com.android.launcher3.allapps.BaseAllAppsAdapter;
|
||||
import com.android.launcher3.allapps.BaseAllAppsContainerView;
|
||||
import com.android.launcher3.allapps.search.SearchAdapterProvider;
|
||||
|
||||
@@ -79,4 +82,11 @@ public class TaskbarAllAppsContainerView extends BaseAllAppsContainerView<Taskba
|
||||
setInsets(insets.getInsets(WindowInsets.Type.systemBars()).toRect());
|
||||
return super.onApplyWindowInsets(insets);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<TaskbarAllAppsContext> mAppsList,
|
||||
BaseAdapterProvider[] adapterProviders) {
|
||||
return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
|
||||
adapterProviders);
|
||||
}
|
||||
}
|
||||
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.taskbar.unfold;
|
||||
|
||||
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
|
||||
|
||||
/**
|
||||
* ScopedUnfoldTransitionProgressProvider that doesn't propagate destroy method
|
||||
*/
|
||||
public class NonDestroyableScopedUnfoldTransitionProgressProvider extends
|
||||
ScopedUnfoldTransitionProgressProvider {
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import android.app.Person;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.content.res.Resources;
|
||||
import android.view.Display;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
@@ -36,20 +35,6 @@ public class ApiWrapper {
|
||||
return persons == null ? Utilities.EMPTY_PERSON_ARRAY : persons;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the display is an internal displays
|
||||
*/
|
||||
public static boolean isInternalDisplay(Display display) {
|
||||
return display.getType() == Display.TYPE_INTERNAL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique ID representing the display
|
||||
*/
|
||||
public static String getUniqueId(Display display) {
|
||||
return display.getUniqueId();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum space that should be left empty at the end of hotseat
|
||||
*/
|
||||
|
||||
@@ -118,8 +118,8 @@ public final class RecentsViewStateController extends
|
||||
|
||||
if (isSplitSelectionState(currentState, toState)) {
|
||||
// Animation to "dismiss" selected taskView
|
||||
PendingAnimation splitSelectInitAnimation =
|
||||
mRecentsView.createSplitSelectInitAnimation();
|
||||
PendingAnimation splitSelectInitAnimation = mRecentsView.createSplitSelectInitAnimation(
|
||||
toState.getTransitionDuration(mLauncher));
|
||||
// Add properties to shift remaining taskViews to get out of placeholder view
|
||||
splitSelectInitAnimation.setFloat(mRecentsView, taskViewsFloat.first,
|
||||
toState.getSplitSelectTranslation(mLauncher), LINEAR);
|
||||
|
||||
@@ -35,11 +35,11 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.ResourceUtils;
|
||||
import com.android.launcher3.util.DisplayController.Info;
|
||||
import com.android.launcher3.util.DisplayController.NavigationMode;
|
||||
import com.android.launcher3.util.window.CachedDisplayInfo;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Maintains state for supporting nav bars and tracking their gestures in multiple orientations.
|
||||
@@ -51,55 +51,17 @@ import java.util.Objects;
|
||||
*/
|
||||
class OrientationTouchTransformer {
|
||||
|
||||
private static class CurrentDisplay {
|
||||
public Point size;
|
||||
public int rotation;
|
||||
|
||||
CurrentDisplay() {
|
||||
this.size = new Point(0, 0);
|
||||
this.rotation = 0;
|
||||
}
|
||||
|
||||
CurrentDisplay(Point size, int rotation) {
|
||||
this.size = size;
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CurrentDisplay:"
|
||||
+ " rotation: " + rotation
|
||||
+ " size: " + size;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
|
||||
CurrentDisplay display = (CurrentDisplay) o;
|
||||
if (rotation != display.rotation) return false;
|
||||
|
||||
return Objects.equals(size, display.size);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(size, rotation);
|
||||
}
|
||||
};
|
||||
|
||||
private static final String TAG = "OrientationTouchTransformer";
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private static final int QUICKSTEP_ROTATION_UNINITIALIZED = -1;
|
||||
|
||||
private final Map<CurrentDisplay, OrientationRectF> mSwipeTouchRegions =
|
||||
new HashMap<CurrentDisplay, OrientationRectF>();
|
||||
private final Map<CachedDisplayInfo, OrientationRectF> mSwipeTouchRegions =
|
||||
new HashMap<CachedDisplayInfo, OrientationRectF>();
|
||||
private final RectF mAssistantLeftRegion = new RectF();
|
||||
private final RectF mAssistantRightRegion = new RectF();
|
||||
private final RectF mOneHandedModeRegion = new RectF();
|
||||
private CurrentDisplay mCurrentDisplay = new CurrentDisplay();
|
||||
private CachedDisplayInfo mCachedDisplayInfo = new CachedDisplayInfo();
|
||||
private int mNavBarGesturalHeight;
|
||||
private final int mNavBarLargerGesturalHeight;
|
||||
private boolean mEnableMultipleRegions;
|
||||
@@ -184,22 +146,22 @@ class OrientationTouchTransformer {
|
||||
* @see #enableMultipleRegions(boolean, Info)
|
||||
*/
|
||||
void createOrAddTouchRegion(Info info) {
|
||||
mCurrentDisplay = new CurrentDisplay(info.currentSize, info.rotation);
|
||||
mCachedDisplayInfo = new CachedDisplayInfo(info.currentSize, info.rotation);
|
||||
|
||||
if (mQuickStepStartingRotation > QUICKSTEP_ROTATION_UNINITIALIZED
|
||||
&& mCurrentDisplay.rotation == mQuickStepStartingRotation) {
|
||||
&& mCachedDisplayInfo.rotation == mQuickStepStartingRotation) {
|
||||
// User already was swiping and the current screen is same rotation as the starting one
|
||||
// Remove active nav bars in other rotations except for the one we started out in
|
||||
resetSwipeRegions(info);
|
||||
return;
|
||||
}
|
||||
OrientationRectF region = mSwipeTouchRegions.get(mCurrentDisplay);
|
||||
OrientationRectF region = mSwipeTouchRegions.get(mCachedDisplayInfo);
|
||||
if (region != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mEnableMultipleRegions) {
|
||||
mSwipeTouchRegions.put(mCurrentDisplay, createRegionForDisplay(info));
|
||||
mSwipeTouchRegions.put(mCachedDisplayInfo, createRegionForDisplay(info));
|
||||
} else {
|
||||
resetSwipeRegions(info);
|
||||
}
|
||||
@@ -245,31 +207,31 @@ class OrientationTouchTransformer {
|
||||
*/
|
||||
private void resetSwipeRegions(Info region) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "clearing all regions except rotation: " + mCurrentDisplay.rotation);
|
||||
Log.d(TAG, "clearing all regions except rotation: " + mCachedDisplayInfo.rotation);
|
||||
}
|
||||
|
||||
mCurrentDisplay = new CurrentDisplay(region.currentSize, region.rotation);
|
||||
OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCurrentDisplay);
|
||||
mCachedDisplayInfo = new CachedDisplayInfo(region.currentSize, region.rotation);
|
||||
OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCachedDisplayInfo);
|
||||
if (regionToKeep == null) {
|
||||
regionToKeep = createRegionForDisplay(region);
|
||||
}
|
||||
mSwipeTouchRegions.clear();
|
||||
mSwipeTouchRegions.put(mCurrentDisplay, regionToKeep);
|
||||
mSwipeTouchRegions.put(mCachedDisplayInfo, regionToKeep);
|
||||
updateAssistantRegions(regionToKeep);
|
||||
}
|
||||
|
||||
private void resetSwipeRegions() {
|
||||
OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCurrentDisplay);
|
||||
OrientationRectF regionToKeep = mSwipeTouchRegions.get(mCachedDisplayInfo);
|
||||
mSwipeTouchRegions.clear();
|
||||
if (regionToKeep != null) {
|
||||
mSwipeTouchRegions.put(mCurrentDisplay, regionToKeep);
|
||||
mSwipeTouchRegions.put(mCachedDisplayInfo, regionToKeep);
|
||||
updateAssistantRegions(regionToKeep);
|
||||
}
|
||||
}
|
||||
|
||||
private OrientationRectF createRegionForDisplay(Info display) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "creating rotation region for: " + mCurrentDisplay.rotation
|
||||
Log.d(TAG, "creating rotation region for: " + mCachedDisplayInfo.rotation
|
||||
+ " with mode: " + mMode + " displayRotation: " + display.rotation);
|
||||
}
|
||||
|
||||
@@ -368,7 +330,7 @@ class OrientationTouchTransformer {
|
||||
true);
|
||||
}
|
||||
} else {
|
||||
mLastRectTouched.applyTransformFromRotation(event, mCurrentDisplay.rotation,
|
||||
mLastRectTouched.applyTransformFromRotation(event, mCachedDisplayInfo.rotation,
|
||||
true);
|
||||
}
|
||||
break;
|
||||
@@ -387,7 +349,7 @@ class OrientationTouchTransformer {
|
||||
true);
|
||||
}
|
||||
} else {
|
||||
mLastRectTouched.applyTransformFromRotation(event, mCurrentDisplay.rotation,
|
||||
mLastRectTouched.applyTransformFromRotation(event, mCachedDisplayInfo.rotation,
|
||||
true);
|
||||
}
|
||||
mLastRectTouched = null;
|
||||
@@ -403,11 +365,12 @@ class OrientationTouchTransformer {
|
||||
if (rect == null) {
|
||||
continue;
|
||||
}
|
||||
if (rect.applyTransformFromRotation(event, mCurrentDisplay.rotation, false)) {
|
||||
if (rect.applyTransformFromRotation(
|
||||
event, mCachedDisplayInfo.rotation, false)) {
|
||||
mLastRectTouched = rect;
|
||||
mActiveTouchRotation = rect.getRotation();
|
||||
if (mEnableMultipleRegions
|
||||
&& mCurrentDisplay.rotation == mActiveTouchRotation) {
|
||||
&& mCachedDisplayInfo.rotation == mActiveTouchRotation) {
|
||||
// TODO(b/154580671) might make this block unnecessary
|
||||
// Start a touch session for the default nav region for the display
|
||||
mQuickStepStartingRotation = mLastRectTouched.getRotation();
|
||||
@@ -430,7 +393,7 @@ class OrientationTouchTransformer {
|
||||
pw.println(" lastTouchedRegion=" + mLastRectTouched);
|
||||
pw.println(" multipleRegionsEnabled=" + mEnableMultipleRegions);
|
||||
StringBuilder regions = new StringBuilder(" currentTouchableRotations=");
|
||||
for (CurrentDisplay key: mSwipeTouchRegions.keySet()) {
|
||||
for (CachedDisplayInfo key: mSwipeTouchRegions.keySet()) {
|
||||
OrientationRectF rectF = mSwipeTouchRegions.get(key);
|
||||
regions.append(rectF).append(" ");
|
||||
}
|
||||
|
||||
@@ -49,9 +49,9 @@ import java.util.HashMap;
|
||||
|
||||
public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAnimationListener {
|
||||
public static final boolean ENABLE_SHELL_TRANSITIONS =
|
||||
SystemProperties.getBoolean("persist.debug.shell_transit", false);
|
||||
SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
|
||||
public static final boolean SHELL_TRANSITIONS_ROTATION = ENABLE_SHELL_TRANSITIONS
|
||||
&& SystemProperties.getBoolean("persist.debug.shell_transit_rotate", false);
|
||||
&& SystemProperties.getBoolean("persist.wm.debug.shell_transit_rotate", false);
|
||||
|
||||
private RecentsAnimationController mController;
|
||||
private RecentsAnimationCallbacks mCallbacks;
|
||||
|
||||
@@ -111,7 +111,8 @@ public class FallbackRecentsStateController implements StateHandler<RecentsState
|
||||
|
||||
RecentsState currentState = mActivity.getStateManager().getState();
|
||||
if (isSplitSelectionState(state) && !isSplitSelectionState(currentState)) {
|
||||
setter.add(mRecentsView.createSplitSelectInitAnimation().buildAnim());
|
||||
setter.add(mRecentsView.createSplitSelectInitAnimation(
|
||||
state.getTransitionDuration(mActivity)).buildAnim());
|
||||
}
|
||||
|
||||
Pair<FloatProperty, FloatProperty> taskViewsFloat =
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.view.GestureDetector;
|
||||
import android.view.GestureDetector.SimpleOnGestureListener;
|
||||
import android.view.MotionEvent;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.taskbar.TaskbarActivityContext;
|
||||
import com.android.quickstep.InputConsumer;
|
||||
@@ -36,14 +37,20 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
|
||||
private final GestureDetector mLongPressDetector;
|
||||
private final float mSquaredTouchSlop;
|
||||
|
||||
|
||||
private float mDownX, mDownY;
|
||||
private boolean mCanceledUnstashHint;
|
||||
private final float mUnstashArea;
|
||||
private final float mScreenWidth;
|
||||
|
||||
public TaskbarStashInputConsumer(Context context, InputConsumer delegate,
|
||||
InputMonitorCompat inputMonitor, TaskbarActivityContext taskbarActivityContext) {
|
||||
super(delegate, inputMonitor);
|
||||
mTaskbarActivityContext = taskbarActivityContext;
|
||||
mSquaredTouchSlop = Utilities.squaredTouchSlop(context);
|
||||
mScreenWidth = context.getResources().getDisplayMetrics().widthPixels;
|
||||
mUnstashArea = context.getResources()
|
||||
.getDimensionPixelSize(R.dimen.taskbar_unstash_input_area);
|
||||
|
||||
mLongPressDetector = new GestureDetector(context, new SimpleOnGestureListener() {
|
||||
@Override
|
||||
@@ -69,11 +76,13 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
|
||||
final float y = ev.getRawY();
|
||||
switch (ev.getAction()) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mDownX = x;
|
||||
mDownY = y;
|
||||
mTaskbarActivityContext.startTaskbarUnstashHint(
|
||||
/* animateForward = */ true);
|
||||
mCanceledUnstashHint = false;
|
||||
if (isInArea(x)) {
|
||||
mDownX = x;
|
||||
mDownY = y;
|
||||
mTaskbarActivityContext.startTaskbarUnstashHint(
|
||||
/* animateForward = */ true);
|
||||
mCanceledUnstashHint = false;
|
||||
}
|
||||
break;
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (!mCanceledUnstashHint
|
||||
@@ -95,10 +104,18 @@ public class TaskbarStashInputConsumer extends DelegateInputConsumer {
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isInArea(float x) {
|
||||
float areaFromMiddle = mUnstashArea / 2.0f;
|
||||
float distFromMiddle = Math.abs(mScreenWidth / 2.0f - x);
|
||||
return distFromMiddle < areaFromMiddle;
|
||||
}
|
||||
|
||||
private void onLongPressDetected(MotionEvent motionEvent) {
|
||||
if (mTaskbarActivityContext != null
|
||||
&& mTaskbarActivityContext.onLongPressToUnstashTaskbar()) {
|
||||
setActive(motionEvent);
|
||||
if (mTaskbarActivityContext != null && isInArea(motionEvent.getRawX())) {
|
||||
boolean taskBarPressed = mTaskbarActivityContext.onLongPressToUnstashTaskbar();
|
||||
if (taskBarPressed) {
|
||||
setActive(motionEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,7 @@ import android.widget.TextView;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.quickstep.AnimatedFloat;
|
||||
@@ -110,6 +111,12 @@ public class AllSetActivity extends Activity {
|
||||
mContentView = findViewById(R.id.content_view);
|
||||
mSwipeUpShift = getResources().getDimension(R.dimen.allset_swipe_up_shift);
|
||||
|
||||
boolean isTablet = InvariantDeviceProfile.INSTANCE.get(getApplicationContext())
|
||||
.getDeviceProfile(this).isTablet;
|
||||
TextView subtitle = findViewById(R.id.subtitle);
|
||||
subtitle.setText(isTablet
|
||||
? R.string.allset_description_tablet : R.string.allset_description);
|
||||
|
||||
TextView tv = findViewById(R.id.navigation_settings);
|
||||
tv.setTextColor(accentColor);
|
||||
tv.setOnClickListener(v -> {
|
||||
|
||||
@@ -57,14 +57,14 @@ final class BackGestureTutorialController extends TutorialController {
|
||||
@LayoutRes
|
||||
int getMockAppTaskCurrentPageLayoutResId() {
|
||||
return mTutorialFragment.isLargeScreen()
|
||||
? R.layout.gesture_tutorial_foldable_mock_conversation
|
||||
? R.layout.gesture_tutorial_tablet_mock_conversation
|
||||
: R.layout.gesture_tutorial_mock_conversation;
|
||||
}
|
||||
|
||||
@LayoutRes
|
||||
int getMockAppTaskPreviousPageLayoutResId() {
|
||||
return mTutorialFragment.isLargeScreen()
|
||||
? R.layout.gesture_tutorial_foldable_mock_conversation_list
|
||||
? R.layout.gesture_tutorial_tablet_mock_conversation_list
|
||||
: R.layout.gesture_tutorial_mock_conversation_list;
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ final class HomeGestureTutorialController extends SwipeUpGestureTutorialControll
|
||||
@Override
|
||||
protected int getMockAppTaskLayoutResId() {
|
||||
return mTutorialFragment.isLargeScreen()
|
||||
? R.layout.gesture_tutorial_foldable_mock_webpage
|
||||
? R.layout.gesture_tutorial_tablet_mock_webpage
|
||||
: R.layout.gesture_tutorial_mock_webpage;
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ final class OverviewGestureTutorialController extends SwipeUpGestureTutorialCont
|
||||
@Override
|
||||
protected int getMockAppTaskLayoutResId() {
|
||||
return mTutorialFragment.isLargeScreen()
|
||||
? R.layout.gesture_tutorial_foldable_mock_conversation_list
|
||||
? R.layout.gesture_tutorial_tablet_mock_conversation_list
|
||||
: R.layout.gesture_tutorial_mock_conversation_list;
|
||||
}
|
||||
|
||||
|
||||
+10
-2
@@ -280,6 +280,15 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
super(context, deviceState, gestureState);
|
||||
mRemoteTargetHandles[0] = new RemoteTargetGluer.RemoteTargetHandle(
|
||||
mRemoteTargetHandles[0].getTaskViewSimulator(), new FakeTransformParams());
|
||||
|
||||
for (RemoteTargetGluer.RemoteTargetHandle handle
|
||||
: mTargetGluer.getRemoteTargetHandles()) {
|
||||
// Override home screen rotation preference so that home and overview animations
|
||||
// work properly
|
||||
handle.getTaskViewSimulator()
|
||||
.getOrientationState()
|
||||
.ignoreAllowHomeRotationPreference();
|
||||
}
|
||||
}
|
||||
|
||||
void initDp(DeviceProfile dp) {
|
||||
@@ -336,8 +345,7 @@ abstract class SwipeUpGestureTutorialController extends TutorialController {
|
||||
1f - SHAPE_PROGRESS_DURATION /* shapeProgressStart */,
|
||||
radius, 255,
|
||||
false, /* isOpening */
|
||||
mFakeIconView, mDp,
|
||||
false /* isVerticalBarLayout */);
|
||||
mFakeIconView, mDp);
|
||||
mFakeIconView.setAlpha(1);
|
||||
mFakeTaskView.setAlpha(getWindowAlpha(progress));
|
||||
mFakePreviousTaskView.setAlpha(getWindowAlpha(progress));
|
||||
|
||||
@@ -49,6 +49,7 @@ import androidx.annotation.StringRes;
|
||||
import androidx.appcompat.app.AlertDialog;
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.AnimatorListeners;
|
||||
@@ -73,7 +74,7 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
private static final int FEEDBACK_ANIMATION_MS = 133;
|
||||
private static final int RIPPLE_VISIBLE_MS = 300;
|
||||
private static final int GESTURE_ANIMATION_DELAY_MS = 1500;
|
||||
private static final int ADVANCE_TUTORIAL_TIMEOUT_MS = 4000;
|
||||
private static final int ADVANCE_TUTORIAL_TIMEOUT_MS = 2000;
|
||||
private static final long GESTURE_ANIMATION_PAUSE_DURATION_MILLIS = 1000;
|
||||
|
||||
final TutorialFragment mTutorialFragment;
|
||||
@@ -185,7 +186,9 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
@LayoutRes
|
||||
protected int getMockHotseatResId() {
|
||||
return mTutorialFragment.isLargeScreen()
|
||||
? R.layout.gesture_tutorial_foldable_mock_hotseat
|
||||
? (mTutorialFragment.isFoldable()
|
||||
? R.layout.gesture_tutorial_foldable_mock_hotseat
|
||||
: R.layout.gesture_tutorial_tablet_mock_hotseat)
|
||||
: R.layout.gesture_tutorial_mock_hotseat;
|
||||
}
|
||||
|
||||
@@ -319,6 +322,9 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
}
|
||||
|
||||
void hideFeedback() {
|
||||
if (mFeedbackView.getVisibility() != View.VISIBLE) {
|
||||
return;
|
||||
}
|
||||
cancelQueuedGestureAnimation();
|
||||
mFeedbackView.clearAnimation();
|
||||
mFeedbackView.setVisibility(View.INVISIBLE);
|
||||
@@ -515,20 +521,45 @@ abstract class TutorialController implements BackGestureAttemptCallback,
|
||||
}
|
||||
|
||||
private void updateLayout() {
|
||||
if (mContext != null) {
|
||||
RelativeLayout.LayoutParams feedbackLayoutParams =
|
||||
(RelativeLayout.LayoutParams) mFeedbackView.getLayoutParams();
|
||||
feedbackLayoutParams.setMarginStart(mContext.getResources().getDimensionPixelSize(
|
||||
mTutorialFragment.isLargeScreen()
|
||||
? R.dimen.gesture_tutorial_foldable_feedback_margin_start_end
|
||||
: R.dimen.gesture_tutorial_feedback_margin_start_end));
|
||||
feedbackLayoutParams.setMarginEnd(mContext.getResources().getDimensionPixelSize(
|
||||
mTutorialFragment.isLargeScreen()
|
||||
? R.dimen.gesture_tutorial_foldable_feedback_margin_start_end
|
||||
: R.dimen.gesture_tutorial_feedback_margin_start_end));
|
||||
|
||||
mFakeTaskbarView.setVisibility(mTutorialFragment.isLargeScreen() ? View.VISIBLE : GONE);
|
||||
if (mContext == null) {
|
||||
return;
|
||||
}
|
||||
RelativeLayout.LayoutParams feedbackLayoutParams =
|
||||
(RelativeLayout.LayoutParams) mFeedbackView.getLayoutParams();
|
||||
feedbackLayoutParams.setMarginStart(mContext.getResources().getDimensionPixelSize(
|
||||
mTutorialFragment.isLargeScreen()
|
||||
? R.dimen.gesture_tutorial_tablet_feedback_margin_start_end
|
||||
: R.dimen.gesture_tutorial_feedback_margin_start_end));
|
||||
feedbackLayoutParams.setMarginEnd(mContext.getResources().getDimensionPixelSize(
|
||||
mTutorialFragment.isLargeScreen()
|
||||
? R.dimen.gesture_tutorial_tablet_feedback_margin_start_end
|
||||
: R.dimen.gesture_tutorial_feedback_margin_start_end));
|
||||
feedbackLayoutParams.topMargin = mContext.getResources().getDimensionPixelSize(
|
||||
mTutorialFragment.isLargeScreen()
|
||||
? R.dimen.gesture_tutorial_tablet_feedback_margin_top
|
||||
: R.dimen.gesture_tutorial_feedback_margin_top);
|
||||
|
||||
mFakeTaskbarView.setVisibility(mTutorialFragment.isLargeScreen() ? View.VISIBLE : GONE);
|
||||
|
||||
RelativeLayout.LayoutParams hotseatLayoutParams =
|
||||
(RelativeLayout.LayoutParams) mFakeHotseatView.getLayoutParams();
|
||||
if (!mTutorialFragment.isLargeScreen()) {
|
||||
DeviceProfile dp = mTutorialFragment.getDeviceProfile();
|
||||
dp.updateIsSeascape(mContext);
|
||||
|
||||
hotseatLayoutParams.addRule(dp.isLandscape
|
||||
? (dp.isSeascape()
|
||||
? RelativeLayout.ALIGN_PARENT_START
|
||||
: RelativeLayout.ALIGN_PARENT_END)
|
||||
: RelativeLayout.ALIGN_PARENT_BOTTOM);
|
||||
} else {
|
||||
hotseatLayoutParams.width = RelativeLayout.LayoutParams.MATCH_PARENT;
|
||||
hotseatLayoutParams.height = RelativeLayout.LayoutParams.WRAP_CONTENT;
|
||||
hotseatLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
|
||||
hotseatLayoutParams.removeRule(RelativeLayout.ALIGN_PARENT_START);
|
||||
hotseatLayoutParams.removeRule(RelativeLayout.ALIGN_PARENT_END);
|
||||
}
|
||||
mFakeHotseatView.setLayoutParams(hotseatLayoutParams);
|
||||
}
|
||||
|
||||
private AlertDialog createSkipTutorialDialog() {
|
||||
|
||||
@@ -20,7 +20,6 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.drawable.Animatable2;
|
||||
import android.graphics.drawable.AnimatedVectorDrawable;
|
||||
@@ -41,6 +40,7 @@ import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.InvariantDeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.quickstep.interaction.TutorialController.TutorialType;
|
||||
@@ -67,7 +67,9 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
|
||||
|
||||
private boolean mFragmentStopped = false;
|
||||
|
||||
private DeviceProfile mDeviceProfile;
|
||||
private boolean mIsLargeScreen;
|
||||
private boolean mIsFoldable;
|
||||
|
||||
public static TutorialFragment newInstance(TutorialType tutorialType, boolean gestureComplete) {
|
||||
TutorialFragment fragment = getFragmentForTutorialType(tutorialType);
|
||||
@@ -139,22 +141,24 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
|
||||
mEdgeBackGestureHandler = new EdgeBackGestureHandler(getContext());
|
||||
mNavBarGestureHandler = new NavBarGestureHandler(getContext());
|
||||
|
||||
mIsLargeScreen = InvariantDeviceProfile.INSTANCE.get(getContext())
|
||||
.getDeviceProfile(getContext()).isTablet;
|
||||
|
||||
if (mIsLargeScreen) {
|
||||
((Activity) getContext()).setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_USER);
|
||||
} else {
|
||||
// Temporary until UI mocks for landscape mode for phones are created.
|
||||
((Activity) getContext()).setRequestedOrientation(
|
||||
ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
|
||||
}
|
||||
mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(getContext())
|
||||
.getDeviceProfile(getContext());
|
||||
mIsLargeScreen = mDeviceProfile.isTablet;
|
||||
mIsFoldable = mDeviceProfile.isTwoPanels;
|
||||
}
|
||||
|
||||
public boolean isLargeScreen() {
|
||||
return mIsLargeScreen;
|
||||
}
|
||||
|
||||
public boolean isFoldable() {
|
||||
return mIsFoldable;
|
||||
}
|
||||
|
||||
DeviceProfile getDeviceProfile() {
|
||||
return mDeviceProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
@@ -296,6 +300,9 @@ abstract class TutorialFragment extends Fragment implements OnTouchListener {
|
||||
|
||||
@Override
|
||||
public boolean onTouch(View view, MotionEvent motionEvent) {
|
||||
if (mTutorialController != null) {
|
||||
mTutorialController.hideFeedback();
|
||||
}
|
||||
// Note: Using logical-or to ensure both functions get called.
|
||||
return mEdgeBackGestureHandler.onTouch(view, motionEvent)
|
||||
| mNavBarGestureHandler.onTouch(view, motionEvent);
|
||||
|
||||
@@ -23,7 +23,6 @@ import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import androidx.appcompat.content.res.AppCompatResources;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
@@ -87,8 +86,10 @@ public class TutorialStepIndicator extends LinearLayout {
|
||||
for (int i = mTotalSteps; i < getChildCount(); i++) {
|
||||
removeViewAt(i);
|
||||
}
|
||||
int stepIndicatorColor = GraphicsUtils.getAttrColor(
|
||||
int activeStepIndicatorColor = GraphicsUtils.getAttrColor(
|
||||
getContext(), android.R.attr.textColorPrimary);
|
||||
int inactiveStepIndicatorColor = GraphicsUtils.getAttrColor(
|
||||
getContext(), android.R.attr.textColorSecondaryInverse);
|
||||
for (int i = 0; i < mTotalSteps; i++) {
|
||||
Drawable pageIndicatorPillDrawable = AppCompatResources.getDrawable(
|
||||
getContext(), R.drawable.tutorial_step_indicator_pill);
|
||||
@@ -107,10 +108,9 @@ public class TutorialStepIndicator extends LinearLayout {
|
||||
}
|
||||
if (pageIndicatorPillDrawable != null) {
|
||||
if (i < mCurrentStep) {
|
||||
pageIndicatorPillDrawable.setTint(stepIndicatorColor);
|
||||
pageIndicatorPillDrawable.setTint(activeStepIndicatorColor);
|
||||
} else {
|
||||
pageIndicatorPillDrawable.setTint(
|
||||
ColorUtils.setAlphaComponent(stepIndicatorColor, 0x22));
|
||||
pageIndicatorPillDrawable.setTint(inactiveStepIndicatorColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ package com.android.quickstep.logging;
|
||||
import static androidx.core.util.Preconditions.checkNotNull;
|
||||
import static androidx.core.util.Preconditions.checkState;
|
||||
|
||||
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_NON_ACTIONABLE;
|
||||
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS;
|
||||
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.FOLDER;
|
||||
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.SEARCH_RESULT_CONTAINER;
|
||||
@@ -82,6 +83,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
|
||||
public class StatsLogCompatManager extends StatsLogManager {
|
||||
|
||||
private static final String TAG = "StatsLog";
|
||||
private static final String LATENCY_TAG = "StatsLatencyLog";
|
||||
private static final boolean IS_VERBOSE = Utilities.isPropertyEnabled(LogConfig.STATSLOG);
|
||||
private static final InstanceId DEFAULT_INSTANCE_ID = InstanceId.fakeInstanceId(0);
|
||||
// LauncherAtom.ItemInfo.getDefaultInstance() should be used but until launcher proto migrates
|
||||
@@ -196,7 +198,9 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
private static class StatsCompatLogger implements StatsLogger {
|
||||
|
||||
private static final ItemInfo DEFAULT_ITEM_INFO = new ItemInfo();
|
||||
|
||||
static {
|
||||
DEFAULT_ITEM_INFO.itemType = ITEM_TYPE_NON_ACTIONABLE;
|
||||
}
|
||||
private final Context mContext;
|
||||
private final Optional<ActivityContext> mActivityContext;
|
||||
private ItemInfo mItemInfo = DEFAULT_ITEM_INFO;
|
||||
@@ -388,13 +392,21 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
if (IS_VERBOSE) {
|
||||
String name = (event instanceof Enum) ? ((Enum) event).name() :
|
||||
event.getId() + "";
|
||||
|
||||
Log.d(TAG, instanceId == DEFAULT_INSTANCE_ID
|
||||
? String.format("\n%s (State:%s->%s)\n%s", name, getStateString(srcState),
|
||||
getStateString(dstState), atomInfo)
|
||||
: String.format("\n%s (State:%s->%s) (InstanceId:%s)\n%s", name,
|
||||
getStateString(srcState), getStateString(dstState), instanceId,
|
||||
atomInfo));
|
||||
StringBuilder logStringBuilder = new StringBuilder("\n");
|
||||
if (instanceId != DEFAULT_INSTANCE_ID) {
|
||||
logStringBuilder.append(String.format("InstanceId:%s ", instanceId));
|
||||
}
|
||||
logStringBuilder.append(name);
|
||||
if (srcState != LAUNCHER_STATE_UNSPECIFIED
|
||||
|| dstState != LAUNCHER_STATE_UNSPECIFIED) {
|
||||
logStringBuilder.append(
|
||||
String.format("(State:%s->%s)", getStateString(srcState),
|
||||
getStateString(dstState)));
|
||||
}
|
||||
if (mItemInfo != DEFAULT_ITEM_INFO) {
|
||||
logStringBuilder.append("\n").append(atomInfo);
|
||||
}
|
||||
Log.d(TAG, logStringBuilder.toString());
|
||||
}
|
||||
|
||||
for (StatsLogConsumer consumer : LOGS_CONSUMER) {
|
||||
@@ -479,11 +491,12 @@ public class StatsLogCompatManager extends StatsLogManager {
|
||||
if (IS_VERBOSE) {
|
||||
String name = (event instanceof Enum) ? ((Enum) event).name() :
|
||||
event.getId() + "";
|
||||
|
||||
Log.d(TAG, mInstanceId == DEFAULT_INSTANCE_ID
|
||||
? String.format("\n%s = %dms\n", name, mLatencyInMillis)
|
||||
: String.format("\n%s = %dms (InstanceId:%s)\n", name,
|
||||
mLatencyInMillis, mInstanceId));
|
||||
StringBuilder logStringBuilder = new StringBuilder("\n");
|
||||
if (mInstanceId != DEFAULT_INSTANCE_ID) {
|
||||
logStringBuilder.append(String.format("InstanceId:%s ", mInstanceId));
|
||||
}
|
||||
logStringBuilder.append(String.format("%s=%sms", name, mLatencyInMillis));
|
||||
Log.d(LATENCY_TAG, logStringBuilder.toString());
|
||||
}
|
||||
|
||||
SysUiStatsLog.write(SysUiStatsLog.LAUNCHER_LATENCY,
|
||||
|
||||
@@ -48,10 +48,10 @@ import androidx.annotation.WorkerThread;
|
||||
import androidx.core.content.FileProvider;
|
||||
|
||||
import com.android.internal.app.ChooserActivity;
|
||||
import com.android.internal.util.ScreenshotHelper;
|
||||
import com.android.launcher3.BuildConfig;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
import com.android.systemui.shared.recents.utilities.BitmapUtil;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
@@ -77,7 +77,8 @@ public class ImageActionUtils {
|
||||
public static void saveScreenshot(SystemUiProxy systemUiProxy, Bitmap screenshot,
|
||||
Rect screenshotBounds,
|
||||
Insets visibleInsets, Task.TaskKey task) {
|
||||
systemUiProxy.handleImageBundleAsScreenshot(BitmapUtil.hardwareBitmapToBundle(screenshot),
|
||||
systemUiProxy.handleImageBundleAsScreenshot(
|
||||
ScreenshotHelper.HardwareBitmapBundler.hardwareBitmapToBundle(screenshot),
|
||||
screenshotBounds, visibleInsets, task);
|
||||
}
|
||||
|
||||
|
||||
@@ -102,6 +102,8 @@ public class RecentsOrientedState implements
|
||||
// Whether the swipe gesture is running, so the recents would stay locked in the
|
||||
// current orientation
|
||||
private static final int FLAG_SWIPE_UP_NOT_RUNNING = 1 << 8;
|
||||
// Ignore shared prefs for home rotation rotation, allowing it in if the activity supports it
|
||||
private static final int FLAG_IGNORE_ALLOW_HOME_ROTATION_PREF = 1 << 9;
|
||||
|
||||
private static final int MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE =
|
||||
FLAG_MULTIPLE_ORIENTATION_SUPPORTED_BY_ACTIVITY
|
||||
@@ -371,12 +373,17 @@ public class RecentsOrientedState implements
|
||||
== MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE;
|
||||
}
|
||||
|
||||
public void ignoreAllowHomeRotationPreference() {
|
||||
setFlag(FLAG_IGNORE_ALLOW_HOME_ROTATION_PREF, true);
|
||||
}
|
||||
|
||||
public boolean isRecentsActivityRotationAllowed() {
|
||||
// Activity rotation is allowed if the multi-simulated-rotation is not supported
|
||||
// (fallback recents or tablets) or activity rotation is enabled by various settings.
|
||||
return ((mFlags & MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE)
|
||||
!= MASK_MULTIPLE_ORIENTATION_SUPPORTED_BY_DEVICE)
|
||||
|| (mFlags & (FLAG_HOME_ROTATION_ALLOWED_IN_PREFS
|
||||
|| (mFlags & (FLAG_IGNORE_ALLOW_HOME_ROTATION_PREF
|
||||
| FLAG_HOME_ROTATION_ALLOWED_IN_PREFS
|
||||
| FLAG_MULTIWINDOW_ROTATION_ALLOWED
|
||||
| FLAG_HOME_ROTATION_FORCE_ENABLED_FOR_TESTING)) != 0;
|
||||
}
|
||||
@@ -599,7 +606,7 @@ public class RecentsOrientedState implements
|
||||
width = Math.min(currentSize.x, currentSize.y);
|
||||
height = Math.max(currentSize.x, currentSize.y);
|
||||
}
|
||||
return idp.getBestMatch(width, height);
|
||||
return idp.getBestMatch(width, height, mRecentsActivityRotation);
|
||||
}
|
||||
|
||||
private static String nameAndAddress(Object obj) {
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.Display;
|
||||
|
||||
import com.android.launcher3.util.window.WindowManagerProxy;
|
||||
|
||||
/**
|
||||
* Extension of {@link WindowManagerProxy} with some assumption for the default system Launcher
|
||||
*/
|
||||
public class SystemWindowManagerProxy extends WindowManagerProxy {
|
||||
|
||||
public SystemWindowManagerProxy(Context context) {
|
||||
super(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplayId(Display display) {
|
||||
return display.getUniqueId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInternalDisplay(Display display) {
|
||||
return display.getType() == Display.TYPE_INTERNAL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getRotation(Context context) {
|
||||
return context.getResources().getConfiguration().windowConfiguration.getRotation();
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,6 @@ import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRES
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.QuickstepTransitionManager.RECENTS_LAUNCH_DURATION;
|
||||
import static com.android.launcher3.QuickstepTransitionManager.SPLIT_LAUNCH_DURATION;
|
||||
import static com.android.launcher3.Utilities.EDGE_NAV_BAR;
|
||||
import static com.android.launcher3.Utilities.mapToRange;
|
||||
import static com.android.launcher3.Utilities.squaredHypot;
|
||||
@@ -45,7 +44,6 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_DISMISS_SWIPE_UP;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASK_LAUNCH_SWIPE_DOWN;
|
||||
import static com.android.launcher3.statehandlers.DepthController.DEPTH;
|
||||
import static com.android.launcher3.testing.TestProtocol.TASK_VIEW_ID_CRASH;
|
||||
import static com.android.launcher3.touch.PagedOrientationHandler.CANVAS_TRANSLATE;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
|
||||
@@ -2282,8 +2280,6 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
* Sets the running task id, cleaning up the old running task if necessary.
|
||||
*/
|
||||
public void setCurrentTask(int runningTaskViewId) {
|
||||
Log.d(TASK_VIEW_ID_CRASH, "currentRunningTaskViewId: " + mRunningTaskViewId
|
||||
+ " requestedTaskViewId: " + runningTaskViewId);
|
||||
if (mRunningTaskViewId == runningTaskViewId) {
|
||||
return;
|
||||
}
|
||||
@@ -3987,14 +3983,12 @@ public abstract class RecentsView<ACTIVITY_TYPE extends StatefulActivity<STATE_T
|
||||
splitSelectSource.position.stagePosition);
|
||||
}
|
||||
|
||||
public PendingAnimation createSplitSelectInitAnimation() {
|
||||
public PendingAnimation createSplitSelectInitAnimation(int duration) {
|
||||
if (mSplitHiddenTaskView != null) {
|
||||
int duration = mActivity.getStateManager().getState().getTransitionDuration(
|
||||
getContext());
|
||||
return createTaskDismissAnimation(mSplitHiddenTaskView, true, false, duration,
|
||||
true /* dismissingForSplitSelection*/);
|
||||
} else {
|
||||
PendingAnimation anim = new PendingAnimation(SPLIT_LAUNCH_DURATION);
|
||||
PendingAnimation anim = new PendingAnimation(duration);
|
||||
createInitialSplitSelectAnimation(anim);
|
||||
return anim;
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@ import org.junit.rules.TestRule;
|
||||
*/
|
||||
public abstract class AbstractQuickStepTest extends AbstractLauncherUiTest {
|
||||
static final boolean ENABLE_SHELL_TRANSITIONS =
|
||||
SystemProperties.getBoolean("persist.debug.shell_transit", false);
|
||||
SystemProperties.getBoolean("persist.wm.debug.shell_transit", false);
|
||||
@Override
|
||||
protected TestRule getRulesInsideActivityMonitor() {
|
||||
return RuleChain.
|
||||
|
||||
@@ -15,16 +15,15 @@
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import static android.view.Display.DEFAULT_DISPLAY;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.doAnswer;
|
||||
import static org.mockito.Mockito.doReturn;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Pair;
|
||||
import android.view.Display;
|
||||
import android.view.Surface;
|
||||
import android.view.SurfaceControl;
|
||||
@@ -38,6 +37,10 @@ import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.DisplayController.Info;
|
||||
import com.android.launcher3.util.LauncherModelHelper;
|
||||
import com.android.launcher3.util.ReflectionHelpers;
|
||||
import com.android.launcher3.util.RotationUtils;
|
||||
import com.android.launcher3.util.WindowBounds;
|
||||
import com.android.launcher3.util.window.CachedDisplayInfo;
|
||||
import com.android.launcher3.util.window.WindowManagerProxy;
|
||||
import com.android.quickstep.FallbackActivityInterface;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
|
||||
@@ -142,29 +145,34 @@ public class TaskViewSimulatorTest {
|
||||
LauncherModelHelper helper = new LauncherModelHelper();
|
||||
try {
|
||||
helper.sandboxContext.allow(SystemUiProxy.INSTANCE);
|
||||
int rotation = mDisplaySize.x > mDisplaySize.y
|
||||
? Surface.ROTATION_90 : Surface.ROTATION_0;
|
||||
CachedDisplayInfo cdi =
|
||||
new CachedDisplayInfo("test-display", mDisplaySize, rotation , new Rect());
|
||||
WindowBounds wm = new WindowBounds(
|
||||
new Rect(0, 0, mDisplaySize.x, mDisplaySize.y),
|
||||
mDisplayInsets);
|
||||
WindowBounds[] allBounds = new WindowBounds[4];
|
||||
for (int i = 0; i < 4; i++) {
|
||||
Rect boundsR = new Rect(wm.bounds);
|
||||
Rect insetsR = new Rect(wm.insets);
|
||||
|
||||
Display display = mock(Display.class);
|
||||
doReturn(DEFAULT_DISPLAY).when(display).getDisplayId();
|
||||
doReturn(mDisplaySize.x > mDisplaySize.y ? Surface.ROTATION_90 : Surface.ROTATION_0)
|
||||
.when(display).getRotation();
|
||||
doAnswer(i -> {
|
||||
((Point) i.getArgument(0)).set(mDisplaySize.x, mDisplaySize.y);
|
||||
return null;
|
||||
}).when(display).getRealSize(any());
|
||||
doAnswer(i -> {
|
||||
Point smallestSize = i.getArgument(0);
|
||||
Point largestSize = i.getArgument(1);
|
||||
smallestSize.x = smallestSize.y = Math.min(mDisplaySize.x, mDisplaySize.y);
|
||||
largestSize.x = largestSize.y = Math.max(mDisplaySize.x, mDisplaySize.y);
|
||||
RotationUtils.rotateRect(insetsR, RotationUtils.deltaRotation(rotation, i));
|
||||
RotationUtils.rotateRect(boundsR, RotationUtils.deltaRotation(rotation, i));
|
||||
boundsR.set(0, 0, Math.abs(boundsR.width()), Math.abs(boundsR.height()));
|
||||
allBounds[i] = new WindowBounds(boundsR, insetsR);
|
||||
}
|
||||
|
||||
smallestSize.x -= mDisplayInsets.left + mDisplayInsets.right;
|
||||
largestSize.x -= mDisplayInsets.left + mDisplayInsets.right;
|
||||
WindowManagerProxy wmProxy = mock(WindowManagerProxy.class);
|
||||
doReturn(cdi).when(wmProxy).getDisplayInfo(any());
|
||||
doReturn(wm).when(wmProxy).getRealBounds(any(), any(), any());
|
||||
|
||||
smallestSize.y -= mDisplayInsets.top + mDisplayInsets.bottom;
|
||||
largestSize.y -= mDisplayInsets.top + mDisplayInsets.bottom;
|
||||
return null;
|
||||
}).when(display).getCurrentSizeRange(any(), any());
|
||||
DisplayController.Info mockInfo = new Info(helper.sandboxContext, display);
|
||||
ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> perDisplayBoundsCache =
|
||||
new ArrayMap<>();
|
||||
perDisplayBoundsCache.put(cdi.id, Pair.create(cdi.normalize(), allBounds));
|
||||
|
||||
DisplayController.Info mockInfo = new Info(
|
||||
helper.sandboxContext, mock(Display.class), wmProxy, perDisplayBoundsCache);
|
||||
|
||||
DisplayController controller =
|
||||
DisplayController.INSTANCE.get(helper.sandboxContext);
|
||||
@@ -172,7 +180,7 @@ public class TaskViewSimulatorTest {
|
||||
ReflectionHelpers.setField(controller, "mInfo", mockInfo);
|
||||
|
||||
mDeviceProfile = InvariantDeviceProfile.INSTANCE.get(helper.sandboxContext)
|
||||
.getBestMatch(mAppBounds.width(), mAppBounds.height());
|
||||
.getBestMatch(mAppBounds.width(), mAppBounds.height(), rotation);
|
||||
mDeviceProfile.updateInsets(mLauncherInsets);
|
||||
|
||||
TaskViewSimulator tvs = new TaskViewSimulator(helper.sandboxContext,
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
<string name="test_information_handler_class" translatable="false"></string>
|
||||
<string name="launcher_activity_logic_class" translatable="false"></string>
|
||||
<string name="model_delegate_class" translatable="false"></string>
|
||||
<string name="window_manager_proxy_class" translatable="false"></string>
|
||||
|
||||
<!-- View ID to use for QSB widget -->
|
||||
<item type="id" name="qsb_widget" />
|
||||
|
||||
@@ -29,7 +29,6 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.LauncherApps;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -41,8 +40,6 @@ import android.util.Log;
|
||||
import android.view.ActionMode;
|
||||
import android.view.Display;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets.Type;
|
||||
import android.view.WindowMetrics;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
@@ -322,11 +319,7 @@ public abstract class BaseDraggingActivity extends BaseActivity
|
||||
|
||||
protected WindowBounds getMultiWindowDisplaySize() {
|
||||
if (Utilities.ATLEAST_R) {
|
||||
WindowMetrics wm = getWindowManager().getCurrentWindowMetrics();
|
||||
|
||||
Insets insets = wm.getWindowInsets().getInsets(Type.systemBars());
|
||||
return new WindowBounds(wm.getBounds(),
|
||||
new Rect(insets.left, insets.top, insets.right, insets.bottom));
|
||||
return WindowBounds.fromWindowMetrics(getWindowManager().getCurrentWindowMetrics());
|
||||
}
|
||||
// Note: Calls to getSize() can't rely on our cached DefaultDisplay since it can return
|
||||
// the app window size
|
||||
|
||||
@@ -75,6 +75,7 @@ public class DeviceProfile {
|
||||
public final int heightPx;
|
||||
public final int availableWidthPx;
|
||||
public final int availableHeightPx;
|
||||
public final int rotationHint;
|
||||
|
||||
public final float aspectRatio;
|
||||
|
||||
@@ -239,6 +240,7 @@ public class DeviceProfile {
|
||||
this.isGestureMode = isGestureMode;
|
||||
windowX = windowBounds.bounds.left;
|
||||
windowY = windowBounds.bounds.top;
|
||||
this.rotationHint = windowBounds.rotationHint;
|
||||
|
||||
isScalableGrid = inv.isScalable && !isVerticalBarLayout() && !isMultiWindowMode;
|
||||
|
||||
@@ -346,9 +348,14 @@ public class DeviceProfile {
|
||||
workspaceCellPaddingXPx = res.getDimensionPixelSize(R.dimen.dynamic_grid_cell_padding_x);
|
||||
|
||||
hotseatQsbHeight = res.getDimensionPixelSize(R.dimen.qsb_widget_height);
|
||||
isQsbInline = isLargeTablet && isLandscape && hotseatQsbHeight > 0;
|
||||
// Whether QSB might be inline in appropriate orientation (landscape).
|
||||
boolean canQsbInline = isLargeTablet && hotseatQsbHeight > 0;
|
||||
isQsbInline = canQsbInline && isLandscape;
|
||||
|
||||
if (isTaskbarPresent && !isGestureMode && isQsbInline) {
|
||||
// We shrink hotseat sizes regardless of orientation, if nav buttons are inline and QSB
|
||||
// might be inline in either orientations, to keep hotseat size consistent across rotation.
|
||||
boolean areNavButtonsInline = isTaskbarPresent && !isGestureMode;
|
||||
if (areNavButtonsInline && canQsbInline) {
|
||||
numShownHotseatIcons = inv.numShrunkenHotseatIcons;
|
||||
} else {
|
||||
numShownHotseatIcons =
|
||||
@@ -543,8 +550,8 @@ public class DeviceProfile {
|
||||
}
|
||||
|
||||
public Builder toBuilder(Context context) {
|
||||
WindowBounds bounds =
|
||||
new WindowBounds(widthPx, heightPx, availableWidthPx, availableHeightPx);
|
||||
WindowBounds bounds = new WindowBounds(
|
||||
widthPx, heightPx, availableWidthPx, availableHeightPx, rotationHint);
|
||||
bounds.bounds.offsetTo(windowX, windowY);
|
||||
return new Builder(context, inv, mInfo)
|
||||
.setWindowBounds(bounds)
|
||||
|
||||
@@ -55,6 +55,7 @@ import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.Themes;
|
||||
import com.android.launcher3.util.WindowBounds;
|
||||
import com.android.launcher3.util.window.WindowManagerProxy;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
@@ -180,8 +181,7 @@ public class InvariantDeviceProfile {
|
||||
private final ArrayList<OnIDPChangeListener> mChangeListeners = new ArrayList<>();
|
||||
|
||||
@VisibleForTesting
|
||||
public InvariantDeviceProfile() {
|
||||
}
|
||||
public InvariantDeviceProfile() { }
|
||||
|
||||
@TargetApi(23)
|
||||
private InvariantDeviceProfile(Context context) {
|
||||
@@ -278,11 +278,16 @@ public class InvariantDeviceProfile {
|
||||
}
|
||||
|
||||
private static @DeviceType int getDeviceType(Info displayInfo) {
|
||||
// Each screen has two profiles (portrait/landscape), so devices with four or more
|
||||
// supported profiles implies two or more internal displays.
|
||||
if (displayInfo.supportedBounds.size() >= 4 && ENABLE_TWO_PANEL_HOME.get()) {
|
||||
int flagPhone = 1 << 0;
|
||||
int flagTablet = 1 << 1;
|
||||
|
||||
int type = displayInfo.supportedBounds.stream()
|
||||
.mapToInt(bounds -> displayInfo.isTablet(bounds) ? flagTablet : flagPhone)
|
||||
.reduce(0, (a, b) -> a | b);
|
||||
if ((type == (flagPhone | flagTablet)) && ENABLE_TWO_PANEL_HOME.get()) {
|
||||
// device has profiles supporting both phone and table modes
|
||||
return TYPE_MULTI_DISPLAY;
|
||||
} else if (displayInfo.supportedBounds.stream().allMatch(displayInfo::isTablet)) {
|
||||
} else if (type == flagTablet) {
|
||||
return TYPE_TABLET;
|
||||
} else {
|
||||
return TYPE_PHONE;
|
||||
@@ -613,10 +618,14 @@ public class InvariantDeviceProfile {
|
||||
|
||||
float screenWidth = config.screenWidthDp * res.getDisplayMetrics().density;
|
||||
float screenHeight = config.screenHeightDp * res.getDisplayMetrics().density;
|
||||
return getBestMatch(screenWidth, screenHeight);
|
||||
return getBestMatch(screenWidth, screenHeight,
|
||||
WindowManagerProxy.INSTANCE.get(context).getRotation(context));
|
||||
}
|
||||
|
||||
public DeviceProfile getBestMatch(float screenWidth, float screenHeight) {
|
||||
/**
|
||||
* Returns the device profile matching the provided screen configuration
|
||||
*/
|
||||
public DeviceProfile getBestMatch(float screenWidth, float screenHeight, int rotation) {
|
||||
DeviceProfile bestMatch = supportedProfiles.get(0);
|
||||
float minDiff = Float.MAX_VALUE;
|
||||
|
||||
@@ -626,6 +635,8 @@ public class InvariantDeviceProfile {
|
||||
if (diff < minDiff) {
|
||||
minDiff = diff;
|
||||
bestMatch = profile;
|
||||
} else if (diff == minDiff && profile.rotationHint == rotation) {
|
||||
bestMatch = profile;
|
||||
}
|
||||
}
|
||||
return bestMatch;
|
||||
|
||||
@@ -228,6 +228,7 @@ import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
@@ -1108,21 +1109,23 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
&& mAllAppsSessionLogId == null) {
|
||||
// creates new instance ID since new all apps session is started.
|
||||
mAllAppsSessionLogId = new InstanceIdSequence().newInstanceId();
|
||||
getStatsLogManager().logger().withContainerInfo(
|
||||
ContainerInfo.newBuilder().setWorkspace(
|
||||
WorkspaceContainer.newBuilder().setPageIndex(
|
||||
getWorkspace().getCurrentPage())).build())
|
||||
.log(getAllAppsEntryEvent());
|
||||
if (getAllAppsEntryEvent().isPresent()) {
|
||||
getStatsLogManager().logger()
|
||||
.withContainerInfo(ContainerInfo.newBuilder()
|
||||
.setWorkspace(WorkspaceContainer.newBuilder()
|
||||
.setPageIndex(getWorkspace().getCurrentPage())).build())
|
||||
.log(getAllAppsEntryEvent().get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link EventEnum} that should be logged when Launcher enters into AllApps state.
|
||||
*/
|
||||
protected EventEnum getAllAppsEntryEvent() {
|
||||
return FeatureFlags.ENABLE_DEVICE_SEARCH.get()
|
||||
protected Optional<EventEnum> getAllAppsEntryEvent() {
|
||||
return Optional.of(FeatureFlags.ENABLE_DEVICE_SEARCH.get()
|
||||
? LAUNCHER_ALLAPPS_ENTRY_WITH_DEVICE_SEARCH
|
||||
: LAUNCHER_ALLAPPS_ENTRY;
|
||||
: LAUNCHER_ALLAPPS_ENTRY);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1151,17 +1154,18 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
// Making sure mAllAppsSessionLogId is not null to avoid double logging.
|
||||
&& mAllAppsSessionLogId != null) {
|
||||
getAppsView().reset(false);
|
||||
getStatsLogManager().logger()
|
||||
.withContainerInfo(LauncherAtom.ContainerInfo.newBuilder()
|
||||
.setWorkspace(
|
||||
LauncherAtom.WorkspaceContainer.newBuilder()
|
||||
.setPageIndex(getWorkspace().getCurrentPage()))
|
||||
.build())
|
||||
.log(LAUNCHER_ALLAPPS_EXIT);
|
||||
getAllAppsExitEvent().ifPresent(getStatsLogManager().logger()::log);
|
||||
mAllAppsSessionLogId = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link EventEnum} that should be logged when Launcher exists from AllApps state.
|
||||
*/
|
||||
protected Optional<EventEnum> getAllAppsExitEvent() {
|
||||
return Optional.of(LAUNCHER_ALLAPPS_EXIT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
Object traceToken = TraceHelper.INSTANCE.beginSection(ON_RESUME_EVT,
|
||||
@@ -3192,4 +3196,15 @@ public class Launcher extends StatefulActivity<LauncherState> implements Launche
|
||||
public ArrowPopup<?> getOptionsPopup() {
|
||||
return findViewById(R.id.popup_container);
|
||||
}
|
||||
|
||||
/** Pauses view updates that should not be run during the app launch animation. */
|
||||
public void pauseExpensiveViewUpdates() {
|
||||
// Pause page indicator animations as they lead to layer trashing.
|
||||
getWorkspace().getPageIndicator().pauseAnimations();
|
||||
}
|
||||
|
||||
/** Resumes view updates at the end of the app launch animation. */
|
||||
public void resumeExpensiveViewUpdates() {
|
||||
getWorkspace().getPageIndicator().skipAnimationsToEnd();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,19 @@
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
|
||||
import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVITY;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.android.launcher3.graphics.SysUiScrim;
|
||||
import com.android.launcher3.statemanager.StatefulActivity;
|
||||
import com.android.launcher3.uioverrides.ApiWrapper;
|
||||
import com.android.launcher3.util.window.WindowManagerProxy;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -60,76 +55,12 @@ public class LauncherRootView extends InsettableFrameLayout {
|
||||
|
||||
@Override
|
||||
public WindowInsets onApplyWindowInsets(WindowInsets insets) {
|
||||
if (Utilities.ATLEAST_R) {
|
||||
insets = updateInsetsDueToTaskbar(insets);
|
||||
Insets systemWindowInsets = insets.getInsetsIgnoringVisibility(
|
||||
WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
|
||||
mTempRect.set(systemWindowInsets.left, systemWindowInsets.top, systemWindowInsets.right,
|
||||
systemWindowInsets.bottom);
|
||||
} else {
|
||||
mTempRect.set(insets.getSystemWindowInsetLeft(), insets.getSystemWindowInsetTop(),
|
||||
insets.getSystemWindowInsetRight(), insets.getSystemWindowInsetBottom());
|
||||
}
|
||||
insets = WindowManagerProxy.INSTANCE.get(getContext())
|
||||
.normalizeWindowInsets(getContext(), insets, mTempRect);
|
||||
handleSystemWindowInsets(mTempRect);
|
||||
return insets;
|
||||
}
|
||||
|
||||
/**
|
||||
* Taskbar provides nav bar and tappable insets. However, taskbar is not attached immediately,
|
||||
* and can be destroyed and recreated. Thus, instead of relying on taskbar being present to
|
||||
* get its insets, we calculate them ourselves so they are stable regardless of whether taskbar
|
||||
* is currently attached.
|
||||
*
|
||||
* @param oldInsets The system-provided insets, which we are modifying.
|
||||
* @return The updated insets.
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.R)
|
||||
private WindowInsets updateInsetsDueToTaskbar(WindowInsets oldInsets) {
|
||||
if (!ApiWrapper.TASKBAR_DRAWN_IN_PROCESS) {
|
||||
// 3P launchers based on Launcher3 should still be inset like normal.
|
||||
return oldInsets;
|
||||
}
|
||||
|
||||
WindowInsets.Builder updatedInsetsBuilder = new WindowInsets.Builder(oldInsets);
|
||||
|
||||
DeviceProfile dp = mActivity.getDeviceProfile();
|
||||
Resources resources = getResources();
|
||||
|
||||
Insets oldNavInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
|
||||
Rect newNavInsets = new Rect(oldNavInsets.left, oldNavInsets.top, oldNavInsets.right,
|
||||
oldNavInsets.bottom);
|
||||
|
||||
if (dp.isLandscape) {
|
||||
boolean isGesturalMode = ResourceUtils.getIntegerByName(
|
||||
"config_navBarInteractionMode",
|
||||
resources,
|
||||
INVALID_RESOURCE_HANDLE) == 2;
|
||||
if (dp.isTablet || isGesturalMode) {
|
||||
newNavInsets.bottom = dp.isTaskbarPresent
|
||||
? 0
|
||||
: ResourceUtils.getNavbarSize("navigation_bar_height_landscape", resources);
|
||||
} else {
|
||||
int navWidth = ResourceUtils.getNavbarSize("navigation_bar_width", resources);
|
||||
if (dp.isSeascape()) {
|
||||
newNavInsets.left = navWidth;
|
||||
} else {
|
||||
newNavInsets.right = navWidth;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
newNavInsets.bottom = dp.isTaskbarPresent
|
||||
? 0
|
||||
: ResourceUtils.getNavbarSize("navigation_bar_height", resources);
|
||||
}
|
||||
updatedInsetsBuilder.setInsets(WindowInsets.Type.navigationBars(), Insets.of(newNavInsets));
|
||||
updatedInsetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(),
|
||||
Insets.of(newNavInsets));
|
||||
|
||||
mActivity.updateWindowInsets(updatedInsetsBuilder, oldInsets);
|
||||
|
||||
return updatedInsetsBuilder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
// If the insets haven't changed, this is a no-op. Avoid unnecessary layout caused by
|
||||
|
||||
@@ -28,6 +28,9 @@ public class ResourceUtils {
|
||||
public static final String NAVBAR_BOTTOM_GESTURE_LARGER_SIZE =
|
||||
"navigation_bar_gesture_larger_height";
|
||||
|
||||
public static final String NAVBAR_HEIGHT = "navigation_bar_height";
|
||||
public static final String NAVBAR_HEIGHT_LANDSCAPE = "navigation_bar_height_landscape";
|
||||
|
||||
public static int getNavbarSize(String resName, Resources res) {
|
||||
return getDimenByName(resName, res, DEFAULT_NAVBAR_VALUE);
|
||||
}
|
||||
|
||||
@@ -256,4 +256,11 @@ public class ActivityAllAppsContainerView<T extends BaseDraggingActivity> extend
|
||||
layoutParams.removeRule(RelativeLayout.BELOW);
|
||||
layoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
|
||||
BaseAdapterProvider[] adapterProviders) {
|
||||
return new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
|
||||
adapterProviders);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,36 +15,20 @@
|
||||
*/
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static com.android.launcher3.touch.ItemLongClickListener.INSTANCE_ALL_APPS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnFocusChangeListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.core.view.accessibility.AccessibilityEventCompat;
|
||||
import androidx.core.view.accessibility.AccessibilityNodeInfoCompat;
|
||||
import androidx.core.view.accessibility.AccessibilityRecordCompat;
|
||||
import androidx.recyclerview.widget.GridLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
@@ -53,111 +37,26 @@ import java.util.List;
|
||||
* @param <T> Type of context inflating all apps.
|
||||
*/
|
||||
public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
|
||||
RecyclerView.Adapter<AllAppsGridAdapter.ViewHolder> {
|
||||
BaseAllAppsAdapter<T> {
|
||||
|
||||
public static final String TAG = "AppsGridAdapter";
|
||||
private final GridLayoutManager mGridLayoutMgr;
|
||||
private final GridSpanSizer mGridSizer;
|
||||
|
||||
// A normal icon
|
||||
public static final int VIEW_TYPE_ICON = 1 << 1;
|
||||
// The message shown when there are no filtered results
|
||||
public static final int VIEW_TYPE_EMPTY_SEARCH = 1 << 2;
|
||||
// The message to continue to a market search when there are no filtered results
|
||||
public static final int VIEW_TYPE_SEARCH_MARKET = 1 << 3;
|
||||
|
||||
// We use various dividers for various purposes. They share enough attributes to reuse layouts,
|
||||
// but differ in enough attributes to require different view types
|
||||
|
||||
// A divider that separates the apps list and the search market button
|
||||
public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 4;
|
||||
|
||||
// Common view type masks
|
||||
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
|
||||
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
|
||||
|
||||
|
||||
private final BaseAdapterProvider[] mAdapterProviders;
|
||||
|
||||
/**
|
||||
* ViewHolder for each icon.
|
||||
*/
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
}
|
||||
public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
|
||||
AlphabeticalAppsList apps, BaseAdapterProvider[] adapterProviders) {
|
||||
super(activityContext, inflater, apps, adapterProviders);
|
||||
mGridSizer = new GridSpanSizer();
|
||||
mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
|
||||
mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
|
||||
setAppsPerRow(activityContext.getDeviceProfile().numShownAllAppsColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Info about a particular adapter item (can be either section or app)
|
||||
* Returns the grid layout manager.
|
||||
*/
|
||||
public static class AdapterItem {
|
||||
/** Common properties */
|
||||
// The index of this adapter item in the list
|
||||
public int position;
|
||||
// The type of this item
|
||||
public int viewType;
|
||||
|
||||
// The section name of this item. Note that there can be multiple items with different
|
||||
// sectionNames in the same section
|
||||
public String sectionName = null;
|
||||
// The row that this item shows up on
|
||||
public int rowIndex;
|
||||
// The index of this app in the row
|
||||
public int rowAppIndex;
|
||||
// The associated ItemInfoWithIcon for the item
|
||||
public ItemInfoWithIcon itemInfo = null;
|
||||
// The index of this app not including sections
|
||||
public int appIndex = -1;
|
||||
// Search section associated to result
|
||||
public DecorationInfo decorationInfo = null;
|
||||
|
||||
/**
|
||||
* Factory method for AppIcon AdapterItem
|
||||
*/
|
||||
public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
|
||||
int appIndex) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_ICON;
|
||||
item.position = pos;
|
||||
item.sectionName = sectionName;
|
||||
item.itemInfo = appInfo;
|
||||
item.appIndex = appIndex;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for empty search results view
|
||||
*/
|
||||
public static AdapterItem asEmptySearch(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_EMPTY_SEARCH;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for a dividerView in AllAppsSearch
|
||||
*/
|
||||
public static AdapterItem asAllAppsDivider(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_ALL_APPS_DIVIDER;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for a market search button
|
||||
*/
|
||||
public static AdapterItem asMarketSearch(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_SEARCH_MARKET;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
protected boolean isCountedForAccessibility() {
|
||||
return viewType == VIEW_TYPE_ICON || viewType == VIEW_TYPE_SEARCH_MARKET;
|
||||
}
|
||||
public RecyclerView.LayoutManager getLayoutManager() {
|
||||
return mGridLayoutMgr;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -217,7 +116,7 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
|
||||
*/
|
||||
private int getRowsNotForAccessibility(int adapterPosition) {
|
||||
List<AdapterItem> items = mApps.getAdapterItems();
|
||||
adapterPosition = Math.max(adapterPosition, mApps.getAdapterItems().size() - 1);
|
||||
adapterPosition = Math.max(adapterPosition, items.size() - 1);
|
||||
int extraRows = 0;
|
||||
for (int i = 0; i <= adapterPosition; i++) {
|
||||
if (!isViewType(items.get(i).viewType, VIEW_TYPE_MASK_ICON)) {
|
||||
@@ -228,6 +127,20 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAppsPerRow(int appsPerRow) {
|
||||
mAppsPerRow = appsPerRow;
|
||||
int totalSpans = mAppsPerRow;
|
||||
for (BaseAdapterProvider adapterProvider : mAdapterProviders) {
|
||||
for (int itemPerRow : adapterProvider.getSupportedItemsPerRowArray()) {
|
||||
if (totalSpans % itemPerRow != 0) {
|
||||
totalSpans *= itemPerRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
mGridLayoutMgr.setSpanCount(totalSpans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper class to size the grid items.
|
||||
*/
|
||||
@@ -255,202 +168,4 @@ public class AllAppsGridAdapter<T extends Context & ActivityContext> extends
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final T mActivityContext;
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final AlphabeticalAppsList<T> mApps;
|
||||
private final GridLayoutManager mGridLayoutMgr;
|
||||
private final GridSpanSizer mGridSizer;
|
||||
|
||||
private final OnClickListener mOnIconClickListener;
|
||||
private OnLongClickListener mOnIconLongClickListener = INSTANCE_ALL_APPS;
|
||||
|
||||
private int mAppsPerRow;
|
||||
|
||||
private OnFocusChangeListener mIconFocusListener;
|
||||
|
||||
// The text to show when there are no search results and no market search handler.
|
||||
protected String mEmptySearchMessage;
|
||||
// The click listener to send off to the market app, updated each time the search query changes.
|
||||
private OnClickListener mMarketSearchClickListener;
|
||||
|
||||
private final int mExtraHeight;
|
||||
|
||||
public AllAppsGridAdapter(T activityContext, LayoutInflater inflater,
|
||||
AlphabeticalAppsList<T> apps, BaseAdapterProvider[] adapterProviders) {
|
||||
Resources res = activityContext.getResources();
|
||||
mActivityContext = activityContext;
|
||||
mApps = apps;
|
||||
mEmptySearchMessage = res.getString(R.string.all_apps_loading_message);
|
||||
mGridSizer = new GridSpanSizer();
|
||||
mGridLayoutMgr = new AppsGridLayoutManager(mActivityContext);
|
||||
mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
|
||||
mLayoutInflater = inflater;
|
||||
|
||||
mOnIconClickListener = mActivityContext.getItemOnClickListener();
|
||||
|
||||
mAdapterProviders = adapterProviders;
|
||||
setAppsPerRow(mActivityContext.getDeviceProfile().numShownAllAppsColumns);
|
||||
mExtraHeight = mActivityContext.getResources().getDimensionPixelSize(
|
||||
R.dimen.all_apps_height_extra);
|
||||
}
|
||||
|
||||
public void setAppsPerRow(int appsPerRow) {
|
||||
mAppsPerRow = appsPerRow;
|
||||
int totalSpans = mAppsPerRow;
|
||||
for (BaseAdapterProvider adapterProvider : mAdapterProviders) {
|
||||
for (int itemPerRow : adapterProvider.getSupportedItemsPerRowArray()) {
|
||||
if (totalSpans % itemPerRow != 0) {
|
||||
totalSpans *= itemPerRow;
|
||||
}
|
||||
}
|
||||
}
|
||||
mGridLayoutMgr.setSpanCount(totalSpans);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the long click listener for icons
|
||||
*/
|
||||
public void setOnIconLongClickListener(@Nullable OnLongClickListener listener) {
|
||||
mOnIconLongClickListener = listener;
|
||||
}
|
||||
|
||||
public static boolean isDividerViewType(int viewType) {
|
||||
return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
|
||||
}
|
||||
|
||||
public static boolean isIconViewType(int viewType) {
|
||||
return isViewType(viewType, VIEW_TYPE_MASK_ICON);
|
||||
}
|
||||
|
||||
public static boolean isViewType(int viewType, int viewTypeMask) {
|
||||
return (viewType & viewTypeMask) != 0;
|
||||
}
|
||||
|
||||
public void setIconFocusListener(OnFocusChangeListener focusListener) {
|
||||
mIconFocusListener = focusListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last search query that was made, used to show when there are no results and to also
|
||||
* seed the intent for searching the market.
|
||||
*/
|
||||
public void setLastSearchQuery(String query, OnClickListener marketSearchClickListener) {
|
||||
Resources res = mActivityContext.getResources();
|
||||
mEmptySearchMessage = res.getString(R.string.all_apps_no_search_results, query);
|
||||
mMarketSearchClickListener = marketSearchClickListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the grid layout manager.
|
||||
*/
|
||||
public GridLayoutManager getLayoutManager() {
|
||||
return mGridLayoutMgr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
switch (viewType) {
|
||||
case VIEW_TYPE_ICON:
|
||||
int layout = !FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() ? R.layout.all_apps_icon
|
||||
: R.layout.all_apps_icon_twoline;
|
||||
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
|
||||
layout, parent, false);
|
||||
icon.setLongPressTimeoutFactor(1f);
|
||||
icon.setOnFocusChangeListener(mIconFocusListener);
|
||||
icon.setOnClickListener(mOnIconClickListener);
|
||||
icon.setOnLongClickListener(mOnIconLongClickListener);
|
||||
// Ensure the all apps icon height matches the workspace icons in portrait mode.
|
||||
icon.getLayoutParams().height =
|
||||
mActivityContext.getDeviceProfile().allAppsCellHeightPx;
|
||||
if (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()) {
|
||||
icon.getLayoutParams().height += mExtraHeight;
|
||||
}
|
||||
return new ViewHolder(icon);
|
||||
case VIEW_TYPE_EMPTY_SEARCH:
|
||||
return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
|
||||
parent, false));
|
||||
case VIEW_TYPE_SEARCH_MARKET:
|
||||
View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
|
||||
parent, false);
|
||||
searchMarketView.setOnClickListener(mMarketSearchClickListener);
|
||||
return new ViewHolder(searchMarketView);
|
||||
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
||||
return new ViewHolder(mLayoutInflater.inflate(
|
||||
R.layout.all_apps_divider, parent, false));
|
||||
default:
|
||||
BaseAdapterProvider adapterProvider = getAdapterProvider(viewType);
|
||||
if (adapterProvider != null) {
|
||||
return adapterProvider.onCreateViewHolder(mLayoutInflater, parent, viewType);
|
||||
}
|
||||
throw new RuntimeException("Unexpected view type" + viewType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
switch (holder.getItemViewType()) {
|
||||
case VIEW_TYPE_ICON:
|
||||
AdapterItem adapterItem = mApps.getAdapterItems().get(position);
|
||||
BubbleTextView icon = (BubbleTextView) holder.itemView;
|
||||
icon.reset();
|
||||
if (adapterItem.itemInfo instanceof AppInfo) {
|
||||
icon.applyFromApplicationInfo((AppInfo) adapterItem.itemInfo);
|
||||
} else {
|
||||
icon.applyFromItemInfoWithIcon(adapterItem.itemInfo);
|
||||
}
|
||||
break;
|
||||
case VIEW_TYPE_EMPTY_SEARCH:
|
||||
TextView emptyViewText = (TextView) holder.itemView;
|
||||
emptyViewText.setText(mEmptySearchMessage);
|
||||
emptyViewText.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
|
||||
Gravity.START | Gravity.CENTER_VERTICAL);
|
||||
break;
|
||||
case VIEW_TYPE_SEARCH_MARKET:
|
||||
TextView searchView = (TextView) holder.itemView;
|
||||
if (mMarketSearchClickListener != null) {
|
||||
searchView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
searchView.setVisibility(View.GONE);
|
||||
}
|
||||
break;
|
||||
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
||||
// nothing to do
|
||||
break;
|
||||
default:
|
||||
BaseAdapterProvider adapterProvider = getAdapterProvider(holder.getItemViewType());
|
||||
if (adapterProvider != null) {
|
||||
adapterProvider.onBindView(holder, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(@NonNull ViewHolder holder) {
|
||||
super.onViewRecycled(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFailedToRecycleView(ViewHolder holder) {
|
||||
// Always recycle and we will reset the view when it is bound
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mApps.getAdapterItems().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
AdapterItem item = mApps.getAdapterItems().get(position);
|
||||
return item.viewType;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private BaseAdapterProvider getAdapterProvider(int viewType) {
|
||||
return Arrays.stream(mAdapterProviders).filter(
|
||||
adapterProvider -> adapterProvider.isViewSupported(viewType)).findFirst().orElse(
|
||||
null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import static android.view.View.MeasureSpec.EXACTLY;
|
||||
import static android.view.View.MeasureSpec.UNSPECIFIED;
|
||||
import static android.view.View.MeasureSpec.makeMeasureSpec;
|
||||
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_SCROLLED;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_ALLAPPS_VERTICAL_SWIPE_END;
|
||||
import static com.android.launcher3.util.LogConfig.SEARCH_LOGGING;
|
||||
@@ -203,6 +204,7 @@ public class AllAppsRecyclerView extends BaseRecyclerView {
|
||||
StatsLogManager mgr = ActivityContext.lookupContext(getContext()).getStatsLogManager();
|
||||
switch (state) {
|
||||
case SCROLL_STATE_DRAGGING:
|
||||
mgr.logger().log(LAUNCHER_ALLAPPS_SCROLLED);
|
||||
requestFocus();
|
||||
mgr.logger().sendToInteractionJankMonitor(
|
||||
LAUNCHER_ALLAPPS_VERTICAL_SWIPE_BEGIN, this);
|
||||
|
||||
@@ -18,7 +18,7 @@ package com.android.launcher3.allapps;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
|
||||
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.util.ItemInfoMatcher;
|
||||
@@ -82,7 +82,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
|
||||
|
||||
// The of ordered component names as a result of a search query
|
||||
private ArrayList<AdapterItem> mSearchResults;
|
||||
private AllAppsGridAdapter<T> mAdapter;
|
||||
private BaseAllAppsAdapter<T> mAdapter;
|
||||
private AppInfoComparator mAppNameComparator;
|
||||
private final int mNumAppsPerRow;
|
||||
private int mNumAppRowsInAdapter;
|
||||
@@ -106,7 +106,7 @@ public class AlphabeticalAppsList<T extends Context & ActivityContext> implement
|
||||
/**
|
||||
* Sets the adapter to notify when this dataset changes.
|
||||
*/
|
||||
public void setAdapter(AllAppsGridAdapter<T> adapter) {
|
||||
public void setAdapter(BaseAllAppsAdapter<T> adapter) {
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,333 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.allapps;
|
||||
|
||||
import static com.android.launcher3.touch.ItemLongClickListener.INSTANCE_ALL_APPS;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnFocusChangeListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.model.data.AppInfo;
|
||||
import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Adapter for all the apps.
|
||||
*
|
||||
* @param <T> Type of context inflating all apps.
|
||||
*/
|
||||
public abstract class BaseAllAppsAdapter<T extends Context & ActivityContext> extends
|
||||
RecyclerView.Adapter<BaseAllAppsAdapter.ViewHolder> {
|
||||
|
||||
public static final String TAG = "BaseAllAppsAdapter";
|
||||
|
||||
// A normal icon
|
||||
public static final int VIEW_TYPE_ICON = 1 << 1;
|
||||
// The message shown when there are no filtered results
|
||||
public static final int VIEW_TYPE_EMPTY_SEARCH = 1 << 2;
|
||||
// The message to continue to a market search when there are no filtered results
|
||||
public static final int VIEW_TYPE_SEARCH_MARKET = 1 << 3;
|
||||
|
||||
// We use various dividers for various purposes. They share enough attributes to reuse layouts,
|
||||
// but differ in enough attributes to require different view types
|
||||
|
||||
// A divider that separates the apps list and the search market button
|
||||
public static final int VIEW_TYPE_ALL_APPS_DIVIDER = 1 << 4;
|
||||
|
||||
// Common view type masks
|
||||
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
|
||||
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
|
||||
|
||||
|
||||
protected final BaseAdapterProvider[] mAdapterProviders;
|
||||
|
||||
/**
|
||||
* ViewHolder for each icon.
|
||||
*/
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
public ViewHolder(View v) {
|
||||
super(v);
|
||||
}
|
||||
}
|
||||
|
||||
/** Sets the number of apps to be displayed in one row of the all apps screen. */
|
||||
public abstract void setAppsPerRow(int appsPerRow);
|
||||
|
||||
/**
|
||||
* Info about a particular adapter item (can be either section or app)
|
||||
*/
|
||||
public static class AdapterItem {
|
||||
/** Common properties */
|
||||
// The index of this adapter item in the list
|
||||
public int position;
|
||||
// The type of this item
|
||||
public int viewType;
|
||||
|
||||
// The section name of this item. Note that there can be multiple items with different
|
||||
// sectionNames in the same section
|
||||
public String sectionName = null;
|
||||
// The row that this item shows up on
|
||||
public int rowIndex;
|
||||
// The index of this app in the row
|
||||
public int rowAppIndex;
|
||||
// The associated ItemInfoWithIcon for the item
|
||||
public ItemInfoWithIcon itemInfo = null;
|
||||
// The index of this app not including sections
|
||||
public int appIndex = -1;
|
||||
// Search section associated to result
|
||||
public DecorationInfo decorationInfo = null;
|
||||
|
||||
/**
|
||||
* Factory method for AppIcon AdapterItem
|
||||
*/
|
||||
public static AdapterItem asApp(int pos, String sectionName, AppInfo appInfo,
|
||||
int appIndex) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_ICON;
|
||||
item.position = pos;
|
||||
item.sectionName = sectionName;
|
||||
item.itemInfo = appInfo;
|
||||
item.appIndex = appIndex;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for empty search results view
|
||||
*/
|
||||
public static AdapterItem asEmptySearch(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_EMPTY_SEARCH;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for a dividerView in AllAppsSearch
|
||||
*/
|
||||
public static AdapterItem asAllAppsDivider(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_ALL_APPS_DIVIDER;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for a market search button
|
||||
*/
|
||||
public static AdapterItem asMarketSearch(int pos) {
|
||||
AdapterItem item = new AdapterItem();
|
||||
item.viewType = VIEW_TYPE_SEARCH_MARKET;
|
||||
item.position = pos;
|
||||
return item;
|
||||
}
|
||||
|
||||
protected boolean isCountedForAccessibility() {
|
||||
return viewType == VIEW_TYPE_ICON || viewType == VIEW_TYPE_SEARCH_MARKET;
|
||||
}
|
||||
}
|
||||
|
||||
protected final T mActivityContext;
|
||||
protected final AlphabeticalAppsList<T> mApps;
|
||||
// The text to show when there are no search results and no market search handler.
|
||||
protected String mEmptySearchMessage;
|
||||
protected int mAppsPerRow;
|
||||
|
||||
private final LayoutInflater mLayoutInflater;
|
||||
private final OnClickListener mOnIconClickListener;
|
||||
private OnLongClickListener mOnIconLongClickListener = INSTANCE_ALL_APPS;
|
||||
private OnFocusChangeListener mIconFocusListener;
|
||||
// The click listener to send off to the market app, updated each time the search query changes.
|
||||
private OnClickListener mMarketSearchClickListener;
|
||||
private final int mExtraHeight;
|
||||
|
||||
public BaseAllAppsAdapter(T activityContext, LayoutInflater inflater,
|
||||
AlphabeticalAppsList<T> apps, BaseAdapterProvider[] adapterProviders) {
|
||||
Resources res = activityContext.getResources();
|
||||
mActivityContext = activityContext;
|
||||
mApps = apps;
|
||||
mEmptySearchMessage = res.getString(R.string.all_apps_loading_message);
|
||||
mLayoutInflater = inflater;
|
||||
|
||||
mOnIconClickListener = mActivityContext.getItemOnClickListener();
|
||||
|
||||
mAdapterProviders = adapterProviders;
|
||||
mExtraHeight = res.getDimensionPixelSize(R.dimen.all_apps_height_extra);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the long click listener for icons
|
||||
*/
|
||||
public void setOnIconLongClickListener(@Nullable OnLongClickListener listener) {
|
||||
mOnIconLongClickListener = listener;
|
||||
}
|
||||
|
||||
/** Checks if the passed viewType represents all apps divider. */
|
||||
public static boolean isDividerViewType(int viewType) {
|
||||
return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
|
||||
}
|
||||
|
||||
/** Checks if the passed viewType represents all apps icon. */
|
||||
public static boolean isIconViewType(int viewType) {
|
||||
return isViewType(viewType, VIEW_TYPE_MASK_ICON);
|
||||
}
|
||||
|
||||
public void setIconFocusListener(OnFocusChangeListener focusListener) {
|
||||
mIconFocusListener = focusListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the last search query that was made, used to show when there are no results and to also
|
||||
* seed the intent for searching the market.
|
||||
*/
|
||||
public void setLastSearchQuery(String query, OnClickListener marketSearchClickListener) {
|
||||
Resources res = mActivityContext.getResources();
|
||||
mEmptySearchMessage = res.getString(R.string.all_apps_no_search_results, query);
|
||||
mMarketSearchClickListener = marketSearchClickListener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the layout manager.
|
||||
*/
|
||||
public abstract RecyclerView.LayoutManager getLayoutManager();
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
switch (viewType) {
|
||||
case VIEW_TYPE_ICON:
|
||||
int layout = !FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get() ? R.layout.all_apps_icon
|
||||
: R.layout.all_apps_icon_twoline;
|
||||
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
|
||||
layout, parent, false);
|
||||
icon.setLongPressTimeoutFactor(1f);
|
||||
icon.setOnFocusChangeListener(mIconFocusListener);
|
||||
icon.setOnClickListener(mOnIconClickListener);
|
||||
icon.setOnLongClickListener(mOnIconLongClickListener);
|
||||
// Ensure the all apps icon height matches the workspace icons in portrait mode.
|
||||
icon.getLayoutParams().height =
|
||||
mActivityContext.getDeviceProfile().allAppsCellHeightPx;
|
||||
if (FeatureFlags.ENABLE_TWOLINE_ALLAPPS.get()) {
|
||||
icon.getLayoutParams().height += mExtraHeight;
|
||||
}
|
||||
return new ViewHolder(icon);
|
||||
case VIEW_TYPE_EMPTY_SEARCH:
|
||||
return new ViewHolder(mLayoutInflater.inflate(R.layout.all_apps_empty_search,
|
||||
parent, false));
|
||||
case VIEW_TYPE_SEARCH_MARKET:
|
||||
View searchMarketView = mLayoutInflater.inflate(R.layout.all_apps_search_market,
|
||||
parent, false);
|
||||
searchMarketView.setOnClickListener(mMarketSearchClickListener);
|
||||
return new ViewHolder(searchMarketView);
|
||||
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
||||
return new ViewHolder(mLayoutInflater.inflate(
|
||||
R.layout.all_apps_divider, parent, false));
|
||||
default:
|
||||
BaseAdapterProvider adapterProvider = getAdapterProvider(viewType);
|
||||
if (adapterProvider != null) {
|
||||
return adapterProvider.onCreateViewHolder(mLayoutInflater, parent, viewType);
|
||||
}
|
||||
throw new RuntimeException("Unexpected view type" + viewType);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
switch (holder.getItemViewType()) {
|
||||
case VIEW_TYPE_ICON:
|
||||
AdapterItem adapterItem = mApps.getAdapterItems().get(position);
|
||||
BubbleTextView icon = (BubbleTextView) holder.itemView;
|
||||
icon.reset();
|
||||
if (adapterItem.itemInfo instanceof AppInfo) {
|
||||
icon.applyFromApplicationInfo((AppInfo) adapterItem.itemInfo);
|
||||
} else {
|
||||
icon.applyFromItemInfoWithIcon(adapterItem.itemInfo);
|
||||
}
|
||||
break;
|
||||
case VIEW_TYPE_EMPTY_SEARCH:
|
||||
TextView emptyViewText = (TextView) holder.itemView;
|
||||
emptyViewText.setText(mEmptySearchMessage);
|
||||
emptyViewText.setGravity(mApps.hasNoFilteredResults() ? Gravity.CENTER :
|
||||
Gravity.START | Gravity.CENTER_VERTICAL);
|
||||
break;
|
||||
case VIEW_TYPE_SEARCH_MARKET:
|
||||
TextView searchView = (TextView) holder.itemView;
|
||||
if (mMarketSearchClickListener != null) {
|
||||
searchView.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
searchView.setVisibility(View.GONE);
|
||||
}
|
||||
break;
|
||||
case VIEW_TYPE_ALL_APPS_DIVIDER:
|
||||
// nothing to do
|
||||
break;
|
||||
default:
|
||||
BaseAdapterProvider adapterProvider = getAdapterProvider(holder.getItemViewType());
|
||||
if (adapterProvider != null) {
|
||||
adapterProvider.onBindView(holder, position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewRecycled(@NonNull ViewHolder holder) {
|
||||
super.onViewRecycled(holder);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onFailedToRecycleView(ViewHolder holder) {
|
||||
// Always recycle and we will reset the view when it is bound
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mApps.getAdapterItems().size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
AdapterItem item = mApps.getAdapterItems().get(position);
|
||||
return item.viewType;
|
||||
}
|
||||
|
||||
protected static boolean isViewType(int viewType, int viewTypeMask) {
|
||||
return (viewType & viewTypeMask) != 0;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
protected BaseAdapterProvider getAdapterProvider(int viewType) {
|
||||
return Arrays.stream(mAdapterProviders).filter(
|
||||
adapterProvider -> adapterProvider.isViewSupported(viewType)).findFirst().orElse(
|
||||
null);
|
||||
}
|
||||
}
|
||||
@@ -44,7 +44,6 @@ import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.annotation.VisibleForTesting;
|
||||
import androidx.core.graphics.ColorUtils;
|
||||
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
@@ -697,18 +696,21 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
return ColorUtils.blendARGB(mScrimColor, mHeaderProtectionColor, blendRatio);
|
||||
}
|
||||
|
||||
protected abstract BaseAllAppsAdapter getAdapter(AlphabeticalAppsList<T> mAppsList,
|
||||
BaseAdapterProvider[] adapterProviders);
|
||||
|
||||
protected int getHeaderBottom() {
|
||||
return (int) getTranslationY();
|
||||
}
|
||||
|
||||
/** Holds a {@link AllAppsGridAdapter} and related fields. */
|
||||
/** Holds a {@link BaseAllAppsAdapter} and related fields. */
|
||||
public class AdapterHolder {
|
||||
public static final int MAIN = 0;
|
||||
public static final int WORK = 1;
|
||||
|
||||
private final boolean mIsWork;
|
||||
public final AllAppsGridAdapter<T> adapter;
|
||||
final LinearLayoutManager mLayoutManager;
|
||||
public final BaseAllAppsAdapter<T> adapter;
|
||||
final RecyclerView.LayoutManager mLayoutManager;
|
||||
final AlphabeticalAppsList<T> mAppsList;
|
||||
final Rect mPadding = new Rect();
|
||||
AllAppsRecyclerView mRecyclerView;
|
||||
@@ -724,8 +726,7 @@ public abstract class BaseAllAppsContainerView<T extends Context & ActivityConte
|
||||
mWorkManager.getAdapterProvider()}
|
||||
: new BaseAdapterProvider[]{mMainAdapterProvider};
|
||||
|
||||
adapter = new AllAppsGridAdapter<>(mActivityContext, getLayoutInflater(), mAppsList,
|
||||
adapterProviders);
|
||||
adapter = getAdapter(mAppsList, adapterProviders);
|
||||
mAppsList.setAdapter(adapter);
|
||||
mLayoutManager = adapter.getLayoutManager();
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.ExtendedEditText;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
|
||||
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.search.SearchAlgorithm;
|
||||
import com.android.launcher3.search.SearchCallback;
|
||||
|
||||
@@ -38,9 +38,9 @@ import com.android.launcher3.ExtendedEditText;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.allapps.ActivityAllAppsContainerView;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
|
||||
import com.android.launcher3.allapps.AllAppsStore;
|
||||
import com.android.launcher3.allapps.AlphabeticalAppsList;
|
||||
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
|
||||
import com.android.launcher3.allapps.SearchUiManager;
|
||||
import com.android.launcher3.search.SearchCallback;
|
||||
|
||||
|
||||
@@ -23,7 +23,7 @@ import android.os.Handler;
|
||||
import androidx.annotation.AnyThread;
|
||||
|
||||
import com.android.launcher3.LauncherAppState;
|
||||
import com.android.launcher3.allapps.AllAppsGridAdapter.AdapterItem;
|
||||
import com.android.launcher3.allapps.BaseAllAppsAdapter.AdapterItem;
|
||||
import com.android.launcher3.model.AllAppsList;
|
||||
import com.android.launcher3.model.BaseModelUpdateTask;
|
||||
import com.android.launcher3.model.BgDataModel;
|
||||
|
||||
@@ -87,6 +87,7 @@ import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
|
||||
import com.android.launcher3.util.window.WindowManagerProxy;
|
||||
import com.android.launcher3.views.ActivityContext;
|
||||
import com.android.launcher3.views.BaseDragLayer;
|
||||
import com.android.launcher3.widget.BaseLauncherAppWidgetHostView;
|
||||
@@ -128,7 +129,8 @@ public class LauncherPreviewRenderer extends ContextWrapper
|
||||
public PreviewContext(Context base, InvariantDeviceProfile idp) {
|
||||
super(base, UserCache.INSTANCE, InstallSessionHelper.INSTANCE,
|
||||
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
|
||||
CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE);
|
||||
CustomWidgetManager.INSTANCE, PluginManagerWrapper.INSTANCE,
|
||||
WindowManagerProxy.INSTANCE);
|
||||
mIdp = idp;
|
||||
mObjectMap.put(InvariantDeviceProfile.INSTANCE, idp);
|
||||
mObjectMap.put(LauncherAppState.INSTANCE,
|
||||
|
||||
@@ -440,7 +440,7 @@ public class IconCache extends BaseIconCache {
|
||||
cn,
|
||||
sectionKey.first);
|
||||
}
|
||||
if (loadFallbackTitle && TextUtils.isEmpty(entry.title)) {
|
||||
if (loadFallbackTitle && TextUtils.isEmpty(entry.title) && lai != null) {
|
||||
loadFallbackTitle(
|
||||
lai,
|
||||
entry,
|
||||
|
||||
@@ -527,7 +527,11 @@ public class StatsLogManager implements ResourceBasedOverride {
|
||||
LAUNCHER_TASKBAR_LONGPRESS_SHOW(897),
|
||||
|
||||
@UiEvent(doc = "User clicks on the search icon on header to launch search in app.")
|
||||
LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH(913);
|
||||
LAUNCHER_ALLAPPS_SEARCHINAPP_LAUNCH(913),
|
||||
|
||||
@UiEvent(doc = "User scrolled on one of the all apps surfaces such as A-Z list, search "
|
||||
+ "result page etc.")
|
||||
LAUNCHER_ALLAPPS_SCROLLED(985);
|
||||
|
||||
// ADD MORE
|
||||
|
||||
|
||||
@@ -17,15 +17,11 @@ package com.android.launcher3.statemanager;
|
||||
|
||||
import static com.android.launcher3.LauncherState.FLAG_NON_INTERACTIVE;
|
||||
|
||||
import android.graphics.Insets;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.WindowInsets;
|
||||
|
||||
import androidx.annotation.CallSuper;
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.android.launcher3.BaseDraggingActivity;
|
||||
import com.android.launcher3.LauncherRootView;
|
||||
@@ -178,14 +174,6 @@ public abstract class StatefulActivity<STATE_TYPE extends BaseState<STATE_TYPE>>
|
||||
Utilities.postAsyncCallback(mHandler, mHandleDeferredResume);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives subclasses a chance to override some window insets (via
|
||||
* {@link android.view.WindowInsets.Builder#setInsets(int, Insets)}).
|
||||
*/
|
||||
@RequiresApi(api = Build.VERSION_CODES.R)
|
||||
public void updateWindowInsets(WindowInsets.Builder updatedInsetsBuilder,
|
||||
WindowInsets oldInsets) { }
|
||||
|
||||
/**
|
||||
* Runs the given {@param r} runnable when this activity binds to the touch interaction service.
|
||||
*/
|
||||
|
||||
@@ -21,7 +21,7 @@ import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
|
||||
import static android.util.DisplayMetrics.DENSITY_DEVICE_STABLE;
|
||||
|
||||
import static com.android.launcher3.Utilities.dpiFromPx;
|
||||
import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH;
|
||||
import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
|
||||
|
||||
import android.content.SharedPreferences;
|
||||
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
|
||||
|
||||
@@ -125,7 +125,6 @@ public final class TestProtocol {
|
||||
public static final String REQUEST_MOCK_SENSOR_ROTATION = "mock-sensor-rotation";
|
||||
|
||||
public static final String PERMANENT_DIAG_TAG = "TaplTarget";
|
||||
public static final String TASK_VIEW_ID_CRASH = "b/195430732";
|
||||
public static final String NO_DROP_TARGET = "b/195031154";
|
||||
public static final String NULL_INT_SET = "b/200572078";
|
||||
public static final String MISSING_PROMISE_ICON = "b/202985412";
|
||||
|
||||
@@ -26,10 +26,8 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_NAVIGATION_MODE_GESTURE_BUTTON;
|
||||
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
|
||||
import static com.android.launcher3.util.PackageManagerHelper.getPackageFilter;
|
||||
import static com.android.launcher3.util.WindowManagerCompat.MIN_LARGE_TABLET_WIDTH;
|
||||
import static com.android.launcher3.util.WindowManagerCompat.MIN_TABLET_WIDTH;
|
||||
|
||||
import static java.util.Collections.emptyMap;
|
||||
import static com.android.launcher3.util.window.WindowManagerProxy.MIN_LARGE_TABLET_WIDTH;
|
||||
import static com.android.launcher3.util.window.WindowManagerProxy.MIN_TABLET_WIDTH;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.TargetApi;
|
||||
@@ -38,12 +36,13 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.view.Display;
|
||||
|
||||
import androidx.annotation.AnyThread;
|
||||
@@ -52,11 +51,12 @@ import androidx.annotation.UiThread;
|
||||
import com.android.launcher3.ResourceUtils;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.logging.StatsLogManager.LauncherEvent;
|
||||
import com.android.launcher3.uioverrides.ApiWrapper;
|
||||
import com.android.launcher3.util.window.CachedDisplayInfo;
|
||||
import com.android.launcher3.util.window.WindowManagerProxy;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Map;
|
||||
import java.util.Collections;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
|
||||
@@ -89,6 +89,7 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
|
||||
|
||||
// Null for SDK < S
|
||||
private final Context mWindowContext;
|
||||
|
||||
// The callback in this listener updates DeviceProfile, which other listeners might depend on
|
||||
private DisplayInfoChangeListener mPriorityListener;
|
||||
private final ArrayList<DisplayInfoChangeListener> mListeners = new ArrayList<>();
|
||||
@@ -115,23 +116,9 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
|
||||
mContext.registerReceiver(mReceiver,
|
||||
getPackageFilter(TARGET_OVERLAY_PACKAGE, ACTION_OVERLAY_CHANGED));
|
||||
|
||||
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(context);
|
||||
mInfo = new Info(getDisplayInfoContext(display), display,
|
||||
getInternalDisplays(mDM), emptyMap());
|
||||
}
|
||||
|
||||
private static ArrayMap<String, PortraitSize> getInternalDisplays(
|
||||
DisplayManager displayManager) {
|
||||
Display[] displays = displayManager.getDisplays();
|
||||
ArrayMap<String, PortraitSize> internalDisplays = new ArrayMap<>();
|
||||
for (Display display : displays) {
|
||||
if (ApiWrapper.isInternalDisplay(display)) {
|
||||
Point size = new Point();
|
||||
display.getRealSize(size);
|
||||
internalDisplays.put(ApiWrapper.getUniqueId(display),
|
||||
new PortraitSize(size.x, size.y));
|
||||
}
|
||||
}
|
||||
return internalDisplays;
|
||||
wmProxy, wmProxy.estimateInternalDisplayBounds(context));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -226,16 +213,17 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
|
||||
|
||||
@AnyThread
|
||||
private void handleInfoChange(Display display) {
|
||||
WindowManagerProxy wmProxy = WindowManagerProxy.INSTANCE.get(mContext);
|
||||
Info oldInfo = mInfo;
|
||||
|
||||
Context displayContext = getDisplayInfoContext(display);
|
||||
Info newInfo = new Info(displayContext, display,
|
||||
oldInfo.mInternalDisplays, oldInfo.mPerDisplayBounds);
|
||||
Info newInfo = new Info(displayContext, display, wmProxy, oldInfo.mPerDisplayBounds);
|
||||
|
||||
if (newInfo.densityDpi != oldInfo.densityDpi || newInfo.fontScale != oldInfo.fontScale
|
||||
|| newInfo.navigationMode != oldInfo.navigationMode) {
|
||||
// Cache may not be valid anymore, recreate without cache
|
||||
newInfo = new Info(displayContext, display, getInternalDisplays(mDM), emptyMap());
|
||||
newInfo = new Info(displayContext, display, wmProxy,
|
||||
wmProxy.estimateInternalDisplayBounds(displayContext));
|
||||
}
|
||||
|
||||
int change = 0;
|
||||
@@ -254,9 +242,8 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
|
||||
if (!newInfo.supportedBounds.equals(oldInfo.supportedBounds)) {
|
||||
change |= CHANGE_SUPPORTED_BOUNDS;
|
||||
|
||||
PortraitSize realSize = new PortraitSize(newInfo.currentSize.x, newInfo.currentSize.y);
|
||||
PortraitSize expectedSize = oldInfo.mInternalDisplays.get(
|
||||
ApiWrapper.getUniqueId(display));
|
||||
Point currentS = newInfo.currentSize;
|
||||
Point expectedS = oldInfo.mPerDisplayBounds.get(newInfo.displayId).first.size;
|
||||
if (newInfo.supportedBounds.size() != oldInfo.supportedBounds.size()) {
|
||||
Log.e("b/198965093",
|
||||
"Inconsistent number of displays"
|
||||
@@ -264,7 +251,9 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
|
||||
+ "\noldInfo.supportedBounds: " + oldInfo.supportedBounds
|
||||
+ "\nnewInfo.supportedBounds: " + newInfo.supportedBounds);
|
||||
}
|
||||
if (!realSize.equals(expectedSize) && display.getState() == Display.STATE_OFF) {
|
||||
if ((Math.min(currentS.x, currentS.y) != Math.min(expectedS.x, expectedS.y)
|
||||
|| Math.max(currentS.x, currentS.y) != Math.max(expectedS.x, expectedS.y))
|
||||
&& display.getState() == Display.STATE_OFF) {
|
||||
Log.e("b/198965093", "Display size changed while display is off, ignoring change");
|
||||
return;
|
||||
}
|
||||
@@ -290,30 +279,38 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
|
||||
|
||||
public static class Info {
|
||||
|
||||
// Configuration properties
|
||||
// Cached property
|
||||
public final int rotation;
|
||||
public final String displayId;
|
||||
public final Point currentSize;
|
||||
public final Rect cutout;
|
||||
|
||||
// Configuration property
|
||||
public final float fontScale;
|
||||
public final int densityDpi;
|
||||
public final NavigationMode navigationMode;
|
||||
|
||||
private final PortraitSize mScreenSizeDp;
|
||||
|
||||
public final Point currentSize;
|
||||
|
||||
public String displayId;
|
||||
public final Set<WindowBounds> supportedBounds = new ArraySet<>();
|
||||
private final Map<String, Set<WindowBounds>> mPerDisplayBounds = new ArrayMap<>();
|
||||
private final ArrayMap<String, PortraitSize> mInternalDisplays;
|
||||
|
||||
private final ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> mPerDisplayBounds =
|
||||
new ArrayMap<>();
|
||||
|
||||
public Info(Context context, Display display) {
|
||||
this(context, display, new ArrayMap<>(), emptyMap());
|
||||
/* don't need system overrides for external displays */
|
||||
this(context, display, new WindowManagerProxy(), new ArrayMap<>());
|
||||
}
|
||||
|
||||
private Info(Context context, Display display,
|
||||
ArrayMap<String, PortraitSize> internalDisplays,
|
||||
Map<String, Set<WindowBounds>> perDisplayBoundsCache) {
|
||||
mInternalDisplays = internalDisplays;
|
||||
rotation = display.getRotation();
|
||||
// Used for testing
|
||||
public Info(Context context, Display display,
|
||||
WindowManagerProxy wmProxy,
|
||||
ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> perDisplayBoundsCache) {
|
||||
CachedDisplayInfo displayInfo = wmProxy.getDisplayInfo(display);
|
||||
rotation = displayInfo.rotation;
|
||||
currentSize = displayInfo.size;
|
||||
displayId = displayInfo.id;
|
||||
cutout = displayInfo.cutout;
|
||||
|
||||
Configuration config = context.getResources().getConfiguration();
|
||||
fontScale = config.fontScale;
|
||||
@@ -321,54 +318,29 @@ public class DisplayController implements ComponentCallbacks, SafeCloseable {
|
||||
mScreenSizeDp = new PortraitSize(config.screenHeightDp, config.screenWidthDp);
|
||||
navigationMode = parseNavigationMode(context);
|
||||
|
||||
currentSize = new Point();
|
||||
display.getRealSize(currentSize);
|
||||
mPerDisplayBounds.putAll(perDisplayBoundsCache);
|
||||
Pair<CachedDisplayInfo, WindowBounds[]> cachedValue = mPerDisplayBounds.get(displayId);
|
||||
|
||||
displayId = ApiWrapper.getUniqueId(display);
|
||||
Set<WindowBounds> currentSupportedBounds =
|
||||
getSupportedBoundsForDisplay(display, currentSize);
|
||||
mPerDisplayBounds.put(displayId, currentSupportedBounds);
|
||||
supportedBounds.addAll(currentSupportedBounds);
|
||||
|
||||
if (ApiWrapper.isInternalDisplay(display) && internalDisplays.size() > 1) {
|
||||
int displayCount = internalDisplays.size();
|
||||
for (int i = 0; i < displayCount; i++) {
|
||||
String displayKey = internalDisplays.keyAt(i);
|
||||
if (TextUtils.equals(displayId, displayKey)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Set<WindowBounds> displayBounds = perDisplayBoundsCache.get(displayKey);
|
||||
if (displayBounds == null) {
|
||||
// We assume densityDpi is the same across all internal displays
|
||||
displayBounds = WindowManagerCompat.estimateDisplayProfiles(
|
||||
context, internalDisplays.valueAt(i), densityDpi,
|
||||
ApiWrapper.TASKBAR_DRAWN_IN_PROCESS);
|
||||
}
|
||||
|
||||
supportedBounds.addAll(displayBounds);
|
||||
mPerDisplayBounds.put(displayKey, displayBounds);
|
||||
WindowBounds realBounds = wmProxy.getRealBounds(context, display, displayInfo);
|
||||
if (cachedValue == null) {
|
||||
supportedBounds.add(realBounds);
|
||||
} else {
|
||||
// Verify that the real bounds are a match
|
||||
WindowBounds expectedBounds = cachedValue.second[displayInfo.rotation];
|
||||
if (!realBounds.equals(expectedBounds)) {
|
||||
WindowBounds[] clone = new WindowBounds[4];
|
||||
System.arraycopy(cachedValue.second, 0, clone, 0, 4);
|
||||
clone[displayInfo.rotation] = realBounds;
|
||||
cachedValue = Pair.create(displayInfo.normalize(), clone);
|
||||
mPerDisplayBounds.put(displayId, cachedValue);
|
||||
}
|
||||
}
|
||||
mPerDisplayBounds.values().forEach(
|
||||
pair -> Collections.addAll(supportedBounds, pair.second));
|
||||
Log.d("b/211775278", "displayId: " + displayId + ", currentSize: " + currentSize);
|
||||
Log.d("b/211775278", "perDisplayBounds: " + mPerDisplayBounds);
|
||||
}
|
||||
|
||||
private static Set<WindowBounds> getSupportedBoundsForDisplay(Display display, Point size) {
|
||||
Point smallestSize = new Point();
|
||||
Point largestSize = new Point();
|
||||
display.getCurrentSizeRange(smallestSize, largestSize);
|
||||
|
||||
int portraitWidth = Math.min(size.x, size.y);
|
||||
int portraitHeight = Math.max(size.x, size.y);
|
||||
Set<WindowBounds> result = new ArraySet<>();
|
||||
result.add(new WindowBounds(portraitWidth, portraitHeight,
|
||||
smallestSize.x, largestSize.y));
|
||||
result.add(new WindowBounds(portraitHeight, portraitWidth,
|
||||
largestSize.x, smallestSize.y));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code true} if the bounds represent a tablet.
|
||||
*/
|
||||
|
||||
@@ -15,10 +15,17 @@
|
||||
*/
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
|
||||
|
||||
import static java.util.concurrent.Executors.newSingleThreadExecutor;
|
||||
|
||||
import android.os.HandlerThread;
|
||||
import android.os.Looper;
|
||||
import android.os.Process;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
import java.util.concurrent.ThreadPoolExecutor;
|
||||
@@ -34,6 +41,9 @@ public class Executors {
|
||||
Math.max(Runtime.getRuntime().availableProcessors(), 2);
|
||||
private static final int KEEP_ALIVE = 1;
|
||||
|
||||
/** Dedicated executor instances for work depending on other packages. */
|
||||
private static final Map<String, ExecutorService> PACKAGE_EXECUTORS = new ConcurrentHashMap<>();
|
||||
|
||||
/**
|
||||
* An {@link ThreadPoolExecutor} to be used with async task with no limit on the queue size.
|
||||
*/
|
||||
@@ -75,6 +85,18 @@ public class Executors {
|
||||
public static final LooperExecutor MODEL_EXECUTOR =
|
||||
new LooperExecutor(createAndStartNewLooper("launcher-loader"));
|
||||
|
||||
/**
|
||||
* Returns and caches a single thread executor for a given package.
|
||||
*
|
||||
* @param packageName Package associated with the executor.
|
||||
*/
|
||||
public static ExecutorService getPackageExecutor(String packageName) {
|
||||
return PACKAGE_EXECUTORS.computeIfAbsent(
|
||||
packageName,
|
||||
p -> newSingleThreadExecutor(
|
||||
new SimpleThreadFactory(p, THREAD_PRIORITY_BACKGROUND)));
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple ThreadFactory to set the thread name and priority when used with executors.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import static android.view.Surface.ROTATION_0;
|
||||
import static android.view.Surface.ROTATION_180;
|
||||
import static android.view.Surface.ROTATION_270;
|
||||
import static android.view.Surface.ROTATION_90;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
|
||||
/**
|
||||
* Utility methods based on {@code frameworks/base/core/java/android/util/RotationUtils.java}
|
||||
*/
|
||||
public class RotationUtils {
|
||||
|
||||
/**
|
||||
* Rotates an Rect according to the given rotation.
|
||||
*/
|
||||
public static void rotateRect(Rect rect, int rotation) {
|
||||
switch (rotation) {
|
||||
case ROTATION_0:
|
||||
return;
|
||||
case ROTATION_90:
|
||||
rect.set(rect.top, rect.right, rect.bottom, rect.left);
|
||||
return;
|
||||
case ROTATION_180:
|
||||
rect.set(rect.right, rect.bottom, rect.left, rect.top);
|
||||
return;
|
||||
case ROTATION_270:
|
||||
rect.set(rect.bottom, rect.left, rect.top, rect.right);
|
||||
return;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown rotation: " + rotation);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Rotates an size according to the given rotation.
|
||||
*/
|
||||
public static void rotateSize(Point size, int rotation) {
|
||||
switch (rotation) {
|
||||
case ROTATION_0:
|
||||
case ROTATION_180:
|
||||
return;
|
||||
case ROTATION_90:
|
||||
case ROTATION_270:
|
||||
size.set(size.y, size.x);
|
||||
return;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown rotation: " + rotation);
|
||||
}
|
||||
}
|
||||
|
||||
/** @return the rotation needed to rotate from oldRotation to newRotation. */
|
||||
public static int deltaRotation(int oldRotation, int newRotation) {
|
||||
int delta = newRotation - oldRotation;
|
||||
if (delta < 0) delta += 4;
|
||||
return delta;
|
||||
}
|
||||
}
|
||||
@@ -33,19 +33,27 @@ public class WindowBounds {
|
||||
public final Rect bounds;
|
||||
public final Rect insets;
|
||||
public final Point availableSize;
|
||||
public final int rotationHint;
|
||||
|
||||
public WindowBounds(Rect bounds, Rect insets) {
|
||||
this(bounds, insets, -1);
|
||||
}
|
||||
|
||||
public WindowBounds(Rect bounds, Rect insets, int rotationHint) {
|
||||
this.bounds = bounds;
|
||||
this.insets = insets;
|
||||
this.rotationHint = rotationHint;
|
||||
availableSize = new Point(bounds.width() - insets.left - insets.right,
|
||||
bounds.height() - insets.top - insets.bottom);
|
||||
}
|
||||
|
||||
public WindowBounds(int width, int height, int availableWidth, int availableHeight) {
|
||||
public WindowBounds(int width, int height, int availableWidth, int availableHeight,
|
||||
int rotationHint) {
|
||||
this.bounds = new Rect(0, 0, width, height);
|
||||
this.availableSize = new Point(availableWidth, availableHeight);
|
||||
// We don't care about insets in this case
|
||||
this.insets = new Rect(0, 0, width - availableWidth, height - availableHeight);
|
||||
this.rotationHint = rotationHint;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.util;
|
||||
|
||||
import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
|
||||
import static com.android.launcher3.Utilities.dpiFromPx;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.util.ArraySet;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowInsets.Type;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowMetrics;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ResourceUtils;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.DisplayController.PortraitSize;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Utility class to estimate window manager values
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.S)
|
||||
public class WindowManagerCompat {
|
||||
|
||||
public static final int MIN_TABLET_WIDTH = 600;
|
||||
public static final int MIN_LARGE_TABLET_WIDTH = 720;
|
||||
|
||||
/**
|
||||
* Returns a set of supported render sizes for a internal display.
|
||||
* This is a temporary workaround which assumes only nav-bar insets change across displays, and
|
||||
* is only used until we eventually get the real values
|
||||
* @param consumeTaskBar if true, it assumes that task bar is part of the app window
|
||||
* and ignores any insets because of task bar.
|
||||
*/
|
||||
public static Set<WindowBounds> estimateDisplayProfiles(
|
||||
Context windowContext, PortraitSize size, int densityDpi, boolean consumeTaskBar) {
|
||||
if (!Utilities.ATLEAST_S) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
WindowInsets defaultInsets = windowContext.getSystemService(WindowManager.class)
|
||||
.getMaximumWindowMetrics().getWindowInsets();
|
||||
boolean isGesturalMode = ResourceUtils.getIntegerByName(
|
||||
"config_navBarInteractionMode",
|
||||
windowContext.getResources(),
|
||||
INVALID_RESOURCE_HANDLE) == 2;
|
||||
|
||||
WindowInsets.Builder insetsBuilder = new WindowInsets.Builder(defaultInsets);
|
||||
Set<WindowBounds> result = new ArraySet<>();
|
||||
int swDP = (int) dpiFromPx(size.width, densityDpi);
|
||||
boolean isTablet = swDP >= MIN_TABLET_WIDTH;
|
||||
|
||||
final Insets portraitNav, landscapeNav;
|
||||
if (isTablet && !consumeTaskBar) {
|
||||
portraitNav = landscapeNav = Insets.of(0, 0, 0, windowContext.getResources()
|
||||
.getDimensionPixelSize(R.dimen.taskbar_size));
|
||||
} else if (!isGesturalMode) {
|
||||
portraitNav = Insets.of(0, 0, 0,
|
||||
getSystemResource(windowContext, "navigation_bar_height", swDP));
|
||||
landscapeNav = isTablet
|
||||
? Insets.of(0, 0, 0, getSystemResource(windowContext,
|
||||
"navigation_bar_height_landscape", swDP))
|
||||
: Insets.of(0, 0, getSystemResource(windowContext,
|
||||
"navigation_bar_width", swDP), 0);
|
||||
} else {
|
||||
portraitNav = landscapeNav = Insets.of(0, 0, 0, 0);
|
||||
}
|
||||
|
||||
result.add(WindowBounds.fromWindowMetrics(new WindowMetrics(
|
||||
new Rect(0, 0, size.width, size.height),
|
||||
insetsBuilder.setInsets(Type.navigationBars(), portraitNav).build())));
|
||||
result.add(WindowBounds.fromWindowMetrics(new WindowMetrics(
|
||||
new Rect(0, 0, size.height, size.width),
|
||||
insetsBuilder.setInsets(Type.navigationBars(), landscapeNav).build())));
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int getSystemResource(Context context, String key, int swDp) {
|
||||
int resourceId = context.getResources().getIdentifier(key, "dimen", "android");
|
||||
if (resourceId > 0) {
|
||||
Configuration conf = new Configuration();
|
||||
conf.smallestScreenWidthDp = swDp;
|
||||
return context.createConfigurationContext(conf)
|
||||
.getResources().getDimensionPixelSize(resourceId);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.util.window;
|
||||
|
||||
import static com.android.launcher3.util.RotationUtils.deltaRotation;
|
||||
import static com.android.launcher3.util.RotationUtils.rotateRect;
|
||||
import static com.android.launcher3.util.RotationUtils.rotateSize;
|
||||
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.view.Surface;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* Properties on a display
|
||||
*/
|
||||
public class CachedDisplayInfo {
|
||||
|
||||
public final String id;
|
||||
public final Point size;
|
||||
public final int rotation;
|
||||
public final Rect cutout;
|
||||
|
||||
public CachedDisplayInfo() {
|
||||
this(new Point(0, 0), 0);
|
||||
}
|
||||
|
||||
public CachedDisplayInfo(Point size, int rotation) {
|
||||
this("", size, rotation, new Rect());
|
||||
}
|
||||
|
||||
public CachedDisplayInfo(String id, Point size, int rotation, Rect cutout) {
|
||||
this.id = id;
|
||||
this.size = size;
|
||||
this.rotation = rotation;
|
||||
this.cutout = cutout;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CachedDisplayInfo where the properties are normalized to {@link Surface#ROTATION_0}
|
||||
*/
|
||||
public CachedDisplayInfo normalize() {
|
||||
if (rotation == Surface.ROTATION_0) {
|
||||
return this;
|
||||
}
|
||||
Point newSize = new Point(size);
|
||||
rotateSize(newSize, deltaRotation(rotation, Surface.ROTATION_0));
|
||||
|
||||
Rect newCutout = new Rect(cutout);
|
||||
rotateRect(newCutout, deltaRotation(rotation, Surface.ROTATION_0));
|
||||
return new CachedDisplayInfo(id, newSize, Surface.ROTATION_0, newCutout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CachedDisplayInfo{"
|
||||
+ "id='" + id + '\''
|
||||
+ ", size=" + size
|
||||
+ ", rotation=" + rotation
|
||||
+ ", cutout=" + cutout
|
||||
+ '}';
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (!(o instanceof CachedDisplayInfo)) return false;
|
||||
CachedDisplayInfo that = (CachedDisplayInfo) o;
|
||||
return rotation == that.rotation && Objects.equals(id, that.id)
|
||||
&& Objects.equals(size, that.size) && Objects.equals(cutout,
|
||||
that.cutout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Objects.hash(id, size, rotation, cutout);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
/*
|
||||
* Copyright (C) 2022 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.util.window;
|
||||
|
||||
import static com.android.launcher3.ResourceUtils.INVALID_RESOURCE_HANDLE;
|
||||
import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT;
|
||||
import static com.android.launcher3.ResourceUtils.NAVBAR_HEIGHT_LANDSCAPE;
|
||||
import static com.android.launcher3.ResourceUtils.NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE;
|
||||
import static com.android.launcher3.ResourceUtils.getDimenByName;
|
||||
import static com.android.launcher3.Utilities.dpiFromPx;
|
||||
import static com.android.launcher3.util.MainThreadInitializedObject.forOverride;
|
||||
import static com.android.launcher3.util.RotationUtils.deltaRotation;
|
||||
import static com.android.launcher3.util.RotationUtils.rotateRect;
|
||||
import static com.android.launcher3.util.RotationUtils.rotateSize;
|
||||
|
||||
import android.annotation.TargetApi;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Insets;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.hardware.display.DisplayManager;
|
||||
import android.os.Build;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Pair;
|
||||
import android.view.Display;
|
||||
import android.view.DisplayCutout;
|
||||
import android.view.Surface;
|
||||
import android.view.WindowInsets;
|
||||
import android.view.WindowManager;
|
||||
import android.view.WindowMetrics;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.ResourceUtils;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
import com.android.launcher3.util.WindowBounds;
|
||||
|
||||
/**
|
||||
* Utility class for mocking some window manager behaviours
|
||||
*/
|
||||
public class WindowManagerProxy implements ResourceBasedOverride {
|
||||
|
||||
public static final int MIN_TABLET_WIDTH = 600;
|
||||
public static final int MIN_LARGE_TABLET_WIDTH = 720;
|
||||
|
||||
public static final MainThreadInitializedObject<WindowManagerProxy> INSTANCE =
|
||||
forOverride(WindowManagerProxy.class, R.string.window_manager_proxy_class);
|
||||
|
||||
protected final boolean mTaskbarDrawnInProcess;
|
||||
|
||||
/**
|
||||
* Creates a new instance of proxy, applying any overrides
|
||||
*/
|
||||
public static WindowManagerProxy newInstance(Context context) {
|
||||
return Overrides.getObject(WindowManagerProxy.class, context,
|
||||
R.string.window_manager_proxy_class);
|
||||
}
|
||||
|
||||
public WindowManagerProxy() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
protected WindowManagerProxy(boolean taskbarDrawnInProcess) {
|
||||
mTaskbarDrawnInProcess = taskbarDrawnInProcess;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a map of normalized info of internal displays to estimated window bounds
|
||||
* for that display
|
||||
*/
|
||||
public ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> estimateInternalDisplayBounds(
|
||||
Context context) {
|
||||
Display[] displays = context.getSystemService(DisplayManager.class).getDisplays();
|
||||
ArrayMap<String, Pair<CachedDisplayInfo, WindowBounds[]>> result = new ArrayMap<>();
|
||||
for (Display display : displays) {
|
||||
if (isInternalDisplay(display)) {
|
||||
CachedDisplayInfo info = getDisplayInfo(display).normalize();
|
||||
WindowBounds[] bounds = estimateWindowBounds(context, info);
|
||||
result.put(info.id, Pair.create(info, bounds));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the real bounds for the provided display after applying any insets normalization
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.R)
|
||||
public WindowBounds getRealBounds(Context windowContext,
|
||||
Display display, CachedDisplayInfo info) {
|
||||
if (!Utilities.ATLEAST_R) {
|
||||
Point smallestSize = new Point();
|
||||
Point largestSize = new Point();
|
||||
display.getCurrentSizeRange(smallestSize, largestSize);
|
||||
|
||||
if (info.size.y > info.size.x) {
|
||||
// Portrait
|
||||
return new WindowBounds(info.size.x, info.size.y, smallestSize.x, largestSize.y,
|
||||
info.rotation);
|
||||
} else {
|
||||
// Landscape
|
||||
new WindowBounds(info.size.x, info.size.y, largestSize.x, smallestSize.y,
|
||||
info.rotation);
|
||||
}
|
||||
}
|
||||
|
||||
WindowMetrics wm = windowContext.getSystemService(WindowManager.class)
|
||||
.getCurrentWindowMetrics();
|
||||
|
||||
Rect insets = new Rect();
|
||||
normalizeWindowInsets(windowContext, wm.getWindowInsets(), insets);
|
||||
return new WindowBounds(wm.getBounds(), insets, info.rotation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an updated insets, accounting for various Launcher UI specific overrides like taskbar
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.R)
|
||||
public WindowInsets normalizeWindowInsets(Context context, WindowInsets oldInsets,
|
||||
Rect outInsets) {
|
||||
if (!Utilities.ATLEAST_R || !mTaskbarDrawnInProcess) {
|
||||
outInsets.set(oldInsets.getSystemWindowInsetLeft(), oldInsets.getSystemWindowInsetTop(),
|
||||
oldInsets.getSystemWindowInsetRight(), oldInsets.getSystemWindowInsetBottom());
|
||||
return oldInsets;
|
||||
}
|
||||
|
||||
WindowInsets.Builder insetsBuilder = new WindowInsets.Builder(oldInsets);
|
||||
Insets navInsets = oldInsets.getInsets(WindowInsets.Type.navigationBars());
|
||||
|
||||
Resources systemRes = context.getResources();
|
||||
Configuration config = systemRes.getConfiguration();
|
||||
|
||||
boolean isTablet = config.smallestScreenWidthDp > MIN_TABLET_WIDTH;
|
||||
boolean isGesture = isGestureNav(context);
|
||||
|
||||
int bottomNav = isTablet
|
||||
? 0
|
||||
: (config.screenHeightDp > config.screenWidthDp
|
||||
? getDimenByName(NAVBAR_HEIGHT, systemRes, 0)
|
||||
: (isGesture
|
||||
? getDimenByName(NAVBAR_HEIGHT_LANDSCAPE, systemRes, 0)
|
||||
: 0));
|
||||
Insets newNavInsets = Insets.of(navInsets.left, navInsets.top, navInsets.right, bottomNav);
|
||||
insetsBuilder.setInsets(WindowInsets.Type.navigationBars(), newNavInsets);
|
||||
insetsBuilder.setInsetsIgnoringVisibility(WindowInsets.Type.navigationBars(), newNavInsets);
|
||||
|
||||
// Override the tappable insets to be 0 on the bottom for gesture nav (otherwise taskbar
|
||||
// would count towards it). This is used for the bottom protection in All Apps for example.
|
||||
if (isGesture) {
|
||||
Insets oldTappableInsets = oldInsets.getInsets(WindowInsets.Type.tappableElement());
|
||||
Insets newTappableInsets = Insets.of(oldTappableInsets.left, oldTappableInsets.top,
|
||||
oldTappableInsets.right, 0);
|
||||
insetsBuilder.setInsets(WindowInsets.Type.tappableElement(), newTappableInsets);
|
||||
}
|
||||
|
||||
WindowInsets result = insetsBuilder.build();
|
||||
Insets systemWindowInsets = result.getInsetsIgnoringVisibility(
|
||||
WindowInsets.Type.systemBars() | WindowInsets.Type.displayCutout());
|
||||
outInsets.set(systemWindowInsets.left, systemWindowInsets.top, systemWindowInsets.right,
|
||||
systemWindowInsets.bottom);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the display is an internal displays
|
||||
*/
|
||||
protected boolean isInternalDisplay(Display display) {
|
||||
return display.getDisplayId() == Display.DEFAULT_DISPLAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a list of possible WindowBounds for the display keyed on the 4 surface rotations
|
||||
*/
|
||||
public WindowBounds[] estimateWindowBounds(Context context, CachedDisplayInfo display) {
|
||||
int densityDpi = context.getResources().getConfiguration().densityDpi;
|
||||
int rotation = display.rotation;
|
||||
Rect safeCutout = display.cutout;
|
||||
|
||||
int minSize = Math.min(display.size.x, display.size.y);
|
||||
int swDp = (int) dpiFromPx(minSize, densityDpi);
|
||||
|
||||
Resources systemRes;
|
||||
{
|
||||
Configuration conf = new Configuration();
|
||||
conf.smallestScreenWidthDp = swDp;
|
||||
systemRes = context.createConfigurationContext(conf).getResources();
|
||||
}
|
||||
|
||||
boolean isTablet = swDp >= MIN_TABLET_WIDTH;
|
||||
boolean isTabletOrGesture = isTablet
|
||||
|| (Utilities.ATLEAST_R && isGestureNav(context));
|
||||
|
||||
int statusBarHeight = getDimenByName("status_bar_height", systemRes, 0);
|
||||
|
||||
int navBarHeightPortrait, navBarHeightLandscape, navbarWidthLandscape;
|
||||
|
||||
navBarHeightPortrait = isTablet
|
||||
? (mTaskbarDrawnInProcess
|
||||
? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
|
||||
: getDimenByName(NAVBAR_HEIGHT, systemRes, 0);
|
||||
|
||||
navBarHeightLandscape = isTablet
|
||||
? (mTaskbarDrawnInProcess
|
||||
? 0 : systemRes.getDimensionPixelSize(R.dimen.taskbar_size))
|
||||
: (isTabletOrGesture
|
||||
? getDimenByName(NAVBAR_HEIGHT_LANDSCAPE, systemRes, 0) : 0);
|
||||
navbarWidthLandscape = isTabletOrGesture
|
||||
? 0
|
||||
: getDimenByName(NAVBAR_LANDSCAPE_LEFT_RIGHT_SIZE, systemRes, 0);
|
||||
|
||||
WindowBounds[] result = new WindowBounds[4];
|
||||
Point tempSize = new Point();
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int rotationChange = deltaRotation(rotation, i);
|
||||
tempSize.set(display.size.x, display.size.y);
|
||||
rotateSize(tempSize, rotationChange);
|
||||
Rect bounds = new Rect(0, 0, tempSize.x, tempSize.y);
|
||||
|
||||
int navBarHeight, navbarWidth;
|
||||
if (tempSize.y > tempSize.x) {
|
||||
navBarHeight = navBarHeightPortrait;
|
||||
navbarWidth = 0;
|
||||
} else {
|
||||
navBarHeight = navBarHeightLandscape;
|
||||
navbarWidth = navbarWidthLandscape;
|
||||
}
|
||||
|
||||
Rect insets = new Rect(safeCutout);
|
||||
rotateRect(insets, rotationChange);
|
||||
insets.top = Math.max(insets.top, statusBarHeight);
|
||||
insets.bottom = Math.max(insets.bottom, navBarHeight);
|
||||
|
||||
if (i == Surface.ROTATION_270 || i == Surface.ROTATION_180) {
|
||||
// On reverse landscape (and in rare-case when the natural orientation of the
|
||||
// device is landscape), navigation bar is on the right.
|
||||
insets.left = Math.max(insets.left, navbarWidth);
|
||||
} else {
|
||||
insets.right = Math.max(insets.right, navbarWidth);
|
||||
}
|
||||
result[i] = new WindowBounds(bounds, insets, i);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean isGestureNav(Context context) {
|
||||
return ResourceUtils.getIntegerByName("config_navBarInteractionMode",
|
||||
context.getResources(), INVALID_RESOURCE_HANDLE) == 2;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a CachedDisplayInfo initialized for the current display
|
||||
*/
|
||||
@TargetApi(Build.VERSION_CODES.S)
|
||||
public CachedDisplayInfo getDisplayInfo(Display display) {
|
||||
int rotation = display.getRotation();
|
||||
|
||||
Point size = new Point();
|
||||
display.getRealSize(size);
|
||||
|
||||
Rect cutoutRect = new Rect();
|
||||
if (Utilities.ATLEAST_S) {
|
||||
DisplayCutout cutout = display.getCutout();
|
||||
if (cutout != null) {
|
||||
cutoutRect.set(cutout.getSafeInsetLeft(), cutout.getSafeInsetTop(),
|
||||
cutout.getSafeInsetRight(), cutout.getSafeInsetBottom());
|
||||
}
|
||||
}
|
||||
|
||||
return new CachedDisplayInfo(getDisplayId(display), size, rotation, cutoutRect);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique ID representing the display
|
||||
*/
|
||||
protected String getDisplayId(Display display) {
|
||||
return Integer.toString(display.getDisplayId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns rotation of the display associated with the context.
|
||||
*/
|
||||
public int getRotation(Context context) {
|
||||
Display d = null;
|
||||
if (Utilities.ATLEAST_R) {
|
||||
try {
|
||||
d = context.getDisplay();
|
||||
} catch (UnsupportedOperationException e) {
|
||||
// Ignore
|
||||
}
|
||||
}
|
||||
return d == null ? DisplayController.INSTANCE.get(context).getInfo().rotation
|
||||
: d.getRotation();
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ import com.android.launcher3.model.data.ItemInfoWithIcon;
|
||||
/**
|
||||
* Views that contain {@link BubbleTextView} should implement this interface.
|
||||
*/
|
||||
public interface BubbleTextHolder {
|
||||
public interface BubbleTextHolder extends IconLabelDotView {
|
||||
BubbleTextView getBubbleText();
|
||||
|
||||
/**
|
||||
@@ -32,4 +32,14 @@ public interface BubbleTextHolder {
|
||||
*/
|
||||
default void onItemInfoUpdated(ItemInfoWithIcon itemInfo) {
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setIconVisible(boolean visible) {
|
||||
getBubbleText().setIconVisible(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
default void setForceHideDot(boolean hide) {
|
||||
getBubbleText().setForceHideDot(hide);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,8 +147,7 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
* Update the icon UI to match the provided parameters during an animation frame
|
||||
*/
|
||||
public void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
|
||||
int fgIconAlpha, boolean isOpening, View container, DeviceProfile dp,
|
||||
boolean isVerticalBarLayout) {
|
||||
int fgIconAlpha, boolean isOpening, View container, DeviceProfile dp) {
|
||||
MarginLayoutParams lp = (MarginLayoutParams) container.getLayoutParams();
|
||||
|
||||
float dX = mIsRtl
|
||||
@@ -169,7 +168,7 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
}
|
||||
|
||||
update(rect, progress, shapeProgressStart, cornerRadius, fgIconAlpha, isOpening, scale,
|
||||
minSize, lp, isVerticalBarLayout, dp);
|
||||
minSize, lp, dp);
|
||||
|
||||
container.setPivotX(0);
|
||||
container.setPivotY(0);
|
||||
@@ -181,7 +180,7 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
|
||||
private void update(RectF rect, float progress, float shapeProgressStart, float cornerRadius,
|
||||
int fgIconAlpha, boolean isOpening, float scale, float minSize,
|
||||
MarginLayoutParams parentLp, boolean isVerticalBarLayout, DeviceProfile dp) {
|
||||
MarginLayoutParams parentLp, DeviceProfile dp) {
|
||||
float dX = mIsRtl
|
||||
? rect.left - (dp.widthPx - parentLp.getMarginStart() - parentLp.width)
|
||||
: rect.left - parentLp.getMarginStart();
|
||||
@@ -193,7 +192,7 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
float shapeRevealProgress = boundToRange(mapToRange(max(shapeProgressStart, progress),
|
||||
shapeProgressStart, 1f, 0, toMax, LINEAR), 0, 1);
|
||||
|
||||
if (isVerticalBarLayout) {
|
||||
if (dp.isLandscape) {
|
||||
mOutline.right = (int) (rect.width() / scale);
|
||||
} else {
|
||||
mOutline.bottom = (int) (rect.height() / scale);
|
||||
@@ -218,16 +217,16 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
mRevealAnimator.setCurrentFraction(shapeRevealProgress);
|
||||
}
|
||||
|
||||
float drawableScale = (isVerticalBarLayout ? mOutline.width() : mOutline.height())
|
||||
float drawableScale = (dp.isLandscape ? mOutline.width() : mOutline.height())
|
||||
/ minSize;
|
||||
setBackgroundDrawableBounds(drawableScale, isVerticalBarLayout);
|
||||
setBackgroundDrawableBounds(drawableScale, dp.isLandscape);
|
||||
if (isOpening) {
|
||||
// Center align foreground
|
||||
int height = mFinalDrawableBounds.height();
|
||||
int width = mFinalDrawableBounds.width();
|
||||
int diffY = isVerticalBarLayout ? 0
|
||||
int diffY = dp.isLandscape ? 0
|
||||
: (int) (((height * drawableScale) - height) / 2);
|
||||
int diffX = isVerticalBarLayout ? (int) (((width * drawableScale) - width) / 2)
|
||||
int diffX = dp.isLandscape ? (int) (((width * drawableScale) - width) / 2)
|
||||
: 0;
|
||||
sTmpRect.set(mFinalDrawableBounds);
|
||||
sTmpRect.offset(diffX, diffY);
|
||||
@@ -247,11 +246,11 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
invalidateOutline();
|
||||
}
|
||||
|
||||
private void setBackgroundDrawableBounds(float scale, boolean isVerticalBarLayout) {
|
||||
private void setBackgroundDrawableBounds(float scale, boolean isLandscape) {
|
||||
sTmpRect.set(mFinalDrawableBounds);
|
||||
Utilities.scaleRectAboutCenter(sTmpRect, scale);
|
||||
// Since the drawable is at the top of the view, we need to offset to keep it centered.
|
||||
if (isVerticalBarLayout) {
|
||||
if (isLandscape) {
|
||||
sTmpRect.offsetTo((int) (mFinalDrawableBounds.left * scale), sTmpRect.top);
|
||||
} else {
|
||||
sTmpRect.offsetTo(sTmpRect.left, (int) (mFinalDrawableBounds.top * scale));
|
||||
@@ -269,7 +268,7 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
* Sets the icon for this view as part of initial setup
|
||||
*/
|
||||
public void setIcon(@Nullable Drawable drawable, int iconOffset, MarginLayoutParams lp,
|
||||
boolean isOpening, boolean isVerticalBarLayout, DeviceProfile dp) {
|
||||
boolean isOpening, DeviceProfile dp) {
|
||||
mIsAdaptiveIcon = drawable instanceof AdaptiveIconDrawable;
|
||||
if (mIsAdaptiveIcon) {
|
||||
boolean isFolderIcon = drawable instanceof FolderAdaptiveIcon;
|
||||
@@ -304,7 +303,7 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
Utilities.scaleRectAboutCenter(mStartRevealRect, IconShape.getNormalizationScale());
|
||||
}
|
||||
|
||||
if (isVerticalBarLayout) {
|
||||
if (dp.isLandscape) {
|
||||
lp.width = (int) Math.max(lp.width, lp.height * dp.aspectRatio);
|
||||
} else {
|
||||
lp.height = (int) Math.max(lp.height, lp.width * dp.aspectRatio);
|
||||
@@ -325,7 +324,7 @@ public class ClipIconView extends View implements ClipPathView {
|
||||
bgDrawableStartScale = scale;
|
||||
mOutline.set(0, 0, lp.width, lp.height);
|
||||
}
|
||||
setBackgroundDrawableBounds(bgDrawableStartScale, isVerticalBarLayout);
|
||||
setBackgroundDrawableBounds(bgDrawableStartScale, dp.isLandscape);
|
||||
mEndRevealRect.set(0, 0, lp.width, lp.height);
|
||||
setOutlineProvider(new ViewOutlineProvider() {
|
||||
@Override
|
||||
|
||||
@@ -43,6 +43,7 @@ import androidx.annotation.UiThread;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import com.android.launcher3.BubbleTextView;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.InsettableFrameLayout;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.R;
|
||||
@@ -82,7 +83,6 @@ public class FloatingIconView extends FrameLayout implements
|
||||
private final Launcher mLauncher;
|
||||
private final boolean mIsRtl;
|
||||
|
||||
private boolean mIsVerticalBarLayout = false;
|
||||
private boolean mIsOpening;
|
||||
|
||||
private IconLoadResult mIconLoadResult;
|
||||
@@ -150,7 +150,7 @@ public class FloatingIconView extends FrameLayout implements
|
||||
float shapeProgressStart, float cornerRadius, boolean isOpening) {
|
||||
setAlpha(alpha);
|
||||
mClipIconView.update(rect, progress, shapeProgressStart, cornerRadius, fgIconAlpha,
|
||||
isOpening, this, mLauncher.getDeviceProfile(), mIsVerticalBarLayout);
|
||||
isOpening, this, mLauncher.getDeviceProfile());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -320,11 +320,11 @@ public class FloatingIconView extends FrameLayout implements
|
||||
@UiThread
|
||||
private void setIcon(@Nullable Drawable drawable, @Nullable Drawable badge,
|
||||
@Nullable Drawable btvIcon, int iconOffset) {
|
||||
final DeviceProfile dp = mLauncher.getDeviceProfile();
|
||||
final InsettableFrameLayout.LayoutParams lp =
|
||||
(InsettableFrameLayout.LayoutParams) getLayoutParams();
|
||||
mBadge = badge;
|
||||
mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening, mIsVerticalBarLayout,
|
||||
mLauncher.getDeviceProfile());
|
||||
mClipIconView.setIcon(drawable, iconOffset, lp, mIsOpening, dp);
|
||||
if (drawable instanceof AdaptiveIconDrawable) {
|
||||
final int originalHeight = lp.height;
|
||||
final int originalWidth = lp.width;
|
||||
@@ -332,7 +332,7 @@ public class FloatingIconView extends FrameLayout implements
|
||||
mFinalDrawableBounds.set(0, 0, originalWidth, originalHeight);
|
||||
|
||||
float aspectRatio = mLauncher.getDeviceProfile().aspectRatio;
|
||||
if (mIsVerticalBarLayout) {
|
||||
if (dp.isLandscape) {
|
||||
lp.width = (int) Math.max(lp.width, lp.height * aspectRatio);
|
||||
} else {
|
||||
lp.height = (int) Math.max(lp.height, lp.width * aspectRatio);
|
||||
@@ -565,7 +565,6 @@ public class FloatingIconView extends FrameLayout implements
|
||||
view.recycle();
|
||||
|
||||
// Init properties before getting the drawable.
|
||||
view.mIsVerticalBarLayout = launcher.getDeviceProfile().isVerticalBarLayout();
|
||||
view.mIsOpening = isOpening;
|
||||
view.mOriginalIcon = originalView;
|
||||
view.mPositionOut = positionOut;
|
||||
@@ -587,7 +586,7 @@ public class FloatingIconView extends FrameLayout implements
|
||||
view.matchPositionOf(launcher, originalView, isOpening, positionOut);
|
||||
|
||||
// We need to add it to the overlay, but keep it invisible until animation starts..
|
||||
view.setVisibility(INVISIBLE);
|
||||
setIconAndDotVisible(view, false);
|
||||
parent.addView(view);
|
||||
dragLayer.addView(view.mListenerView);
|
||||
view.mListenerView.setListener(view::fastFinish);
|
||||
@@ -596,16 +595,8 @@ public class FloatingIconView extends FrameLayout implements
|
||||
view.mEndRunnable = null;
|
||||
|
||||
if (hideOriginal) {
|
||||
if (isOpening) {
|
||||
setIconAndDotVisible(originalView, true);
|
||||
view.finish(dragLayer);
|
||||
} else {
|
||||
originalView.setVisibility(VISIBLE);
|
||||
if (originalView instanceof IconLabelDotView) {
|
||||
setIconAndDotVisible(originalView, true);
|
||||
}
|
||||
view.finish(dragLayer);
|
||||
}
|
||||
setIconAndDotVisible(originalView, true);
|
||||
view.finish(dragLayer);
|
||||
} else {
|
||||
view.finish(dragLayer);
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import android.content.res.Resources;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Process;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Pair;
|
||||
import android.util.SparseArray;
|
||||
@@ -55,7 +56,9 @@ import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.compat.AccessibilityManagerCompat;
|
||||
import com.android.launcher3.model.UserManagerState;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.views.ArrowTipView;
|
||||
import com.android.launcher3.views.RecyclerViewFastScroller;
|
||||
import com.android.launcher3.views.SpringRelativeLayout;
|
||||
@@ -94,13 +97,17 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
||||
"launcher.widgets_education_dialog_seen";
|
||||
|
||||
private final Rect mInsets = new Rect();
|
||||
|
||||
private final UserManagerState mUserManagerState = new UserManagerState();
|
||||
|
||||
private final boolean mHasWorkProfile;
|
||||
private final SparseArray<AdapterHolder> mAdapters = new SparseArray();
|
||||
private final UserHandle mCurrentUser = Process.myUserHandle();
|
||||
private final Predicate<WidgetsListBaseEntry> mPrimaryWidgetsFilter =
|
||||
entry -> mCurrentUser.equals(entry.mPkgItem.user);
|
||||
private final Predicate<WidgetsListBaseEntry> mWorkWidgetsFilter =
|
||||
mPrimaryWidgetsFilter.negate();
|
||||
entry -> !mCurrentUser.equals(entry.mPkgItem.user)
|
||||
&& !mUserManagerState.isUserQuiet(entry.mPkgItem.user);
|
||||
@Nullable private ArrowTipView mLatestEducationalTip;
|
||||
private final OnLayoutChangeListener mLayoutChangeListenerToShowTips =
|
||||
new OnLayoutChangeListener() {
|
||||
@@ -171,6 +178,9 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
||||
: 0;
|
||||
mWidgetSheetContentHorizontalPadding = 2 * resources.getDimensionPixelSize(
|
||||
R.dimen.widget_cell_horizontal_padding);
|
||||
|
||||
mUserManagerState.init(UserCache.INSTANCE.get(context),
|
||||
context.getSystemService(UserManager.class));
|
||||
}
|
||||
|
||||
public WidgetsFullSheet(Context context, AttributeSet attrs) {
|
||||
@@ -259,10 +269,15 @@ public class WidgetsFullSheet extends BaseWidgetSheet
|
||||
boolean isWidgetAvailable = adapterHolder.mWidgetsListAdapter.hasVisibleEntries();
|
||||
adapterHolder.mWidgetsRecyclerView.setVisibility(isWidgetAvailable ? VISIBLE : GONE);
|
||||
|
||||
mNoWidgetsView.setText(
|
||||
adapterHolder.mAdapterType == AdapterHolder.SEARCH
|
||||
? R.string.no_search_results
|
||||
: R.string.no_widgets_available);
|
||||
if (adapterHolder.mAdapterType == AdapterHolder.SEARCH) {
|
||||
mNoWidgetsView.setText(R.string.no_search_results);
|
||||
} else if (adapterHolder.mAdapterType == AdapterHolder.WORK
|
||||
&& mUserManagerState.isAnyProfileQuietModeEnabled()
|
||||
&& mActivityContext.getStringCache() != null) {
|
||||
mNoWidgetsView.setText(mActivityContext.getStringCache().workProfilePausedTitle);
|
||||
} else {
|
||||
mNoWidgetsView.setText(R.string.no_widgets_available);
|
||||
}
|
||||
mNoWidgetsView.setVisibility(isWidgetAvailable ? GONE : VISIBLE);
|
||||
}
|
||||
|
||||
|
||||
@@ -19,7 +19,6 @@ package com.android.launcher3.uioverrides;
|
||||
import android.app.Person;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.view.Display;
|
||||
|
||||
import com.android.launcher3.Utilities;
|
||||
|
||||
@@ -31,20 +30,6 @@ public class ApiWrapper {
|
||||
return Utilities.EMPTY_PERSON_ARRAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the display is an internal displays
|
||||
*/
|
||||
public static boolean isInternalDisplay(Display display) {
|
||||
return display.getDisplayId() == Display.DEFAULT_DISPLAY;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a unique ID representing the display
|
||||
*/
|
||||
public static String getUniqueId(Display display) {
|
||||
return Integer.toString(display.getDisplayId());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the minimum space that should be left empty at the end of hotseat
|
||||
*/
|
||||
|
||||
@@ -139,7 +139,7 @@ class DeviceProfileTest {
|
||||
else
|
||||
Pair(1440, 3120)
|
||||
|
||||
windowBounds = WindowBounds(x, y, x, y - 100)
|
||||
windowBounds = WindowBounds(x, y, x, y - 100, 0)
|
||||
|
||||
`when`(info.isTablet(any())).thenReturn(false)
|
||||
`when`(info.isLargeTablet(any())).thenReturn(false)
|
||||
@@ -153,7 +153,7 @@ class DeviceProfileTest {
|
||||
else
|
||||
Pair(1600, 2560)
|
||||
|
||||
windowBounds = WindowBounds(x, y, x, y - 100)
|
||||
windowBounds = WindowBounds(x, y, x, y - 100, 0)
|
||||
|
||||
`when`(info.isTablet(any())).thenReturn(true)
|
||||
`when`(info.isLargeTablet(any())).thenReturn(false)
|
||||
@@ -167,7 +167,7 @@ class DeviceProfileTest {
|
||||
else
|
||||
Pair(1600, 2560)
|
||||
|
||||
windowBounds = WindowBounds(x, y, x, y - 100)
|
||||
windowBounds = WindowBounds(x, y, x, y - 100, 0)
|
||||
|
||||
`when`(info.isTablet(any())).thenReturn(true)
|
||||
`when`(info.isLargeTablet(any())).thenReturn(true)
|
||||
|
||||
@@ -67,6 +67,7 @@ import com.android.launcher3.pm.UserCache;
|
||||
import com.android.launcher3.testing.TestInformationProvider;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject.SandboxContext;
|
||||
import com.android.launcher3.util.window.WindowManagerProxy;
|
||||
import com.android.launcher3.widget.custom.CustomWidgetManager;
|
||||
|
||||
import org.mockito.ArgumentCaptor;
|
||||
@@ -501,7 +502,7 @@ public class LauncherModelHelper {
|
||||
LauncherAppState.INSTANCE, InvariantDeviceProfile.INSTANCE,
|
||||
DisplayController.INSTANCE, CustomWidgetManager.INSTANCE,
|
||||
SettingsCache.INSTANCE, PluginManagerWrapper.INSTANCE,
|
||||
ItemInstallQueue.INSTANCE);
|
||||
ItemInstallQueue.INSTANCE, WindowManagerProxy.INSTANCE);
|
||||
mPm = spy(getBaseContext().getPackageManager());
|
||||
mDbDir = new File(getCacheDir(), UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user