Snap for 11822896 from 8b0469b096 to 24Q3-release
Change-Id: I6c1641f22ba081857db9af1e337009afe8d9b88a
This commit is contained in:
@@ -121,6 +121,17 @@
|
||||
android:layout_weight="1"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<!-- Unused. Included only for compatibility with parent class. -->
|
||||
<LinearLayout
|
||||
android:id="@+id/group_action_buttons"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="@dimen/overview_actions_height"
|
||||
android:layout_gravity="top|center_horizontal"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_save_app_pair"
|
||||
style="@style/GoOverviewActionButton"
|
||||
@@ -128,8 +139,8 @@
|
||||
android:layout_height="wrap_content"
|
||||
android:drawableStart="@drawable/ic_save_app_pair_up_down"
|
||||
android:text="@string/action_save_app_pair"
|
||||
android:theme="@style/ThemeControlHighlightWorkspaceColor"
|
||||
android:visibility="gone" />
|
||||
android:theme="@style/ThemeControlHighlightWorkspaceColor" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.quickstep.views.GoOverviewActionsView>
|
||||
@@ -45,14 +45,24 @@
|
||||
android:theme="@style/ThemeControlHighlightWorkspaceColor"
|
||||
android:visibility="gone" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/group_action_buttons"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="@dimen/overview_actions_height"
|
||||
android:layout_gravity="bottom|center_horizontal"
|
||||
android:orientation="horizontal"
|
||||
android:visibility="gone">
|
||||
|
||||
<Button
|
||||
android:id="@+id/action_save_app_pair"
|
||||
style="@style/OverviewActionButton"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action_save_app_pair"
|
||||
android:theme="@style/ThemeControlHighlightWorkspaceColor"
|
||||
android:visibility="gone" />
|
||||
android:theme="@style/ThemeControlHighlightWorkspaceColor" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.android.quickstep.views.OverviewActionsView>
|
||||
@@ -28,10 +28,7 @@
|
||||
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
|
||||
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
|
||||
|
||||
<com.android.quickstep.views.TaskThumbnailViewDeprecated
|
||||
android:id="@+id/snapshot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<include layout="@layout/task_thumbnail" />
|
||||
|
||||
<!-- Filtering affects only alpha instead of the visibility since visibility can be altered
|
||||
separately through RecentsView#resetFromSplitSelectionState() -->
|
||||
|
||||
@@ -42,10 +42,7 @@
|
||||
views that do not inherint from TaskView only or create a generic TaskView that have
|
||||
N number of tasks.
|
||||
-->
|
||||
<com.android.quickstep.views.TaskThumbnailViewDeprecated
|
||||
android:id="@+id/snapshot"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
<include layout="@layout/task_thumbnail"
|
||||
android:visibility="gone" />
|
||||
|
||||
<ViewStub
|
||||
|
||||
@@ -33,15 +33,10 @@
|
||||
launcher:focusBorderColor="?androidprv:attr/materialColorOutline"
|
||||
launcher:hoverBorderColor="?androidprv:attr/materialColorPrimary">
|
||||
|
||||
<com.android.quickstep.views.TaskThumbnailViewDeprecated
|
||||
android:id="@+id/snapshot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<include layout="@layout/task_thumbnail"/>
|
||||
|
||||
<com.android.quickstep.views.TaskThumbnailViewDeprecated
|
||||
android:id="@+id/bottomright_snapshot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"/>
|
||||
<include layout="@layout/task_thumbnail"
|
||||
android:id="@+id/bottomright_snapshot" />
|
||||
|
||||
<!-- Filtering affects only alpha instead of the visibility since visibility can be altered
|
||||
separately through RecentsView#resetFromSplitSelectionState() -->
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
Copyright (C) 2024 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.
|
||||
-->
|
||||
<com.android.quickstep.views.TaskThumbnailViewDeprecated
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/snapshot"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent" />
|
||||
@@ -95,7 +95,7 @@
|
||||
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Einstellungen der Systemsteuerung"</annotation></string>
|
||||
<string name="action_share" msgid="2648470652637092375">"Teilen"</string>
|
||||
<string name="action_screenshot" msgid="8171125848358142917">"Screenshot"</string>
|
||||
<string name="action_split" msgid="2098009717623550676">"Teilen"</string>
|
||||
<string name="action_split" msgid="2098009717623550676">"Splitscreen"</string>
|
||||
<string name="action_save_app_pair" msgid="5974823919237645229">"App-Paar speichern"</string>
|
||||
<string name="toast_split_select_app" msgid="8464310533320556058">"Für Splitscreen auf weitere App tippen"</string>
|
||||
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Für Splitscreen andere App auswählen"</string>
|
||||
|
||||
@@ -118,7 +118,7 @@
|
||||
<string name="taskbar_edu_pinning_title" msgid="210102174154211712">"Mostrar siempre la barra de tareas"</string>
|
||||
<string name="taskbar_edu_pinning_standalone" msgid="2636919474366410467">"Para mostrar siempre la barra de tareas en la parte inferior, mantén pulsada la línea divisoria"</string>
|
||||
<string name="taskbar_search_edu_title" msgid="5569194922234364530">"Mantén pulsada la tecla de acción para buscar lo que ves en pantalla"</string>
|
||||
<string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"El producto usa la parte seleccionada de tu pantalla para hacer búsquedas. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> y los <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Términos del Servicio<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
|
||||
<string name="taskbar_edu_search_disclosure" msgid="8734536088447779686">"Este producto usa la parte seleccionada de tu pantalla para hacer búsquedas. Se aplican la <xliff:g id="BEGIN_PRIVACY_LINK"><a href="%1$s"></xliff:g>Política de Privacidad<xliff:g id="END_PRIVACY_LINK"></a></xliff:g> y los <xliff:g id="BEGIN_TOS_LINK"><a href="%2$s"></xliff:g>Términos del Servicio<xliff:g id="END_TOS_LINK"></a></xliff:g> de Google."</string>
|
||||
<string name="taskbar_edu_close" msgid="887022990168191073">"Cerrar"</string>
|
||||
<string name="taskbar_edu_done" msgid="6880178093977704569">"Hecho"</string>
|
||||
<string name="taskbar_button_home" msgid="2151398979630664652">"Inicio"</string>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Süsteemi navigeerimisseaded"</annotation></string>
|
||||
<string name="action_share" msgid="2648470652637092375">"Jaga"</string>
|
||||
<string name="action_screenshot" msgid="8171125848358142917">"Ekraanipilt"</string>
|
||||
<string name="action_split" msgid="2098009717623550676">"Eralda"</string>
|
||||
<string name="action_split" msgid="2098009717623550676">"Jaga pooleks"</string>
|
||||
<string name="action_save_app_pair" msgid="5974823919237645229">"Salvesta rakendusepaar"</string>
|
||||
<string name="toast_split_select_app" msgid="8464310533320556058">"Jagatud ekraanikuva kasutamiseks puudutage muud rakendust"</string>
|
||||
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Valige jagatud ekraanikuva jaoks muu rakendus."</string>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"Järjestelmän navigointiasetukset"</annotation></string>
|
||||
<string name="action_share" msgid="2648470652637092375">"Jaa"</string>
|
||||
<string name="action_screenshot" msgid="8171125848358142917">"Kuvakaappaus"</string>
|
||||
<string name="action_split" msgid="2098009717623550676">"Jaa"</string>
|
||||
<string name="action_split" msgid="2098009717623550676">"Jaettu näyttö"</string>
|
||||
<string name="action_save_app_pair" msgid="5974823919237645229">"Tallenna pari"</string>
|
||||
<string name="toast_split_select_app" msgid="8464310533320556058">"Avaa jaettu näyttö napauttamalla toista sovellusta"</string>
|
||||
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"Käytä jaettua näyttöä valitsemalla toinen sovellus"</string>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"စနစ် လမ်းညွှန် ဆက်တင်များ"</annotation></string>
|
||||
<string name="action_share" msgid="2648470652637092375">"မျှဝေရန်"</string>
|
||||
<string name="action_screenshot" msgid="8171125848358142917">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
|
||||
<string name="action_split" msgid="2098009717623550676">"ခွဲထုတ်ရန်"</string>
|
||||
<string name="action_split" msgid="2098009717623550676">"ခွဲရန်"</string>
|
||||
<string name="action_save_app_pair" msgid="5974823919237645229">"အက်ပ်အတွဲ သိမ်းရန်"</string>
|
||||
<string name="toast_split_select_app" msgid="8464310533320556058">"မျက်နှာပြင် ခွဲ၍ပြသရန် အက်ပ်နောက်တစ်ခုကို တို့ပါ"</string>
|
||||
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းသုံးရန် နောက်အက်ပ်တစ်ခုရွေးပါ"</string>
|
||||
|
||||
@@ -95,7 +95,7 @@
|
||||
<string name="allset_navigation_settings" msgid="4713404605961476027"><annotation id="link">"系统导航设置"</annotation></string>
|
||||
<string name="action_share" msgid="2648470652637092375">"分享"</string>
|
||||
<string name="action_screenshot" msgid="8171125848358142917">"屏幕截图"</string>
|
||||
<string name="action_split" msgid="2098009717623550676">"拆分"</string>
|
||||
<string name="action_split" msgid="2098009717623550676">"分屏"</string>
|
||||
<string name="action_save_app_pair" msgid="5974823919237645229">"保存应用组合"</string>
|
||||
<string name="toast_split_select_app" msgid="8464310533320556058">"点按另一个应用即可使用分屏"</string>
|
||||
<string name="toast_contextual_split_select_app" msgid="433510957123687090">"另外选择一个应用才可使用分屏模式"</string>
|
||||
|
||||
@@ -965,7 +965,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
mWindowLayoutParams.paramsForRotation[rot].height = size;
|
||||
}
|
||||
}
|
||||
mControllers.taskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
|
||||
mControllers.runAfterInit(
|
||||
mControllers.taskbarInsetsController
|
||||
::onTaskbarOrBubblebarWindowHeightOrInsetsChanged);
|
||||
notifyUpdateLayoutParams();
|
||||
}
|
||||
|
||||
@@ -1451,7 +1453,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
|
||||
});
|
||||
}
|
||||
|
||||
protected boolean isUserSetupComplete() {
|
||||
public boolean isUserSetupComplete() {
|
||||
return mIsUserSetupComplete;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,8 +24,10 @@ import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Space
|
||||
import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.R
|
||||
import com.android.launcher3.Utilities
|
||||
import com.android.launcher3.taskbar.TaskbarActivityContext
|
||||
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter
|
||||
|
||||
/**
|
||||
@@ -73,6 +75,23 @@ abstract class AbstractNavButtonLayoutter(
|
||||
return params
|
||||
}
|
||||
|
||||
fun adjustForSetupInPhoneMode(
|
||||
navButtonsLayoutParams: FrameLayout.LayoutParams,
|
||||
navButtonsViewLayoutParams: FrameLayout.LayoutParams,
|
||||
deviceProfile: DeviceProfile
|
||||
) {
|
||||
val phoneOrPortraitSetupMargin =
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_margin)
|
||||
navButtonsLayoutParams.marginStart = phoneOrPortraitSetupMargin
|
||||
navButtonsLayoutParams.bottomMargin =
|
||||
if (!deviceProfile.isLandscape) 0
|
||||
else
|
||||
phoneOrPortraitSetupMargin -
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) / 2
|
||||
navButtonsViewLayoutParams.height =
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_height)
|
||||
}
|
||||
|
||||
open fun repositionContextualContainer(
|
||||
contextualContainer: ViewGroup,
|
||||
buttonSize: Int,
|
||||
|
||||
@@ -116,6 +116,7 @@ class NavButtonLayoutFactory {
|
||||
isPhoneGestureMode -> {
|
||||
PhoneGestureLayoutter(
|
||||
resources,
|
||||
navButtonsView,
|
||||
navButtonContainer,
|
||||
endContextualContainer,
|
||||
startContextualContainer,
|
||||
|
||||
@@ -17,15 +17,19 @@
|
||||
package com.android.launcher3.taskbar.navbutton
|
||||
|
||||
import android.content.res.Resources
|
||||
import android.view.Gravity
|
||||
import android.view.ViewGroup
|
||||
import android.widget.FrameLayout
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Space
|
||||
import com.android.launcher3.DeviceProfile
|
||||
import com.android.launcher3.taskbar.TaskbarActivityContext
|
||||
|
||||
/** Layoutter for showing gesture navigation on phone screen. No buttons here, no-op container */
|
||||
class PhoneGestureLayoutter(
|
||||
resources: Resources,
|
||||
navButtonsView: NearestTouchFrame,
|
||||
navBarContainer: LinearLayout,
|
||||
endContextualContainer: ViewGroup,
|
||||
startContextualContainer: ViewGroup,
|
||||
@@ -42,8 +46,31 @@ class PhoneGestureLayoutter(
|
||||
a11yButton,
|
||||
space
|
||||
) {
|
||||
private val mNavButtonsView = navButtonsView
|
||||
|
||||
override fun layoutButtons(context: TaskbarActivityContext, isA11yButtonPersistent: Boolean) {
|
||||
// TODO: look into if we should use SetupNavLayoutter instead.
|
||||
if (!context.isUserSetupComplete) {
|
||||
// Since setup wizard only has back button enabled, it looks strange to be
|
||||
// end-aligned, so start-align instead.
|
||||
val navButtonsLayoutParams = navButtonContainer.layoutParams as FrameLayout.LayoutParams
|
||||
val navButtonsViewLayoutParams =
|
||||
mNavButtonsView.layoutParams as FrameLayout.LayoutParams
|
||||
val deviceProfile: DeviceProfile = context.deviceProfile
|
||||
|
||||
navButtonsLayoutParams.marginEnd = 0
|
||||
navButtonsLayoutParams.gravity = Gravity.START
|
||||
context.setTaskbarWindowSize(context.setupWindowSize)
|
||||
|
||||
adjustForSetupInPhoneMode(
|
||||
navButtonsLayoutParams,
|
||||
navButtonsViewLayoutParams,
|
||||
deviceProfile
|
||||
)
|
||||
mNavButtonsView.layoutParams = navButtonsViewLayoutParams
|
||||
navButtonContainer.layoutParams = navButtonsLayoutParams
|
||||
}
|
||||
|
||||
endContextualContainer.removeAllViews()
|
||||
startContextualContainer.removeAllViews()
|
||||
}
|
||||
|
||||
@@ -77,16 +77,11 @@ class SetupNavLayoutter(
|
||||
navButtonsLayoutParams.height =
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_back_button_suw_height)
|
||||
} else {
|
||||
val phoneOrPortraitSetupMargin =
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_margin)
|
||||
navButtonsLayoutParams.marginStart = phoneOrPortraitSetupMargin
|
||||
navButtonsLayoutParams.bottomMargin =
|
||||
if (!deviceProfile.isLandscape) 0
|
||||
else
|
||||
phoneOrPortraitSetupMargin -
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) / 2
|
||||
navButtonsViewLayoutParams.height =
|
||||
resources.getDimensionPixelSize(R.dimen.taskbar_contextual_button_suw_height)
|
||||
adjustForSetupInPhoneMode(
|
||||
navButtonsLayoutParams,
|
||||
navButtonsViewLayoutParams,
|
||||
deviceProfile
|
||||
)
|
||||
}
|
||||
mNavButtonsView.layoutParams = navButtonsViewLayoutParams
|
||||
navButtonContainer.layoutParams = navButtonsLayoutParams
|
||||
|
||||
@@ -21,7 +21,6 @@ import static com.android.launcher3.LauncherState.OVERVIEW;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS;
|
||||
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
|
||||
import static com.android.launcher3.states.StateAnimationConfig.ANIM_OVERVIEW_ACTIONS_FADE;
|
||||
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
|
||||
import static com.android.quickstep.views.RecentsView.CONTENT_ALPHA;
|
||||
import static com.android.quickstep.views.RecentsView.FULLSCREEN_PROGRESS;
|
||||
import static com.android.quickstep.views.RecentsView.TASK_MODALNESS;
|
||||
@@ -50,6 +49,7 @@ import com.android.quickstep.util.AnimUtils;
|
||||
import com.android.quickstep.util.SplitAnimationTimings;
|
||||
import com.android.quickstep.views.ClearAllButton;
|
||||
import com.android.quickstep.views.LauncherRecentsView;
|
||||
import com.android.quickstep.views.OverviewActionsView;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
|
||||
/**
|
||||
@@ -167,8 +167,8 @@ public final class RecentsViewStateController extends
|
||||
propertySetter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
|
||||
clearAllButtonAlpha, LINEAR);
|
||||
float overviewButtonAlpha = state.areElementsVisible(mLauncher, OVERVIEW_ACTIONS) ? 1 : 0;
|
||||
propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlpha(),
|
||||
MULTI_PROPERTY_VALUE, overviewButtonAlpha, config.getInterpolator(
|
||||
propertySetter.setFloat(mLauncher.getActionsView().getVisibilityAlphaSetter(),
|
||||
OverviewActionsView.FLOAT_SETTER, overviewButtonAlpha, config.getInterpolator(
|
||||
ANIM_OVERVIEW_ACTIONS_FADE, LINEAR));
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -248,7 +248,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController,
|
||||
TASK_THUMBNAIL_SPLASH_ALPHA.set(mRecentsView, fromState.showTaskThumbnailSplash() ? 1f : 0);
|
||||
mRecentsView.setContentAlpha(1);
|
||||
mRecentsView.setFullscreenProgress(fromState.getOverviewFullscreenProgress());
|
||||
mLauncher.getActionsView().getVisibilityAlpha().setValue(
|
||||
mLauncher.getActionsView().getVisibilityAlphaSetter().accept(
|
||||
(fromState.getVisibleElements(mLauncher) & OVERVIEW_ACTIONS) != 0 ? 1f : 0f);
|
||||
mRecentsView.setTaskIconScaledDown(true);
|
||||
|
||||
|
||||
@@ -154,7 +154,7 @@ class DeviceConfigWrapper private constructor(propReader: PropReader) {
|
||||
}
|
||||
|
||||
companion object {
|
||||
val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
|
||||
@JvmStatic val configHelper by lazy { DeviceConfigHelper(::DeviceConfigWrapper) }
|
||||
|
||||
@JvmStatic fun get() = configHelper.config
|
||||
}
|
||||
|
||||
@@ -65,7 +65,6 @@ import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFutur
|
||||
import com.android.systemui.shared.recents.view.RecentsTransition;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.Function;
|
||||
@@ -336,7 +335,7 @@ public interface TaskShortcutFactory {
|
||||
recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView));
|
||||
boolean shouldShowActionsButtonInstead =
|
||||
isLargeTileFocusedTask && isInExpectedScrollPosition;
|
||||
boolean hasUnpinnableApp = Arrays.stream(taskView.getTaskContainers())
|
||||
boolean hasUnpinnableApp = taskView.getTaskContainers().stream()
|
||||
.anyMatch(att -> att != null && att.getItemInfo() != null
|
||||
&& ((att.getItemInfo().runtimeStatusFlags
|
||||
& ItemInfoWithIcon.FLAG_NOT_PINNABLE) != 0));
|
||||
|
||||
@@ -46,12 +46,10 @@ import com.android.launcher3.anim.PendingAnimation;
|
||||
import com.android.launcher3.anim.PropertySetter;
|
||||
import com.android.launcher3.statemanager.StateManager.StateHandler;
|
||||
import com.android.launcher3.states.StateAnimationConfig;
|
||||
import com.android.launcher3.util.MultiPropertyFactory;
|
||||
import com.android.quickstep.RecentsActivity;
|
||||
import com.android.quickstep.views.ClearAllButton;
|
||||
import com.android.quickstep.views.OverviewActionsView;
|
||||
import com.android.quickstep.views.RecentsView;
|
||||
import com.android.quickstep.views.RecentsViewContainer;
|
||||
|
||||
/**
|
||||
* State controller for fallback recents activity
|
||||
@@ -98,8 +96,8 @@ public class FallbackRecentsStateController implements StateHandler<RecentsState
|
||||
setter.setFloat(mRecentsView.getClearAllButton(), ClearAllButton.VISIBILITY_ALPHA,
|
||||
clearAllButtonAlpha, LINEAR);
|
||||
float overviewButtonAlpha = state.hasOverviewActions() ? 1 : 0;
|
||||
setter.setFloat(mActivity.getActionsView().getVisibilityAlpha(),
|
||||
MultiPropertyFactory.MULTI_PROPERTY_VALUE, overviewButtonAlpha, LINEAR);
|
||||
setter.setFloat(mActivity.getActionsView().getVisibilityAlphaSetter(),
|
||||
OverviewActionsView.FLOAT_SETTER, overviewButtonAlpha, LINEAR);
|
||||
|
||||
float[] scaleAndOffset = state.getOverviewScaleAndOffset(mActivity);
|
||||
setter.setFloat(mRecentsView, RECENTS_SCALE_PROPERTY, scaleAndOffset[0],
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.recents.viewmodel
|
||||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
// This is far from complete but serves the purpose of enabling refactoring in other areas
|
||||
class RecentsViewData {
|
||||
val fullscreenProgress = MutableStateFlow(1f)
|
||||
|
||||
// This is typically a View concern but it is used to invalidate rendering in other Views
|
||||
val scale = MutableStateFlow(1f)
|
||||
}
|
||||
@@ -17,22 +17,44 @@
|
||||
package com.android.quickstep.task.thumbnail
|
||||
|
||||
import android.content.Context
|
||||
import android.content.res.Configuration
|
||||
import android.graphics.Canvas
|
||||
import android.graphics.Outline
|
||||
import android.graphics.Paint
|
||||
import android.graphics.PorterDuff
|
||||
import android.graphics.PorterDuffXfermode
|
||||
import android.util.AttributeSet
|
||||
import android.view.View
|
||||
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.*
|
||||
import android.view.ViewOutlineProvider
|
||||
import com.android.launcher3.Utilities
|
||||
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
|
||||
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
|
||||
import com.android.quickstep.util.TaskCornerRadius
|
||||
import com.android.quickstep.views.RecentsView
|
||||
import com.android.quickstep.views.RecentsViewContainer
|
||||
import com.android.quickstep.views.TaskView
|
||||
import com.android.systemui.shared.system.QuickStepContract
|
||||
import kotlinx.coroutines.MainScope
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
class TaskThumbnailView : View {
|
||||
// TODO(b/335649589): Ideally create and obtain this from DI. This ViewModel should be scoped
|
||||
// to [TaskView], and also shared between [TaskView] and [TaskThumbnailView]
|
||||
val viewModel = TaskThumbnailViewModel()
|
||||
// This is using a lazy for now because the dependencies cannot be obtained without DI.
|
||||
val viewModel by lazy {
|
||||
TaskThumbnailViewModel(
|
||||
RecentsViewContainer.containerFromContext<RecentsViewContainer>(context)
|
||||
.getOverviewPanel<RecentsView<*, *>>()
|
||||
.mRecentsViewData,
|
||||
(parent as TaskView).mTaskViewData
|
||||
)
|
||||
}
|
||||
|
||||
private var uiState: TaskThumbnailUiState = Uninitialized
|
||||
private var inheritedScale: Float = 1f
|
||||
|
||||
private var cornerRadius: Float = TaskCornerRadius.get(context)
|
||||
private var fullscreenCornerRadius: Float = QuickStepContract.getWindowCornerRadius(context)
|
||||
|
||||
constructor(context: Context?) : super(context)
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
|
||||
@@ -51,6 +73,27 @@ class TaskThumbnailView : View {
|
||||
invalidate()
|
||||
}
|
||||
}
|
||||
MainScope().launch { viewModel.recentsFullscreenProgress.collect { invalidateOutline() } }
|
||||
MainScope().launch {
|
||||
viewModel.inheritedScale.collect { viewModelInheritedScale ->
|
||||
inheritedScale = viewModelInheritedScale
|
||||
invalidateOutline()
|
||||
}
|
||||
}
|
||||
|
||||
clipToOutline = true
|
||||
outlineProvider =
|
||||
object : ViewOutlineProvider() {
|
||||
override fun getOutline(view: View, outline: Outline) {
|
||||
outline.setRoundRect(
|
||||
0,
|
||||
0,
|
||||
view.measuredWidth,
|
||||
view.measuredHeight,
|
||||
getCurrentCornerRadius()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onDraw(canvas: Canvas) {
|
||||
@@ -60,19 +103,25 @@ class TaskThumbnailView : View {
|
||||
}
|
||||
}
|
||||
|
||||
private fun drawTransparentUiState(canvas: Canvas) {
|
||||
canvas.drawRoundRect(
|
||||
0f,
|
||||
0f,
|
||||
measuredWidth.toFloat(),
|
||||
measuredHeight.toFloat(),
|
||||
// TODO(b/334826840) add rounded corners
|
||||
0f,
|
||||
0f,
|
||||
CLEAR_PAINT
|
||||
)
|
||||
override fun onConfigurationChanged(newConfig: Configuration?) {
|
||||
super.onConfigurationChanged(newConfig)
|
||||
|
||||
cornerRadius = TaskCornerRadius.get(context)
|
||||
fullscreenCornerRadius = QuickStepContract.getWindowCornerRadius(context)
|
||||
invalidateOutline()
|
||||
}
|
||||
|
||||
private fun drawTransparentUiState(canvas: Canvas) {
|
||||
canvas.drawRect(0f, 0f, measuredWidth.toFloat(), measuredHeight.toFloat(), CLEAR_PAINT)
|
||||
}
|
||||
|
||||
private fun getCurrentCornerRadius() =
|
||||
Utilities.mapRange(
|
||||
viewModel.recentsFullscreenProgress.value,
|
||||
cornerRadius,
|
||||
fullscreenCornerRadius
|
||||
) / inheritedScale
|
||||
|
||||
companion object {
|
||||
private val CLEAR_PAINT =
|
||||
Paint().apply { xfermode = PorterDuffXfermode(PorterDuff.Mode.CLEAR) }
|
||||
|
||||
@@ -16,20 +16,32 @@
|
||||
|
||||
package com.android.quickstep.task.thumbnail
|
||||
|
||||
import com.android.quickstep.recents.viewmodel.RecentsViewData
|
||||
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.LiveTile
|
||||
import com.android.quickstep.task.thumbnail.TaskThumbnailUiState.Uninitialized
|
||||
import com.android.quickstep.task.viewmodel.TaskViewData
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.combine
|
||||
import kotlinx.coroutines.flow.map
|
||||
|
||||
class TaskThumbnailViewModel {
|
||||
private val _uiState: MutableStateFlow<TaskThumbnailUiState> =
|
||||
MutableStateFlow(TaskThumbnailUiState.Uninitialized)
|
||||
val uiState: StateFlow<TaskThumbnailUiState> = _uiState
|
||||
class TaskThumbnailViewModel(recentsViewData: RecentsViewData, taskViewData: TaskViewData) {
|
||||
private val task = MutableStateFlow<TaskThumbnail?>(null)
|
||||
|
||||
val recentsFullscreenProgress = recentsViewData.fullscreenProgress
|
||||
val inheritedScale =
|
||||
combine(recentsViewData.scale, taskViewData.scale) { recentsScale, taskScale ->
|
||||
recentsScale * taskScale
|
||||
}
|
||||
val uiState =
|
||||
task.map { taskVal ->
|
||||
when {
|
||||
taskVal == null -> Uninitialized
|
||||
taskVal.isRunning -> LiveTile
|
||||
else -> Uninitialized
|
||||
}
|
||||
}
|
||||
|
||||
fun bind(task: TaskThumbnail) {
|
||||
_uiState.value =
|
||||
if (task.isRunning) {
|
||||
TaskThumbnailUiState.LiveTile
|
||||
} else {
|
||||
TaskThumbnailUiState.Uninitialized
|
||||
}
|
||||
this.task.value = task
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2024 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.task.viewmodel
|
||||
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
|
||||
class TaskViewData {
|
||||
// This is typically a View concern but it is used to invalidate rendering in other Views
|
||||
val scale = MutableStateFlow(1f)
|
||||
}
|
||||
@@ -116,9 +116,9 @@ public class AppPairsController {
|
||||
*/
|
||||
public void saveAppPair(GroupedTaskView gtv) {
|
||||
InteractionJankMonitorWrapper.begin(gtv, Cuj.CUJ_LAUNCHER_SAVE_APP_PAIR);
|
||||
TaskView.TaskContainer[] containers = gtv.getTaskContainers();
|
||||
WorkspaceItemInfo recentsInfo1 = containers[0].getItemInfo();
|
||||
WorkspaceItemInfo recentsInfo2 = containers[1].getItemInfo();
|
||||
List<TaskView.TaskContainer> containers = gtv.getTaskContainers();
|
||||
WorkspaceItemInfo recentsInfo1 = containers.get(0).getItemInfo();
|
||||
WorkspaceItemInfo recentsInfo2 = containers.get(1).getItemInfo();
|
||||
WorkspaceItemInfo app1 = lookupLaunchableItem(recentsInfo1.getComponentKey());
|
||||
WorkspaceItemInfo app2 = lookupLaunchableItem(recentsInfo2.getComponentKey());
|
||||
|
||||
|
||||
@@ -48,12 +48,14 @@ class DeviceConfigHelper<ConfigType>(private val factory: (PropReader) -> Config
|
||||
PropReader(
|
||||
object : PropProvider {
|
||||
override fun <T : Any> get(key: String, fallback: T): T {
|
||||
if (fallback is Int)
|
||||
if (fallback is Int) {
|
||||
allKeys.add(key)
|
||||
return DeviceConfig.getInt(NAMESPACE_LAUNCHER, key, fallback) as T
|
||||
else if (fallback is Boolean)
|
||||
} else if (fallback is Boolean) {
|
||||
allKeys.add(key)
|
||||
return DeviceConfig.getBoolean(NAMESPACE_LAUNCHER, key, fallback)
|
||||
as T
|
||||
else return fallback
|
||||
} else return fallback
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
package com.android.quickstep.views;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_UNDEFINED;
|
||||
@@ -42,6 +42,7 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.desktop.DesktopRecentsTransitionController;
|
||||
import com.android.launcher3.util.CancellableTask;
|
||||
import com.android.launcher3.util.RunnableList;
|
||||
import com.android.launcher3.util.ViewPool;
|
||||
import com.android.quickstep.BaseContainerInterface;
|
||||
import com.android.quickstep.RecentsModel;
|
||||
import com.android.quickstep.TaskThumbnailCache;
|
||||
@@ -69,8 +70,6 @@ public class DesktopTaskView extends TaskView {
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final ArrayList<TaskThumbnailViewDeprecated> mSnapshotViews = new ArrayList<>();
|
||||
|
||||
private final ArrayList<CancellableTask<?>> mPendingThumbnailRequests = new ArrayList<>();
|
||||
|
||||
private final TaskView.FullscreenDrawParams mSnapshotDrawParams;
|
||||
@@ -81,6 +80,8 @@ public class DesktopTaskView extends TaskView {
|
||||
|
||||
private final PointF mTempPointF = new PointF();
|
||||
|
||||
private final ViewPool<TaskThumbnailViewDeprecated> mTaskthumbnailViewPool;
|
||||
|
||||
public DesktopTaskView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
@@ -103,6 +104,10 @@ public class DesktopTaskView extends TaskView {
|
||||
return QuickStepContract.getWindowCornerRadius(context);
|
||||
}
|
||||
};
|
||||
// As DesktopTaskView is inflated in background, use initialSize=0 to avoid initPool.
|
||||
mTaskthumbnailViewPool = new ViewPool<>(context, this, R.layout.task_thumbnail,
|
||||
/* maxSize= */10, /* initialSize= */ 0);
|
||||
mTaskContainers = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -163,45 +168,36 @@ public class DesktopTaskView extends TaskView {
|
||||
}
|
||||
cancelPendingLoadTasks();
|
||||
|
||||
mTaskContainers = new TaskContainer[tasks.size()];
|
||||
|
||||
// Ensure there are equal number of snapshot views and tasks.
|
||||
// More tasks than views, add views. More views than tasks, remove views.
|
||||
// TODO(b/251586230): use a ViewPool for creating TaskThumbnailViews
|
||||
if (mSnapshotViews.size() > tasks.size()) {
|
||||
int diff = mSnapshotViews.size() - tasks.size();
|
||||
for (int i = 0; i < diff; i++) {
|
||||
TaskThumbnailViewDeprecated snapshotView = mSnapshotViews.remove(0);
|
||||
removeView(snapshotView);
|
||||
}
|
||||
} else if (mSnapshotViews.size() < tasks.size()) {
|
||||
int diff = tasks.size() - mSnapshotViews.size();
|
||||
for (int i = 0; i < diff; i++) {
|
||||
TaskThumbnailViewDeprecated snapshotView =
|
||||
new TaskThumbnailViewDeprecated(getContext());
|
||||
mSnapshotViews.add(snapshotView);
|
||||
// Add snapshots from to position after the initial child views.
|
||||
addView(snapshotView, mChildCountAtInflation,
|
||||
new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||
}
|
||||
}
|
||||
|
||||
((ArrayList<TaskContainer>) mTaskContainers).ensureCapacity(tasks.size());
|
||||
for (int i = 0; i < tasks.size(); i++) {
|
||||
Task task = tasks.get(i);
|
||||
TaskThumbnailViewDeprecated thumbnailView = mSnapshotViews.get(i);
|
||||
TaskThumbnailViewDeprecated thumbnailView;
|
||||
if (i >= mTaskContainers.size()) {
|
||||
thumbnailView = mTaskthumbnailViewPool.getView();
|
||||
// Add thumbnailView from to position after the initial child views.
|
||||
addView(thumbnailView, mChildCountAtInflation,
|
||||
new LayoutParams(WRAP_CONTENT, WRAP_CONTENT));
|
||||
} else {
|
||||
thumbnailView = mTaskContainers.get(i).getThumbnailView();
|
||||
}
|
||||
thumbnailView.bind(task);
|
||||
mTaskContainers[i] = createAttributeContainer(task, thumbnailView);
|
||||
TaskContainer taskContainer = new TaskContainer(task, thumbnailView, mIconView,
|
||||
STAGE_POSITION_UNDEFINED, /*digitalWellBeingToast=*/ null);
|
||||
if (i >= mTaskContainers.size()) {
|
||||
mTaskContainers.add(taskContainer);
|
||||
} else {
|
||||
mTaskContainers.set(i, taskContainer);
|
||||
}
|
||||
}
|
||||
while (mTaskContainers.size() > tasks.size()) {
|
||||
TaskContainer taskContainer = mTaskContainers.remove(mTaskContainers.size() - 1);
|
||||
removeView(taskContainer.getThumbnailView());
|
||||
mTaskthumbnailViewPool.recycle(taskContainer.getThumbnailView());
|
||||
}
|
||||
|
||||
setOrientationState(orientedState);
|
||||
}
|
||||
|
||||
private TaskContainer createAttributeContainer(Task task,
|
||||
TaskThumbnailViewDeprecated thumbnailView) {
|
||||
return new TaskContainer(task, thumbnailView, mIconView,
|
||||
STAGE_POSITION_UNDEFINED, /*digitalWellBeingToast=*/ null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskListVisibilityChanged(boolean visible, int changes) {
|
||||
cancelPendingLoadTasks();
|
||||
@@ -314,7 +310,7 @@ public class DesktopTaskView extends TaskView {
|
||||
int thumbnailTopMarginPx = mContainer.getDeviceProfile().overviewTaskThumbnailTopMarginPx;
|
||||
containerHeight -= thumbnailTopMarginPx;
|
||||
|
||||
if (mTaskContainers.length == 0) {
|
||||
if (mTaskContainers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -98,7 +98,7 @@ public class GroupedTaskView extends TaskView {
|
||||
@Deprecated
|
||||
@Nullable
|
||||
private Task getSecondTask() {
|
||||
return mTaskContainers.length > 1 ? mTaskContainers[1].getTask() : null;
|
||||
return mTaskContainers.size() > 1 ? mTaskContainers.get(1).getTask() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -150,11 +150,11 @@ public class GroupedTaskView extends TaskView {
|
||||
public void bind(Task primary, Task secondary, RecentsOrientedState orientedState,
|
||||
@Nullable SplitBounds splitBoundsConfig) {
|
||||
super.bind(primary, orientedState);
|
||||
mTaskContainers = new TaskContainer[]{
|
||||
mTaskContainers[0],
|
||||
mTaskContainers = Arrays.asList(
|
||||
mTaskContainers.get(0),
|
||||
new TaskContainer(secondary, findViewById(R.id.bottomright_snapshot),
|
||||
mIconView2, STAGE_POSITION_BOTTOM_OR_RIGHT, mDigitalWellBeingToast2)};
|
||||
mTaskContainers[0].setStagePosition(
|
||||
mIconView2, STAGE_POSITION_BOTTOM_OR_RIGHT, mDigitalWellBeingToast2));
|
||||
mTaskContainers.get(0).setStagePosition(
|
||||
SplitConfigurationOptions.STAGE_POSITION_TOP_OR_LEFT);
|
||||
mSnapshotView2.bind(secondary);
|
||||
mSplitBoundsConfig = splitBoundsConfig;
|
||||
@@ -176,12 +176,12 @@ public class GroupedTaskView extends TaskView {
|
||||
public void setUpShowAllInstancesListener() {
|
||||
// sets up the listener for the left/top task
|
||||
super.setUpShowAllInstancesListener();
|
||||
if (mTaskContainers.length < 2) {
|
||||
if (mTaskContainers.size() < 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
// right/bottom task's base package name
|
||||
String taskPackageName = mTaskContainers[1].getTask().key.getPackageName();
|
||||
String taskPackageName = mTaskContainers.get(1).getTask().key.getPackageName();
|
||||
|
||||
// icon of the right/bottom task
|
||||
View showWindowsView = findViewById(R.id.show_windows_right);
|
||||
@@ -279,7 +279,7 @@ public class GroupedTaskView extends TaskView {
|
||||
@Nullable
|
||||
@Override
|
||||
public RunnableList launchTaskAnimated() {
|
||||
if (mTaskContainers.length == 0) {
|
||||
if (mTaskContainers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -407,9 +407,8 @@ public class GroupedTaskView extends TaskView {
|
||||
} else {
|
||||
// Currently being split with this taskView, let the non-split selected thumbnail
|
||||
// take up full thumbnail area
|
||||
Optional<TaskContainer> nonSplitContainer = Arrays.stream(
|
||||
mTaskContainers).filter(
|
||||
container -> container.getTask().key.id != initSplitTaskId).findAny();
|
||||
Optional<TaskContainer> nonSplitContainer = mTaskContainers.stream().filter(
|
||||
container -> container.getTask().key.id != initSplitTaskId).findAny();
|
||||
nonSplitContainer.ifPresent(
|
||||
taskIdAttributeContainer -> taskIdAttributeContainer.getThumbnailView().measure(
|
||||
widthMeasureSpec, MeasureSpec.makeMeasureSpec(
|
||||
|
||||
@@ -20,6 +20,7 @@ import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Rect;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.FloatProperty;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.widget.Button;
|
||||
@@ -33,9 +34,7 @@ import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.Flags;
|
||||
import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
import com.android.launcher3.util.DisplayController;
|
||||
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
|
||||
import com.android.launcher3.util.MultiValueAlpha;
|
||||
import com.android.launcher3.util.NavigationMode;
|
||||
import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks;
|
||||
@@ -43,12 +42,26 @@ import com.android.quickstep.util.LayoutUtils;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.Arrays;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
/**
|
||||
* View for showing action buttons in Overview
|
||||
*/
|
||||
public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayout
|
||||
implements OnClickListener, Insettable {
|
||||
public static final FloatProperty<Consumer<Float>> FLOAT_SETTER =
|
||||
new FloatProperty<>("floatSetter") {
|
||||
@Override
|
||||
public void setValue(Consumer<Float> consumer, float v) {
|
||||
consumer.accept(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Float get(Consumer<Float> consumer) {
|
||||
return -1f;
|
||||
}
|
||||
};
|
||||
|
||||
private final Rect mInsets = new Rect();
|
||||
|
||||
@@ -89,30 +102,24 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
private static final int INDEX_HIDDEN_FLAGS_ALPHA = 3;
|
||||
private static final int INDEX_SHARE_TARGET_ALPHA = 4;
|
||||
private static final int INDEX_SCROLL_ALPHA = 5;
|
||||
private static final int NUM_ALPHAS = 6;
|
||||
|
||||
public @interface ScreenshotButtonHiddenFlags { }
|
||||
public static final int FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT = 1 << 0;
|
||||
private static final int INDEX_GROUPED_ALPHA = 6;
|
||||
private static final int INDEX_3P_LAUNCHER = 7;
|
||||
private static final int NUM_ALPHAS = 8;
|
||||
|
||||
public @interface SplitButtonHiddenFlags { }
|
||||
public static final int FLAG_SMALL_SCREEN_HIDE_SPLIT = 1 << 0;
|
||||
public static final int FLAG_MULTIPLE_TASKS_HIDE_SPLIT = 1 << 1;
|
||||
|
||||
public @interface SplitButtonDisabledFlags { }
|
||||
public static final int FLAG_SINGLE_TASK_DISABLE_SPLIT = 1 << 0;
|
||||
|
||||
public @interface AppPairButtonHiddenFlags { }
|
||||
public static final int FLAG_SINGLE_TASK_HIDE_APP_PAIR = 1 << 0;
|
||||
public static final int FLAG_SMALL_SCREEN_HIDE_APP_PAIR = 1 << 1;
|
||||
public static final int FLAG_3P_LAUNCHER_HIDE_APP_PAIR = 1 << 2;
|
||||
|
||||
private MultiValueAlpha mMultiValueAlpha;
|
||||
/** Holds MultiValueAlpha values for all actions buttons */
|
||||
private final MultiValueAlpha[] mMultiValueAlphas = new MultiValueAlpha[2];
|
||||
/** Index used for single-task actions in the mMultiValueAlphas array */
|
||||
private static final int ACTIONS_ALPHAS = 0;
|
||||
/** Index used for grouped-task actions in the mMultiValueAlphas array */
|
||||
private static final int GROUP_ACTIONS_ALPHAS = 1;
|
||||
|
||||
/** Container for the action buttons below a focused, non-split Overview tile. */
|
||||
protected LinearLayout mActionButtons;
|
||||
// The screenshot button is implemented as a Button in launcher3 and NexusLauncher, but is an
|
||||
// ImageButton in go launcher (does not share a common class with Button). Take care when
|
||||
// casting this.
|
||||
private View mScreenshotButton;
|
||||
/** Container for the action buttons below a focused, split Overview tile. */
|
||||
protected LinearLayout mGroupActionButtons;
|
||||
private Button mSplitButton;
|
||||
private Button mSaveAppPairButton;
|
||||
|
||||
@@ -122,21 +129,16 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
@ActionsDisabledFlags
|
||||
protected int mDisabledFlags;
|
||||
|
||||
@ScreenshotButtonHiddenFlags
|
||||
private int mScreenshotButtonHiddenFlags;
|
||||
|
||||
@SplitButtonHiddenFlags
|
||||
private int mSplitButtonHiddenFlags;
|
||||
|
||||
@AppPairButtonHiddenFlags
|
||||
private int mAppPairButtonHiddenFlags;
|
||||
|
||||
@Nullable
|
||||
protected T mCallbacks;
|
||||
|
||||
@Nullable
|
||||
protected DeviceProfile mDp;
|
||||
private final Rect mTaskSize = new Rect();
|
||||
private boolean mIsGroupedTask = false;
|
||||
|
||||
public OverviewActionsView(Context context) {
|
||||
this(context, null);
|
||||
@@ -153,12 +155,21 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
// Initialize 2 view containers: one for single tasks, one for grouped tasks.
|
||||
// These will take up the same space on the screen and alternate visibility as needed.
|
||||
mActionButtons = findViewById(R.id.action_buttons);
|
||||
mMultiValueAlpha = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
|
||||
mMultiValueAlpha.setUpdateVisibility(true);
|
||||
mGroupActionButtons = findViewById(R.id.group_action_buttons);
|
||||
// Initialize a list to set alpha on mActionButtons and mGroupActionButtons simultaneously.
|
||||
mMultiValueAlphas[ACTIONS_ALPHAS] = new MultiValueAlpha(mActionButtons, NUM_ALPHAS);
|
||||
mMultiValueAlphas[GROUP_ACTIONS_ALPHAS] =
|
||||
new MultiValueAlpha(mGroupActionButtons, NUM_ALPHAS);
|
||||
Arrays.stream(mMultiValueAlphas).forEach(a -> a.setUpdateVisibility(true));
|
||||
|
||||
mScreenshotButton = findViewById(R.id.action_screenshot);
|
||||
mScreenshotButton.setOnClickListener(this);
|
||||
// The screenshot button is implemented as a Button in launcher3 and NexusLauncher, but is
|
||||
// an ImageButton in go launcher (does not share a common class with Button). Take care when
|
||||
// casting this.
|
||||
View screenshotButton = findViewById(R.id.action_screenshot);
|
||||
screenshotButton.setOnClickListener(this);
|
||||
mSplitButton = findViewById(R.id.action_split);
|
||||
mSplitButton.setOnClickListener(this);
|
||||
mSaveAppPairButton = findViewById(R.id.action_save_app_pair);
|
||||
@@ -209,7 +220,7 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
mHiddenFlags &= ~visibilityFlags;
|
||||
}
|
||||
boolean isHidden = mHiddenFlags != 0;
|
||||
mMultiValueAlpha.get(INDEX_HIDDEN_FLAGS_ALPHA).setValue(isHidden ? 0 : 1);
|
||||
setActionsAlpha(INDEX_HIDDEN_FLAGS_ALPHA, isHidden ? 0 : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -236,12 +247,8 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
* @param isGroupedTask True if the focused task is a grouped task.
|
||||
*/
|
||||
public void updateForGroupedTask(boolean isGroupedTask) {
|
||||
// Update flags to see if split button should be hidden.
|
||||
updateSplitButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SPLIT, isGroupedTask);
|
||||
// Update flags to see if screenshot button should be hidden.
|
||||
updateScreenshotButtonHiddenFlags(FLAG_MULTIPLE_TASKS_HIDE_SCREENSHOT, isGroupedTask);
|
||||
// Update flags to see if save app pair button should be hidden.
|
||||
updateAppPairButtonHiddenFlags(FLAG_SINGLE_TASK_HIDE_APP_PAIR, !isGroupedTask);
|
||||
mIsGroupedTask = isGroupedTask;
|
||||
updateActionButtonsVisibility();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,36 +258,30 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
assert mDp != null;
|
||||
// Update flags to see if split button should be hidden.
|
||||
updateSplitButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_SPLIT, !mDp.isTablet);
|
||||
// Update flags to see if save app pair button should be hidden.
|
||||
updateAppPairButtonHiddenFlags(FLAG_SMALL_SCREEN_HIDE_APP_PAIR, !mDp.isTablet);
|
||||
updateActionButtonsVisibility();
|
||||
}
|
||||
|
||||
private void updateActionButtonsVisibility() {
|
||||
assert mDp != null;
|
||||
boolean showSingleTaskActions = !mIsGroupedTask;
|
||||
boolean showGroupActions = mIsGroupedTask && mDp.isTablet;
|
||||
getActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showSingleTaskActions ? 1 : 0);
|
||||
getGroupActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showGroupActions ? 1 : 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates flags to hide and show actions buttons for 1p/3p launchers.
|
||||
*/
|
||||
public void updateFor3pLauncher(boolean is3pLauncher) {
|
||||
updateAppPairButtonHiddenFlags(FLAG_3P_LAUNCHER_HIDE_APP_PAIR, is3pLauncher);
|
||||
getGroupActionsAlphas().get(INDEX_3P_LAUNCHER).setValue(is3pLauncher ? 0 : 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the proper flags to indicate whether the "Screenshot" button should be hidden.
|
||||
*
|
||||
* @param flag The flag to update.
|
||||
* @param enable Whether to enable the hidden flag: True will cause view to be hidden.
|
||||
*/
|
||||
private void updateScreenshotButtonHiddenFlags(@ScreenshotButtonHiddenFlags int flag,
|
||||
boolean enable) {
|
||||
if (mScreenshotButton == null) return;
|
||||
if (enable) {
|
||||
mScreenshotButtonHiddenFlags |= flag;
|
||||
} else {
|
||||
mScreenshotButtonHiddenFlags &= ~flag;
|
||||
}
|
||||
int desiredVisibility = mScreenshotButtonHiddenFlags == 0 ? VISIBLE : GONE;
|
||||
if (mScreenshotButton.getVisibility() != desiredVisibility) {
|
||||
mScreenshotButton.setVisibility(desiredVisibility);
|
||||
mActionButtons.requestLayout();
|
||||
}
|
||||
private MultiValueAlpha getActionsAlphas() {
|
||||
return mMultiValueAlphas[ACTIONS_ALPHAS];
|
||||
}
|
||||
|
||||
private MultiValueAlpha getGroupActionsAlphas() {
|
||||
return mMultiValueAlphas[GROUP_ACTIONS_ALPHAS];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -304,56 +305,36 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the proper flags to indicate whether the "Save app pair" button should be disabled.
|
||||
*
|
||||
* @param flag The flag to update.
|
||||
* @param enable Whether to enable the hidden flag: True will cause view to be hidden.
|
||||
*/
|
||||
private void updateAppPairButtonHiddenFlags(
|
||||
@AppPairButtonHiddenFlags int flag, boolean enable) {
|
||||
if (!FeatureFlags.enableAppPairs()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mSaveAppPairButton == null) return;
|
||||
if (enable) {
|
||||
mAppPairButtonHiddenFlags |= flag;
|
||||
} else {
|
||||
mAppPairButtonHiddenFlags &= ~flag;
|
||||
}
|
||||
int desiredVisibility = mAppPairButtonHiddenFlags == 0 ? VISIBLE : GONE;
|
||||
if (mSaveAppPairButton.getVisibility() != desiredVisibility) {
|
||||
mSaveAppPairButton.setVisibility(desiredVisibility);
|
||||
mActionButtons.requestLayout();
|
||||
}
|
||||
private void setActionsAlpha(int index, float value) {
|
||||
Arrays.stream(mMultiValueAlphas).forEach(a -> a.get(index).setValue(value));
|
||||
}
|
||||
|
||||
public MultiProperty getContentAlpha() {
|
||||
return mMultiValueAlpha.get(INDEX_CONTENT_ALPHA);
|
||||
public Consumer<Float> getContentAlphaSetter() {
|
||||
return v -> setActionsAlpha(INDEX_CONTENT_ALPHA, v);
|
||||
}
|
||||
|
||||
public MultiProperty getVisibilityAlpha() {
|
||||
return mMultiValueAlpha.get(INDEX_VISIBILITY_ALPHA);
|
||||
public Consumer<Float> getVisibilityAlphaSetter() {
|
||||
return v -> setActionsAlpha(INDEX_VISIBILITY_ALPHA, v);
|
||||
}
|
||||
|
||||
public MultiProperty getFullscreenAlpha() {
|
||||
return mMultiValueAlpha.get(INDEX_FULLSCREEN_ALPHA);
|
||||
public Consumer<Float> getFullscreenAlphaSetter() {
|
||||
return v -> setActionsAlpha(INDEX_FULLSCREEN_ALPHA, v);
|
||||
}
|
||||
|
||||
public MultiProperty getShareTargetAlpha() {
|
||||
return mMultiValueAlpha.get(INDEX_SHARE_TARGET_ALPHA);
|
||||
public Consumer<Float> getShareTargetAlphaSetter() {
|
||||
return v -> setActionsAlpha(INDEX_SHARE_TARGET_ALPHA, v);
|
||||
}
|
||||
|
||||
public MultiProperty getIndexScrollAlpha() {
|
||||
return mMultiValueAlpha.get(INDEX_SCROLL_ALPHA);
|
||||
public Consumer<Float> getIndexScrollAlphaSetter() {
|
||||
return v -> setActionsAlpha(INDEX_SCROLL_ALPHA, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the visibility of the overview actions buttons.
|
||||
*/
|
||||
public @Visibility int getActionsButtonVisibility() {
|
||||
return mActionButtons.getVisibility();
|
||||
public boolean areActionsButtonsVisible() {
|
||||
return mActionButtons.getVisibility() == View.VISIBLE
|
||||
|| mGroupActionButtons.getVisibility() == View.VISIBLE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -366,10 +347,17 @@ public class OverviewActionsView<T extends OverlayUICallbacks> extends FrameLayo
|
||||
|
||||
/** Updates vertical margins for different navigation mode or configuration changes. */
|
||||
public void updateVerticalMargin(NavigationMode mode) {
|
||||
updateActionBarPosition(mActionButtons);
|
||||
updateActionBarPosition(mGroupActionButtons);
|
||||
}
|
||||
|
||||
/** Positions actions buttons according to device settings and insets. */
|
||||
private void updateActionBarPosition(LinearLayout actionBar) {
|
||||
if (mDp == null) {
|
||||
return;
|
||||
}
|
||||
LayoutParams actionParams = (LayoutParams) mActionButtons.getLayoutParams();
|
||||
|
||||
LayoutParams actionParams = (LayoutParams) actionBar.getLayoutParams();
|
||||
actionParams.setMargins(
|
||||
actionParams.leftMargin, mDp.overviewActionsTopMarginPx,
|
||||
actionParams.rightMargin, getBottomMargin());
|
||||
|
||||
@@ -35,6 +35,7 @@ import static com.android.launcher3.AbstractFloatingView.TYPE_TASK_MENU;
|
||||
import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType;
|
||||
import static com.android.launcher3.BaseActivity.STATE_HANDLER_INVISIBILITY_FLAGS;
|
||||
import static com.android.launcher3.Flags.enableGridOnlyOverview;
|
||||
import static com.android.launcher3.Flags.enableRefactorTaskThumbnail;
|
||||
import static com.android.launcher3.LauncherAnimUtils.SUCCESS_TRANSITION_PROGRESS;
|
||||
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
|
||||
import static com.android.launcher3.LauncherState.BACKGROUND_APP;
|
||||
@@ -186,6 +187,7 @@ import com.android.quickstep.TaskViewUtils;
|
||||
import com.android.quickstep.TopTaskTracker;
|
||||
import com.android.quickstep.ViewUtils;
|
||||
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
|
||||
import com.android.quickstep.recents.viewmodel.RecentsViewData;
|
||||
import com.android.quickstep.util.ActiveGestureErrorDetector;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.AnimUtils;
|
||||
@@ -376,6 +378,9 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
public void setValue(RecentsView view, float scale) {
|
||||
view.setScaleX(scale);
|
||||
view.setScaleY(scale);
|
||||
if (enableRefactorTaskThumbnail()) {
|
||||
view.mRecentsViewData.getScale().setValue(scale);
|
||||
}
|
||||
view.mLastComputedTaskStartPushOutDistance = null;
|
||||
view.mLastComputedTaskEndPushOutDistance = null;
|
||||
view.runActionOnRemoteHandles(new Consumer<RemoteTargetHandle>() {
|
||||
@@ -446,6 +451,8 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
|
||||
private static final float FOREGROUND_SCRIM_TINT = 0.32f;
|
||||
|
||||
public final RecentsViewData mRecentsViewData = new RecentsViewData();
|
||||
|
||||
protected final RecentsOrientedState mOrientationState;
|
||||
protected final BaseContainerInterface<STATE_TYPE, CONTAINER_TYPE> mSizeStrategy;
|
||||
@Nullable
|
||||
@@ -2012,6 +2019,9 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
|
||||
public void setFullscreenProgress(float fullscreenProgress) {
|
||||
mFullscreenProgress = fullscreenProgress;
|
||||
if (enableRefactorTaskThumbnail()) {
|
||||
mRecentsViewData.getFullscreenProgress().setValue(mFullscreenProgress);
|
||||
}
|
||||
int taskCount = getTaskViewCount();
|
||||
for (int i = 0; i < taskCount; i++) {
|
||||
requireTaskViewAt(i).setFullscreenProgress(mFullscreenProgress);
|
||||
@@ -2019,7 +2029,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
mClearAllButton.setFullscreenProgress(fullscreenProgress);
|
||||
|
||||
// Fade out the actions view quickly (0.1 range)
|
||||
mActionsView.getFullscreenAlpha().setValue(
|
||||
mActionsView.getFullscreenAlphaSetter().accept(
|
||||
mapToRange(fullscreenProgress, 0, 0.1f, 1f, 0f, LINEAR));
|
||||
}
|
||||
|
||||
@@ -2270,8 +2280,8 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
}
|
||||
|
||||
private void animateActionsViewAlpha(float alphaValue, long duration) {
|
||||
mActionsViewAlphaAnimator = ObjectAnimator.ofFloat(
|
||||
mActionsView.getVisibilityAlpha(), MULTI_PROPERTY_VALUE, alphaValue);
|
||||
mActionsViewAlphaAnimator = ObjectAnimator.ofFloat(mActionsView.getVisibilityAlphaSetter(),
|
||||
OverviewActionsView.FLOAT_SETTER, alphaValue);
|
||||
mActionsViewAlphaAnimatorFinalValue = alphaValue;
|
||||
mActionsViewAlphaAnimator.setDuration(duration);
|
||||
// Set autocancel to prevent race-conditiony setting of alpha from other animations
|
||||
@@ -2290,7 +2300,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
mClearAllButton.onRecentsViewScroll(scroll, mOverviewGridEnabled);
|
||||
|
||||
// Clear all button alpha was set by the previous line.
|
||||
mActionsView.getIndexScrollAlpha().setValue(1 - mClearAllButton.getScrollAlpha());
|
||||
mActionsView.getIndexScrollAlphaSetter().accept(1 - mClearAllButton.getScrollAlpha());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2354,8 +2364,8 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
// Update the task data for the in/visible children
|
||||
for (int i = 0; i < getTaskViewCount(); i++) {
|
||||
TaskView taskView = requireTaskViewAt(i);
|
||||
TaskContainer[] containers = taskView.getTaskContainers();
|
||||
if (containers.length == 0) {
|
||||
List<TaskContainer> containers = taskView.getTaskContainers();
|
||||
if (containers.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
int index = indexOfChild(taskView);
|
||||
@@ -2367,7 +2377,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
}
|
||||
if (visible) {
|
||||
// Default update all non-null tasks, then remove running ones
|
||||
List<Task> tasksToUpdate = Arrays.stream(containers).filter(Objects::nonNull)
|
||||
List<Task> tasksToUpdate = containers.stream()
|
||||
.map(TaskContainer::getTask)
|
||||
.collect(Collectors.toCollection(ArrayList::new));
|
||||
if (mTmpRunningTasks != null) {
|
||||
@@ -4295,7 +4305,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
int alphaInt = Math.round(alpha * 255);
|
||||
mEmptyMessagePaint.setAlpha(alphaInt);
|
||||
mEmptyIcon.setAlpha(alphaInt);
|
||||
mActionsView.getContentAlpha().setValue(mContentAlpha);
|
||||
mActionsView.getContentAlphaSetter().accept(mContentAlpha);
|
||||
|
||||
if (alpha > 0) {
|
||||
setVisibility(VISIBLE);
|
||||
@@ -4801,7 +4811,7 @@ public abstract class RecentsView<CONTAINER_TYPE extends Context & RecentsViewCo
|
||||
boolean primaryTaskSelected = mSplitHiddenTaskView.getTaskIds()[0]
|
||||
== mSplitSelectStateController.getInitialTaskId();
|
||||
TaskContainer taskContainer = mSplitHiddenTaskView
|
||||
.getTaskContainers()[primaryTaskSelected ? 1 : 0];
|
||||
.getTaskContainers().get(primaryTaskSelected ? 1 : 0);
|
||||
TaskThumbnailViewDeprecated thumbnail = taskContainer.getThumbnailView();
|
||||
mSplitSelectStateController.getSplitAnimationController()
|
||||
.addInitialSplitFromPair(taskContainer, builder,
|
||||
|
||||
@@ -18,8 +18,6 @@ package com.android.quickstep.views;
|
||||
|
||||
import static com.android.app.animation.Interpolators.EMPHASIZED;
|
||||
import static com.android.launcher3.Flags.enableOverviewIconMenu;
|
||||
import static com.android.launcher3.testing.shared.TestProtocol.TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE;
|
||||
import static com.android.launcher3.testing.shared.TestProtocol.testLogD;
|
||||
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
|
||||
import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT;
|
||||
import static com.android.quickstep.views.TaskThumbnailViewDeprecated.DIM_ALPHA;
|
||||
@@ -307,7 +305,6 @@ public class TaskMenuView extends AbstractFloatingView {
|
||||
|
||||
private void animateOpenOrClosed(boolean closing) {
|
||||
if (mOpenCloseAnimator != null && mOpenCloseAnimator.isRunning()) {
|
||||
testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE, "getting canceled");
|
||||
mOpenCloseAnimator.cancel();
|
||||
}
|
||||
mOpenCloseAnimator = new AnimatorSet();
|
||||
@@ -364,14 +361,10 @@ public class TaskMenuView extends AbstractFloatingView {
|
||||
iconAppChip.getMenuTranslationX(),
|
||||
MULTI_PROPERTY_VALUE, closing ? 0 : -additionalTranslationX);
|
||||
menuTranslationXAnim.setInterpolator(EMPHASIZED);
|
||||
testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
|
||||
"TaskMenuView.java.animateOpenOrClosed: running translation animations");
|
||||
|
||||
mOpenCloseAnimator.playTogether(translationYAnim, translationXAnim,
|
||||
menuTranslationXAnim, menuTranslationYAnim);
|
||||
}
|
||||
testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
|
||||
"TaskMenuView.java.animateOpenOrClosed: running animation 2");
|
||||
mOpenCloseAnimator.playTogether(mRevealAnimator,
|
||||
ObjectAnimator.ofFloat(
|
||||
mTaskContainer.getThumbnailView(), DIM_ALPHA,
|
||||
@@ -380,25 +373,14 @@ public class TaskMenuView extends AbstractFloatingView {
|
||||
mOpenCloseAnimator.addListener(new AnimationSuccessListener() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
|
||||
"TaskMenuView.java.animateOpenOrClosed: onAnimationStart");
|
||||
setVisibility(VISIBLE);
|
||||
if (closing && mOnClosingStartCallback != null) {
|
||||
mOnClosingStartCallback.run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
super.onAnimationCancel(animation);
|
||||
testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
|
||||
"TaskMenuView.java.animateOpenOrClosed: onAnimationCancel");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationSuccess(Animator animator) {
|
||||
testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE,
|
||||
"TaskMenuView.java.animateOpenOrClosed: onAnimationSuccess");
|
||||
if (closing) {
|
||||
closeComplete();
|
||||
}
|
||||
@@ -409,7 +391,6 @@ public class TaskMenuView extends AbstractFloatingView {
|
||||
}
|
||||
|
||||
private void closeComplete() {
|
||||
testLogD(TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE, "TaskMenuView.java.closeComplete");
|
||||
mIsOpen = false;
|
||||
mContainer.getDragLayer().removeView(this);
|
||||
mRevealAnimator = null;
|
||||
|
||||
@@ -53,6 +53,7 @@ import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.SystemUiController;
|
||||
import com.android.launcher3.util.SystemUiController.SystemUiControllerFlags;
|
||||
import com.android.launcher3.util.ViewPool;
|
||||
import com.android.quickstep.TaskOverlayFactory.TaskOverlay;
|
||||
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
|
||||
import com.android.quickstep.views.TaskView.FullscreenDrawParams;
|
||||
@@ -66,7 +67,7 @@ import com.android.systemui.shared.recents.utilities.PreviewPositionHelper;
|
||||
* @deprecated This class will be replaced by the new [TaskThumbnailView].
|
||||
*/
|
||||
@Deprecated
|
||||
public class TaskThumbnailViewDeprecated extends View {
|
||||
public class TaskThumbnailViewDeprecated extends View implements ViewPool.Reusable {
|
||||
private static final MainThreadInitializedObject<FullscreenDrawParams> TEMP_PARAMS =
|
||||
new MainThreadInitializedObject<>(FullscreenDrawParams::new);
|
||||
|
||||
@@ -606,4 +607,9 @@ public class TaskThumbnailViewDeprecated extends View {
|
||||
}
|
||||
return mThumbnailData.isRealSnapshot && !mTask.isLocked;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecycle() {
|
||||
// Do nothing
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,6 +107,7 @@ import com.android.quickstep.TaskViewUtils;
|
||||
import com.android.quickstep.orientation.RecentsPagedOrientationHandler;
|
||||
import com.android.quickstep.task.thumbnail.TaskThumbnail;
|
||||
import com.android.quickstep.task.thumbnail.TaskThumbnailView;
|
||||
import com.android.quickstep.task.viewmodel.TaskViewData;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.BorderAnimator;
|
||||
import com.android.quickstep.util.RecentsOrientedState;
|
||||
@@ -326,6 +327,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
}
|
||||
};
|
||||
|
||||
public TaskViewData mTaskViewData = new TaskViewData();
|
||||
protected TaskThumbnailViewDeprecated mTaskThumbnailViewDeprecated;
|
||||
protected TaskThumbnailView mTaskThumbnailView;
|
||||
protected TaskViewIcon mIconView;
|
||||
@@ -368,7 +370,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
private float mStableAlpha = 1;
|
||||
|
||||
private int mTaskViewId = -1;
|
||||
protected TaskContainer[] mTaskContainers = new TaskContainer[0];
|
||||
protected List<TaskContainer> mTaskContainers = Collections.emptyList();
|
||||
|
||||
private boolean mShowScreenshot;
|
||||
private boolean mBorderEnabled;
|
||||
@@ -496,7 +498,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
public void notifyIsRunningTaskUpdated() {
|
||||
// TODO(b/335649589): TaskView's VM will already have access to TaskThumbnailView's VM
|
||||
// so there will be no need to access TaskThumbnailView's VM through the TaskThumbnailView
|
||||
if (mTaskContainers.length > 0) {
|
||||
if (!mTaskContainers.isEmpty()) {
|
||||
bindTaskThumbnailView();
|
||||
}
|
||||
}
|
||||
@@ -685,9 +687,9 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
*/
|
||||
public void bind(Task task, RecentsOrientedState orientedState) {
|
||||
cancelPendingLoadTasks();
|
||||
mTaskContainers = new TaskContainer[]{
|
||||
mTaskContainers = Collections.singletonList(
|
||||
new TaskContainer(task, mTaskThumbnailViewDeprecated, mIconView,
|
||||
STAGE_POSITION_UNDEFINED, mDigitalWellBeingToast)};
|
||||
STAGE_POSITION_UNDEFINED, mDigitalWellBeingToast));
|
||||
if (enableRefactorTaskThumbnail()) {
|
||||
bindTaskThumbnailView();
|
||||
} else {
|
||||
@@ -706,10 +708,10 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
* Sets up an on-click listener and the visibility for show_windows icon on top of the task.
|
||||
*/
|
||||
public void setUpShowAllInstancesListener() {
|
||||
if (mTaskContainers.length == 0) {
|
||||
if (mTaskContainers.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
String taskPackageName = mTaskContainers[0].getTask().key.getPackageName();
|
||||
String taskPackageName = mTaskContainers.get(0).getTask().key.getPackageName();
|
||||
|
||||
// icon of the top/left task
|
||||
View showWindowsView = findViewById(R.id.show_windows);
|
||||
@@ -752,9 +754,9 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of all TaskContainers in the TaskView.
|
||||
* Returns a list of all TaskContainers in the TaskView.
|
||||
*/
|
||||
public TaskContainer[] getTaskContainers() {
|
||||
public List<TaskContainer> getTaskContainers() {
|
||||
return mTaskContainers;
|
||||
}
|
||||
|
||||
@@ -766,7 +768,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public Task getFirstTask() {
|
||||
return mTaskContainers.length > 0 ? mTaskContainers[0].getTask() : null;
|
||||
return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getTask() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -780,12 +782,12 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
* Returns a copy of integer array containing taskIds of all tasks in the TaskView.
|
||||
*/
|
||||
public int[] getTaskIds() {
|
||||
return Arrays.stream(mTaskContainers).mapToInt(
|
||||
return mTaskContainers.stream().mapToInt(
|
||||
container -> container.getTask().key.id).toArray();
|
||||
}
|
||||
|
||||
public boolean containsMultipleTasks() {
|
||||
return mTaskContainers.length > 1;
|
||||
return mTaskContainers.size() > 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -794,7 +796,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
*/
|
||||
@Nullable
|
||||
public TaskContainer getTaskContainerById(int taskId) {
|
||||
return Arrays.stream(mTaskContainers).filter(
|
||||
return mTaskContainers.stream().filter(
|
||||
container -> container.getTask().key.id == taskId).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
@@ -805,7 +807,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
*/
|
||||
@Deprecated
|
||||
public TaskThumbnailViewDeprecated getFirstThumbnailView() {
|
||||
return mTaskContainers.length > 0 ? mTaskContainers[0].getThumbnailView()
|
||||
return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getThumbnailView()
|
||||
: mTaskThumbnailViewDeprecated;
|
||||
}
|
||||
|
||||
@@ -826,7 +828,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
}
|
||||
|
||||
public TaskThumbnailViewDeprecated[] getThumbnailViews() {
|
||||
return Arrays.stream(mTaskContainers).map(
|
||||
return mTaskContainers.stream().map(
|
||||
TaskContainer::getThumbnailView).toArray(
|
||||
TaskThumbnailViewDeprecated[]::new);
|
||||
}
|
||||
@@ -839,7 +841,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
@Deprecated
|
||||
@Nullable
|
||||
public TaskViewIcon getFirstIconView() {
|
||||
return mTaskContainers.length > 0 ? mTaskContainers[0].getIconView() : null;
|
||||
return !mTaskContainers.isEmpty() ? mTaskContainers.get(0).getIconView() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -892,10 +894,10 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
*/
|
||||
protected boolean confirmSecondSplitSelectApp() {
|
||||
int index = getLastSelectedChildTaskIndex();
|
||||
if (index >= mTaskContainers.length) {
|
||||
if (index >= mTaskContainers.size()) {
|
||||
return false;
|
||||
}
|
||||
TaskContainer container = mTaskContainers[index];
|
||||
TaskContainer container = mTaskContainers.get(index);
|
||||
if (container != null) {
|
||||
return getRecentsView().confirmSplitSelect(this, container.getTask(),
|
||||
container.getIconView().getDrawable(), container.getThumbnailView(),
|
||||
@@ -1217,9 +1219,8 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
}
|
||||
|
||||
protected boolean showTaskMenuWithContainer(TaskViewIcon iconView) {
|
||||
Optional<TaskContainer> menuContainer = Arrays.stream(
|
||||
mTaskContainers).filter(
|
||||
container -> container.getIconView() == iconView).findAny();
|
||||
Optional<TaskContainer> menuContainer = mTaskContainers.stream().filter(
|
||||
container -> container.getIconView() == iconView).findAny();
|
||||
if (menuContainer.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
@@ -1462,6 +1463,9 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
scale *= mDismissScale;
|
||||
setScaleX(scale);
|
||||
setScaleY(scale);
|
||||
if (enableRefactorTaskThumbnail()) {
|
||||
mTaskViewData.getScale().setValue(scale);
|
||||
}
|
||||
updateSnapshotRadius();
|
||||
}
|
||||
|
||||
@@ -1768,10 +1772,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
progress = Utilities.boundToRange(progress, 0, 1);
|
||||
mFullscreenProgress = progress;
|
||||
mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE);
|
||||
if (!enableRefactorTaskThumbnail()) {
|
||||
// TODO(b/334826840) Add corner rounding to new TTV
|
||||
mTaskThumbnailViewDeprecated.getTaskOverlay().setFullscreenProgress(progress);
|
||||
}
|
||||
mTaskThumbnailViewDeprecated.getTaskOverlay().setFullscreenProgress(progress);
|
||||
|
||||
RecentsView recentsView = mContainer.getOverviewPanel();
|
||||
// Animate icons and DWB banners in/out, except in QuickSwitch state, when tiles are
|
||||
@@ -1785,10 +1786,7 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
|
||||
protected void updateSnapshotRadius() {
|
||||
updateCurrentFullscreenParams();
|
||||
if (!enableRefactorTaskThumbnail()) {
|
||||
// TODO(b/334826840) Add corner rounding to new TTV
|
||||
mTaskThumbnailViewDeprecated.setFullscreenParams(mCurrentFullscreenParams);
|
||||
}
|
||||
mTaskThumbnailViewDeprecated.setFullscreenParams(mCurrentFullscreenParams);
|
||||
}
|
||||
|
||||
void updateCurrentFullscreenParams() {
|
||||
@@ -1799,8 +1797,8 @@ public class TaskView extends FrameLayout implements Reusable {
|
||||
if (getRecentsView() == null) {
|
||||
return;
|
||||
}
|
||||
fullscreenParams.setProgress(mFullscreenProgress, getRecentsView().getScaleX(),
|
||||
getScaleX());
|
||||
fullscreenParams.setProgress(
|
||||
mFullscreenProgress, getRecentsView().getScaleX(), getScaleX());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+33
-8
@@ -17,38 +17,63 @@
|
||||
package com.android.quickstep.task.thumbnail
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import com.android.quickstep.recents.viewmodel.RecentsViewData
|
||||
import com.android.quickstep.task.viewmodel.TaskViewData
|
||||
import com.android.systemui.shared.recents.model.Task
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import kotlinx.coroutines.flow.first
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class TaskThumbnailViewModelTest {
|
||||
private val systemUnderTest = TaskThumbnailViewModel()
|
||||
private val recentsViewData = RecentsViewData()
|
||||
private val taskViewData = TaskViewData()
|
||||
private val systemUnderTest = TaskThumbnailViewModel(recentsViewData, taskViewData)
|
||||
|
||||
@Test
|
||||
fun initialStateIsUninitialized() {
|
||||
assertThat(systemUnderTest.uiState.value).isEqualTo(TaskThumbnailUiState.Uninitialized)
|
||||
fun initialStateIsUninitialized() = runTest {
|
||||
assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bindRunningTask_thenStateIs_LiveTile() {
|
||||
fun bindRunningTask_thenStateIs_LiveTile() = runTest {
|
||||
val taskThumbnail = TaskThumbnail(Task(), isRunning = true)
|
||||
systemUnderTest.bind(taskThumbnail)
|
||||
|
||||
assertThat(systemUnderTest.uiState.value).isEqualTo(TaskThumbnailUiState.LiveTile)
|
||||
assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bindRunningTaskThenStoppedTask_thenStateIs_Uninitialized() {
|
||||
fun setRecentsFullscreenProgress_thenProgressIsPassedThrough() = runTest {
|
||||
recentsViewData.fullscreenProgress.value = 0.5f
|
||||
|
||||
assertThat(systemUnderTest.recentsFullscreenProgress.first()).isEqualTo(0.5f)
|
||||
|
||||
recentsViewData.fullscreenProgress.value = 0.6f
|
||||
|
||||
assertThat(systemUnderTest.recentsFullscreenProgress.first()).isEqualTo(0.6f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setAncestorScales_thenScaleIsCalculated() = runTest {
|
||||
recentsViewData.scale.value = 0.5f
|
||||
taskViewData.scale.value = 0.6f
|
||||
|
||||
assertThat(systemUnderTest.inheritedScale.first()).isEqualTo(0.3f)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun bindRunningTaskThenStoppedTask_thenStateIs_Uninitialized() = runTest {
|
||||
// TODO(b/334825222): Change the expectation here when snapshot state is implemented
|
||||
val task = Task()
|
||||
val runningTask = TaskThumbnail(task, isRunning = true)
|
||||
val stoppedTask = TaskThumbnail(task, isRunning = false)
|
||||
systemUnderTest.bind(runningTask)
|
||||
assertThat(systemUnderTest.uiState.value).isEqualTo(TaskThumbnailUiState.LiveTile)
|
||||
assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.LiveTile)
|
||||
|
||||
systemUnderTest.bind(stoppedTask)
|
||||
assertThat(systemUnderTest.uiState.value).isEqualTo(TaskThumbnailUiState.Uninitialized)
|
||||
assertThat(systemUnderTest.uiState.first()).isEqualTo(TaskThumbnailUiState.Uninitialized)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,7 @@ import com.android.launcher3.util.TestUtil;
|
||||
import com.android.launcher3.util.rule.ScreenRecordRule;
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@@ -167,6 +168,7 @@ public class TaplPrivateSpaceTest extends AbstractQuickStepTest {
|
||||
|
||||
@Test
|
||||
@ScreenRecordRule.ScreenRecord // b/334946529
|
||||
@Ignore("b/339179262")
|
||||
public void testPrivateSpaceLockingBehaviour() throws IOException {
|
||||
// Scroll to the bottom of All Apps
|
||||
executeOnLauncher(launcher -> launcher.getAppsView().resetAndScrollToPrivateSpaceHeader());
|
||||
|
||||
@@ -130,7 +130,7 @@ public class TaplTestsSplitscreen extends AbstractQuickStepTest {
|
||||
.tapMenu()
|
||||
.hasMenuItem("Save app pair"));
|
||||
} else {
|
||||
overview.getOverviewActions().assertHasAction("Save app pair");
|
||||
overview.getOverviewGroupActions().assertHasAction("Save app pair");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,7 +91,7 @@ class SplitAnimationControllerTest {
|
||||
whenever(mockThumbnailView.thumbnail).thenReturn(mockBitmap)
|
||||
whenever(mockTaskContainer.iconView).thenReturn(mockIconView)
|
||||
whenever(mockIconView.drawable).thenReturn(mockTaskViewDrawable)
|
||||
whenever(mockTaskView.taskContainers).thenReturn(Array(1) { mockTaskContainer })
|
||||
whenever(mockTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
|
||||
|
||||
whenever(splitSelectSource.drawable).thenReturn(mockSplitSourceDrawable)
|
||||
whenever(splitSelectSource.view).thenReturn(mockSplitSourceView)
|
||||
@@ -184,7 +184,7 @@ class SplitAnimationControllerTest {
|
||||
whenever(mockTask.getKey()).thenReturn(mockTaskKey)
|
||||
whenever(mockTaskKey.getId()).thenReturn(taskId)
|
||||
whenever(mockSplitSelectStateController.initialTaskId).thenReturn(taskId)
|
||||
whenever(mockGroupedTaskView.taskContainers).thenReturn(Array(1) { mockTaskContainer })
|
||||
whenever(mockGroupedTaskView.taskContainers).thenReturn(List(1) { mockTaskContainer })
|
||||
val splitAnimInitProps: SplitAnimationController.Companion.SplitAnimInitProps =
|
||||
splitAnimationController.getFirstAnimInitViews(
|
||||
{ mockGroupedTaskView },
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj na početni ekran"</string>
|
||||
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Dodali ste vidžet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> na početni ekran"</string>
|
||||
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Predlozi"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Neophodne aplikacije"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Osnovno"</string>
|
||||
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Novosti i časopisi"</string>
|
||||
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona za opuštanje"</string>
|
||||
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zabava"</string>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<string name="add_to_home_screen" msgid="9168649446635919791">"Přidat na plochu"</string>
|
||||
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> byl přidán na plochu"</string>
|
||||
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Návrhy"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Základní"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Nejdůležitější aplikace"</string>
|
||||
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Zprávy a časopisy"</string>
|
||||
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Vaše klidová zóna"</string>
|
||||
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Zábava"</string>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias y revistas"</string>
|
||||
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Zona de descanso"</string>
|
||||
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimiento"</string>
|
||||
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
|
||||
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociales"</string>
|
||||
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salud y bienestar"</string>
|
||||
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"Clima"</string>
|
||||
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerencias para ti"</string>
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Noticias y revistas"</string>
|
||||
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Tu zona de descanso"</string>
|
||||
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Entretenimiento"</string>
|
||||
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Social"</string>
|
||||
<string name="social_widget_recommendation_category_label" msgid="689147679536384717">"Redes sociales"</string>
|
||||
<string name="fitness_widget_recommendation_category_label" msgid="2756483898236585324">"Salud y actividad física"</string>
|
||||
<string name="weather_widget_recommendation_category_label" msgid="3059715991930798039">"El tiempo"</string>
|
||||
<string name="others_widget_recommendation_category_label" msgid="5555987036267226245">"Sugerencias para ti"</string>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<string name="add_to_home_screen" msgid="9168649446635919791">"Ajouter à l\'écran d\'accueil"</string>
|
||||
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widget <xliff:g id="WIDGET_NAME">%1$s</xliff:g> ajouté à l\'écran d\'accueil"</string>
|
||||
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Suggestions"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Les bases"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Indispensables"</string>
|
||||
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Actualités et magazines"</string>
|
||||
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Votre espace détente"</string>
|
||||
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Divertissement"</string>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<string name="add_to_home_screen" msgid="9168649446635919791">"Dodaj do ekranu głównego"</string>
|
||||
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Widżet <xliff:g id="WIDGET_NAME">%1$s</xliff:g> został dodany do ekranu głównego"</string>
|
||||
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Sugestie"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Niezbędne"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Najbardziej przydatne"</string>
|
||||
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Wiadomości i czasopisma"</string>
|
||||
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Strefa relaksu"</string>
|
||||
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Rozrywka"</string>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<string name="add_to_home_screen" msgid="9168649446635919791">"Додај на почетни екран"</string>
|
||||
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"Додали сте виџет <xliff:g id="WIDGET_NAME">%1$s</xliff:g> на почетни екран"</string>
|
||||
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"Предлози"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Неопходне апликације"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"Основно"</string>
|
||||
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"Новости и часописи"</string>
|
||||
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"Зона за опуштање"</string>
|
||||
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"Забава"</string>
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
<string name="add_to_home_screen" msgid="9168649446635919791">"添加到主屏幕"</string>
|
||||
<string name="added_to_home_screen_accessibility_text" msgid="4451545765448884415">"已将“<xliff:g id="WIDGET_NAME">%1$s</xliff:g>”微件添加到主屏幕"</string>
|
||||
<string name="suggested_widgets_header_title" msgid="1844314680798145222">"建议"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"必备"</string>
|
||||
<string name="productivity_widget_recommendation_category_label" msgid="3811812719618323750">"必备之选"</string>
|
||||
<string name="news_widget_recommendation_category_label" msgid="6756167867113741310">"新闻与杂志"</string>
|
||||
<string name="social_and_entertainment_widget_recommendation_category_label" msgid="2923840997302308191">"您的休闲区"</string>
|
||||
<string name="entertainment_widget_recommendation_category_label" msgid="3973107268630717874">"娱乐"</string>
|
||||
|
||||
@@ -70,6 +70,7 @@ import android.util.TypedValue;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import androidx.annotation.ChecksSdkIntAtLeast;
|
||||
@@ -104,6 +105,7 @@ import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
@@ -835,4 +837,27 @@ public final class Utilities {
|
||||
// No-Op
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does a depth-first search through the View hierarchy starting at root, to find a view that
|
||||
* matches the predicate. Returns null if no View was found. View has a findViewByPredicate
|
||||
* member function but it is currently a @hide API.
|
||||
*/
|
||||
@Nullable
|
||||
public static <T extends View> T findViewByPredicate(@NonNull View root,
|
||||
@NonNull Predicate<View> predicate) {
|
||||
if (predicate.test(root)) {
|
||||
return (T) root;
|
||||
}
|
||||
if (root instanceof ViewGroup parent) {
|
||||
int count = parent.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
View view = findViewByPredicate(parent.getChildAt(i), predicate);
|
||||
if (view != null) {
|
||||
return (T) view;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,8 @@ package com.android.launcher3.widget;
|
||||
|
||||
import static com.android.app.animation.Interpolators.EMPHASIZED;
|
||||
import static com.android.launcher3.Flags.enableWidgetTapToAdd;
|
||||
import static com.android.launcher3.LauncherState.NORMAL;
|
||||
import static com.android.launcher3.anim.AnimatorListeners.forSuccessCallback;
|
||||
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGET_ADD_BUTTON_TAP;
|
||||
|
||||
import android.content.Context;
|
||||
@@ -42,6 +44,7 @@ import com.android.launcher3.Insettable;
|
||||
import com.android.launcher3.Launcher;
|
||||
import com.android.launcher3.PendingAddItemInfo;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.popup.PopupDataProvider;
|
||||
import com.android.launcher3.testing.TestLogging;
|
||||
import com.android.launcher3.testing.shared.TestProtocol;
|
||||
@@ -74,6 +77,7 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<BaseActivity>
|
||||
private boolean mDisableNavBarScrim = false;
|
||||
|
||||
@Nullable private WidgetCell mWidgetCellWithAddButton = null;
|
||||
@Nullable private WidgetItem mLastSelectedWidgetItem = null;
|
||||
|
||||
public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
super(context, attrs, defStyleAttr);
|
||||
@@ -161,6 +165,11 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<BaseActivity>
|
||||
}
|
||||
|
||||
mWidgetCellWithAddButton = mWidgetCellWithAddButton != wc ? wc : null;
|
||||
if (mWidgetCellWithAddButton != null) {
|
||||
mLastSelectedWidgetItem = mWidgetCellWithAddButton.getWidgetItem();
|
||||
} else {
|
||||
mLastSelectedWidgetItem = null;
|
||||
}
|
||||
} else {
|
||||
mActivityContext.getItemOnClickListener().onClick(wc);
|
||||
}
|
||||
@@ -174,7 +183,8 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<BaseActivity>
|
||||
}
|
||||
|
||||
/**
|
||||
* Click handler for tap to add button.
|
||||
* Click handler for tap to add button. This handler assumes we are in the Launcher activity and
|
||||
* should not be used when the widget sheet is displayed elsewhere.
|
||||
*/
|
||||
private void addWidget(@NonNull PendingAddItemInfo info) {
|
||||
// Using a boolean flag here to make sure the callback is only run once. This should never
|
||||
@@ -182,19 +192,23 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<BaseActivity>
|
||||
// needed.
|
||||
final AtomicBoolean hasRun = new AtomicBoolean(false);
|
||||
addOnCloseListener(() -> {
|
||||
if (!hasRun.get()) {
|
||||
Launcher.getLauncher(mActivityContext).getAccessibilityDelegate().addToWorkspace(
|
||||
info, /*accessibility=*/ false,
|
||||
if (hasRun.get()) return;
|
||||
hasRun.set(true);
|
||||
|
||||
// Going to NORMAL state will also dismiss the All Apps view if it is showing.
|
||||
Launcher launcher = Launcher.getLauncher(mActivityContext);
|
||||
launcher.getStateManager().goToState(NORMAL, forSuccessCallback(() -> {
|
||||
launcher.getAccessibilityDelegate().addToWorkspace(info,
|
||||
/*accessibility=*/ false,
|
||||
/*finishCallback=*/ (success) -> {
|
||||
mActivityContext.getStatsLogManager()
|
||||
.logger()
|
||||
.withItemInfo(info)
|
||||
.log(LAUNCHER_WIDGET_ADD_BUTTON_TAP);
|
||||
});
|
||||
hasRun.set(true);
|
||||
}
|
||||
}));
|
||||
});
|
||||
handleClose(true);
|
||||
close(/* animate= */ true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -243,6 +257,14 @@ public abstract class BaseWidgetSheet extends AbstractSlideInView<BaseActivity>
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the component of the widget that is currently showing an add button, if any.
|
||||
*/
|
||||
@Nullable
|
||||
protected WidgetItem getLastSelectedWidgetItem() {
|
||||
return mLastSelectedWidgetItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "Widgets.onLongClick");
|
||||
|
||||
@@ -503,6 +503,15 @@ public class WidgetCell extends LinearLayout {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
|
||||
if (changed && isShowingAddButton()) {
|
||||
post(this::setupIconOrTextButton);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads a high resolution package icon to show next to the widget title.
|
||||
*/
|
||||
@@ -627,4 +636,19 @@ public class WidgetCell extends LinearLayout {
|
||||
set.playSequentially(hideAnim, showAnim);
|
||||
set.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this WidgetCell is displaying the same item as info.
|
||||
*/
|
||||
public boolean matchesItem(WidgetItem info) {
|
||||
if (info == null || mItem == null) return false;
|
||||
if (info.widgetInfo != null && mItem.widgetInfo != null) {
|
||||
return info.widgetInfo.getUser().equals(mItem.widgetInfo.getUser())
|
||||
&& info.widgetInfo.getComponent().equals(mItem.widgetInfo.getComponent());
|
||||
} else if (info.activityInfo != null && mItem.activityInfo != null) {
|
||||
return info.activityInfo.getUser().equals(mItem.activityInfo.getUser())
|
||||
&& info.activityInfo.getComponent().equals(mItem.activityInfo.getComponent());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -142,6 +142,9 @@ public class WidgetsBottomSheet extends BaseWidgetSheet {
|
||||
row.forEach(widgetItem -> {
|
||||
WidgetCell widget = addItemCell(tableRow);
|
||||
widget.applyFromCellItem(widgetItem);
|
||||
if (widget.matchesItem(getLastSelectedWidgetItem())) {
|
||||
widget.callOnClick();
|
||||
}
|
||||
});
|
||||
widgetsTable.addView(tableRow);
|
||||
});
|
||||
|
||||
@@ -29,6 +29,7 @@ import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.LinearLayout;
|
||||
@@ -40,6 +41,7 @@ import androidx.annotation.Px;
|
||||
import com.android.launcher3.DeviceProfile;
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.Utilities;
|
||||
import com.android.launcher3.model.WidgetItem;
|
||||
import com.android.launcher3.model.data.PackageItemInfo;
|
||||
import com.android.launcher3.recyclerview.ViewHolderBinder;
|
||||
import com.android.launcher3.util.PackageUserKey;
|
||||
@@ -194,15 +196,21 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
|
||||
layoutParams.width = 0;
|
||||
}
|
||||
layoutParams.weight = layoutParams.width == 0 ? 0.33F : 0;
|
||||
leftPane.setLayoutParams(layoutParams);
|
||||
requestApplyInsets();
|
||||
if (mSelectedHeader != null) {
|
||||
if (mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) {
|
||||
mSuggestedWidgetsHeader.callOnClick();
|
||||
} else {
|
||||
getHeaderChangeListener().onHeaderChanged(mSelectedHeader);
|
||||
|
||||
post(() -> {
|
||||
// The following calls all trigger requestLayout, so we post them to avoid
|
||||
// calling requestLayout during a layout pass. This also fixes the related warnings
|
||||
// in logcat.
|
||||
leftPane.setLayoutParams(layoutParams);
|
||||
requestApplyInsets();
|
||||
if (mSelectedHeader != null) {
|
||||
if (mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) {
|
||||
mSuggestedWidgetsHeader.callOnClick();
|
||||
} else {
|
||||
getHeaderChangeListener().onHeaderChanged(mSelectedHeader);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,6 +230,9 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
|
||||
if (mSuggestedWidgetsContainer == null && mRecommendedWidgetsCount > 0) {
|
||||
setupSuggestedWidgets(LayoutInflater.from(getContext()));
|
||||
mSuggestedWidgetsHeader.callOnClick();
|
||||
} else if (mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) {
|
||||
// Reselect widget if we are reloading recommendations while it is currently showing.
|
||||
selectWidgetCell(mWidgetRecommendationsContainer, getLastSelectedWidgetItem());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,6 +280,16 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
|
||||
mRightPaneScrollView.setScrollY(0);
|
||||
mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle);
|
||||
mSuggestedWidgetsPackageUserKey = PackageUserKey.fromPackageItemInfo(packageItemInfo);
|
||||
final boolean isChangingHeaders =
|
||||
!mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey);
|
||||
if (isChangingHeaders) {
|
||||
// If switching from another header, unselect any WidgetCells. This is necessary
|
||||
// because we do not clear/recycle the WidgetCells in the recommendations container
|
||||
// when the header is clicked, only when onRecommendationsBound is called. That
|
||||
// means a WidgetCell in the recommendations container may still be selected from
|
||||
// the last time the recommendations were shown.
|
||||
unselectWidgetCell(mWidgetRecommendationsContainer, getLastSelectedWidgetItem());
|
||||
}
|
||||
mSelectedHeader = mSuggestedWidgetsPackageUserKey;
|
||||
});
|
||||
mSuggestedWidgetsContainer.addView(mSuggestedWidgetsHeader);
|
||||
@@ -357,6 +378,8 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
|
||||
return new HeaderChangeListener() {
|
||||
@Override
|
||||
public void onHeaderChanged(@NonNull PackageUserKey selectedHeader) {
|
||||
final boolean isSameHeader = mSelectedHeader != null
|
||||
&& mSelectedHeader.equals(selectedHeader);
|
||||
mSelectedHeader = selectedHeader;
|
||||
WidgetsListContentEntry contentEntry = mActivityContext.getPopupDataProvider()
|
||||
.getSelectedAppWidgets(selectedHeader);
|
||||
@@ -384,11 +407,20 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
|
||||
contentEntryToBind,
|
||||
ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
|
||||
Collections.EMPTY_LIST);
|
||||
if (isSameHeader) {
|
||||
// Reselect the last selected widget if we are reloading the same header.
|
||||
selectWidgetCell(widgetsRowViewHolder.tableContainer,
|
||||
getLastSelectedWidgetItem());
|
||||
}
|
||||
widgetsRowViewHolder.mDataCallback = data -> {
|
||||
mWidgetsListTableViewHolderBinder.bindViewHolder(widgetsRowViewHolder,
|
||||
contentEntryToBind,
|
||||
ViewHolderBinder.POSITION_FIRST | ViewHolderBinder.POSITION_LAST,
|
||||
Collections.singletonList(data));
|
||||
if (isSameHeader) {
|
||||
selectWidgetCell(widgetsRowViewHolder.tableContainer,
|
||||
getLastSelectedWidgetItem());
|
||||
}
|
||||
};
|
||||
mRightPane.removeAllViews();
|
||||
mRightPane.addView(widgetsRowViewHolder.itemView);
|
||||
@@ -401,6 +433,24 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet {
|
||||
};
|
||||
}
|
||||
|
||||
private static void selectWidgetCell(ViewGroup parent, WidgetItem item) {
|
||||
if (parent == null || item == null) return;
|
||||
WidgetCell cell = Utilities.findViewByPredicate(parent, v -> v instanceof WidgetCell wc
|
||||
&& wc.matchesItem(item));
|
||||
if (cell != null && !cell.isShowingAddButton()) {
|
||||
cell.callOnClick();
|
||||
}
|
||||
}
|
||||
|
||||
private static void unselectWidgetCell(ViewGroup parent, WidgetItem item) {
|
||||
if (parent == null || item == null) return;
|
||||
WidgetCell cell = Utilities.findViewByPredicate(parent, v -> v instanceof WidgetCell wc
|
||||
&& wc.matchesItem(item));
|
||||
if (cell != null && cell.isShowingAddButton()) {
|
||||
cell.hideAddButton(/* animate= */ false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setInsets(Rect insets) {
|
||||
super.setInsets(insets);
|
||||
|
||||
@@ -105,6 +105,7 @@ android_library {
|
||||
android_library {
|
||||
name: "Launcher3TestResources",
|
||||
resource_dirs: ["res"],
|
||||
asset_dirs: ["assets"],
|
||||
// TODO(b/319712088): re-enable use_resource_processor
|
||||
use_resource_processor: false,
|
||||
}
|
||||
|
||||
@@ -175,7 +175,6 @@ public final class TestProtocol {
|
||||
public static final String OVERVIEW_OVER_HOME = "b/279059025";
|
||||
public static final String UIOBJECT_STALE_ELEMENT = "b/319501259";
|
||||
public static final String TEST_DRAG_APP_ICON_TO_MULTIPLE_WORKSPACES_FAILURE = "b/326908466";
|
||||
public static final String TEST_TAPL_OVERVIEW_ACTIONS_MENU_FAILURE = "b/326073471";
|
||||
public static final String WIDGET_CONFIG_NULL_EXTRA_INTENT = "b/324419890";
|
||||
public static final String ACTIVITY_NOT_RESUMED_AFTER_BACK = "b/322823209";
|
||||
public static final String OVERVIEW_SELECT_TOOLTIP_MISALIGNED = "b/332485341";
|
||||
|
||||
+5
@@ -22,6 +22,8 @@ import android.util.Log
|
||||
import android.view.View
|
||||
import androidx.core.view.get
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4
|
||||
import androidx.test.filters.SmallTest
|
||||
import com.android.launcher3.CellLayout
|
||||
import com.android.launcher3.celllayout.board.CellLayoutBoard
|
||||
import com.android.launcher3.celllayout.board.IconPoint
|
||||
@@ -34,6 +36,7 @@ import java.util.Random
|
||||
import org.junit.Assert
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
|
||||
private class HotseatReorderTestCase(
|
||||
val startBoard: CellLayoutBoard,
|
||||
@@ -44,6 +47,8 @@ private class HotseatReorderTestCase(
|
||||
}
|
||||
}
|
||||
|
||||
@SmallTest
|
||||
@RunWith(AndroidJUnit4::class)
|
||||
class HotseatReorderUnitTest {
|
||||
|
||||
private val applicationContext: Context =
|
||||
+8
-5
@@ -141,11 +141,14 @@ class ReorderPreviewAnimationTest {
|
||||
ReorderPreviewAnimation.MODE_PREVIEW,
|
||||
AnimationValues(dx = 0, dy = 0, scale = 100)
|
||||
)
|
||||
testAnimationAtGivenProgress(
|
||||
PREVIEW_DURATION * 99,
|
||||
ReorderPreviewAnimation.MODE_PREVIEW,
|
||||
AnimationValues(dx = 5, dy = -10, scale = 96)
|
||||
)
|
||||
// (b/339313407) Temporarily disable this test as the behavior is
|
||||
// inconsistent between Soong & Gradle builds.
|
||||
//
|
||||
// testAnimationAtGivenProgress(
|
||||
// PREVIEW_DURATION * 99,
|
||||
// ReorderPreviewAnimation.MODE_PREVIEW,
|
||||
// AnimationValues(dx = 5, dy = -10, scale = 96)
|
||||
// )
|
||||
testAnimationAtGivenProgress(
|
||||
PREVIEW_DURATION * 98,
|
||||
ReorderPreviewAnimation.MODE_PREVIEW,
|
||||
@@ -358,6 +358,21 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets Overview Actions specific to grouped tasks.
|
||||
*
|
||||
* @return The Overview group actions bar
|
||||
*/
|
||||
@NonNull
|
||||
public OverviewActions getOverviewGroupActions() {
|
||||
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"want to get overview group actions")) {
|
||||
verifyActiveContainer();
|
||||
UiObject2 groupActions = mLauncher.waitForOverviewObject("group_action_buttons");
|
||||
return new OverviewActions(groupActions, mLauncher);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns if clear all button is visible.
|
||||
*/
|
||||
@@ -449,10 +464,18 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer {
|
||||
private void verifyActionsViewVisibility() {
|
||||
try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
|
||||
"want to assert overview actions view visibility")) {
|
||||
boolean isTablet = mLauncher.isTablet();
|
||||
OverviewTask task = isTablet ? getFocusedTaskForTablet() : getCurrentTask();
|
||||
|
||||
if (isActionsViewVisible()) {
|
||||
mLauncher.waitForOverviewObject("action_buttons");
|
||||
if (task.isTaskSplit()) {
|
||||
mLauncher.waitForOverviewObject("group_action_buttons");
|
||||
} else {
|
||||
mLauncher.waitForOverviewObject("action_buttons");
|
||||
}
|
||||
} else {
|
||||
mLauncher.waitUntilOverviewObjectGone("action_buttons");
|
||||
mLauncher.waitUntilOverviewObjectGone("group_action_buttons");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ import java.util.stream.Collectors;
|
||||
public final class LauncherInstrumentation {
|
||||
|
||||
private static final String TAG = "Tapl";
|
||||
private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 15;
|
||||
private static final int ZERO_BUTTON_STEPS_FROM_BACKGROUND_TO_HOME = 5;
|
||||
private static final int GESTURE_STEP_MS = 16;
|
||||
|
||||
static final Pattern EVENT_PILFER_POINTERS = Pattern.compile("pilferPointers");
|
||||
|
||||
Reference in New Issue
Block a user