Snap for 10712072 from 5ed1b4001b to udc-qpr1-release
Change-Id: I681564ee16c56fc099243218a2c5028c11849fee
This commit is contained in:
@@ -27,6 +27,8 @@
|
||||
|
||||
<string name="nav_handle_long_press_handler_class" translatable="false"></string>
|
||||
|
||||
<string name="assist_utils_class" translatable="false"></string>
|
||||
|
||||
<string name="secondary_display_predictions_class" translatable="false">com.android.launcher3.secondarydisplay.SecondaryDisplayPredictionsImpl</string>
|
||||
|
||||
<string name="taskbar_model_callbacks_factory_class" translatable="false">com.android.launcher3.taskbar.TaskbarModelCallbacksFactory</string>
|
||||
|
||||
@@ -51,6 +51,7 @@ import com.android.quickstep.OverviewCommandHelper;
|
||||
import com.android.quickstep.SystemUiProxy;
|
||||
import com.android.quickstep.TaskUtils;
|
||||
import com.android.quickstep.TouchInteractionService;
|
||||
import com.android.quickstep.util.AssistUtilsBase;
|
||||
import com.android.quickstep.views.DesktopTaskView;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
@@ -158,7 +159,7 @@ public class TaskbarNavButtonController implements TaskbarControllers.LoggableTa
|
||||
switch (buttonType) {
|
||||
case BUTTON_HOME:
|
||||
logEvent(LAUNCHER_TASKBAR_HOME_BUTTON_LONGPRESS);
|
||||
startAssistant();
|
||||
onLongPressHome();
|
||||
return true;
|
||||
case BUTTON_A11Y:
|
||||
logEvent(LAUNCHER_TASKBAR_A11Y_BUTTON_LONGPRESS);
|
||||
@@ -307,13 +308,17 @@ public class TaskbarNavButtonController implements TaskbarControllers.LoggableTa
|
||||
}
|
||||
}
|
||||
|
||||
private void startAssistant() {
|
||||
private void onLongPressHome() {
|
||||
if (mScreenPinned || !mAssistantLongPressEnabled) {
|
||||
return;
|
||||
}
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
|
||||
mSystemUiProxy.startAssistant(args);
|
||||
// Attempt to start Assist with AssistUtils, otherwise fall back to SysUi's implementation.
|
||||
if (!AssistUtilsBase.newInstance(mService.getApplicationContext()).tryStartAssistOverride(
|
||||
INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS)) {
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(INVOCATION_TYPE_KEY, INVOCATION_TYPE_HOME_BUTTON_LONG_PRESS);
|
||||
mSystemUiProxy.startAssistant(args);
|
||||
}
|
||||
}
|
||||
|
||||
private void showQuickSettings() {
|
||||
|
||||
@@ -62,6 +62,7 @@ import com.android.internal.view.AppearanceRegion;
|
||||
import com.android.launcher3.util.MainThreadInitializedObject;
|
||||
import com.android.launcher3.util.Preconditions;
|
||||
import com.android.launcher3.util.SplitConfigurationOptions;
|
||||
import com.android.quickstep.util.AssistUtilsBase;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
import com.android.systemui.shared.recents.model.ThumbnailData;
|
||||
import com.android.systemui.shared.system.RecentsAnimationControllerCompat;
|
||||
@@ -250,6 +251,8 @@ public class SystemUiProxy implements ISystemUiProxy {
|
||||
setBackToLauncherCallback(mBackToLauncherCallback, mBackToLauncherRunner);
|
||||
setUnfoldAnimationListener(mUnfoldAnimationListener);
|
||||
setDesktopTaskListener(mDesktopTaskListener);
|
||||
setAssistantOverridesRequested(
|
||||
AssistUtilsBase.newInstance(mContext).getSysUiAssistOverrideInvocationTypes());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -373,6 +376,17 @@ public class SystemUiProxy implements ISystemUiProxy {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAssistantOverridesRequested(int[] invocationTypes) {
|
||||
if (mSystemUiProxy != null) {
|
||||
try {
|
||||
mSystemUiProxy.setAssistantOverridesRequested(invocationTypes);
|
||||
} catch (RemoteException e) {
|
||||
Log.w(TAG, "Failed call setAssistantOverridesRequested", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyAccessibilityButtonClicked(int displayId) {
|
||||
if (mSystemUiProxy != null) {
|
||||
|
||||
@@ -117,6 +117,7 @@ import com.android.quickstep.inputconsumers.TaskbarUnstashInputConsumer;
|
||||
import com.android.quickstep.inputconsumers.TrackpadStatusBarInputConsumer;
|
||||
import com.android.quickstep.util.ActiveGestureLog;
|
||||
import com.android.quickstep.util.ActiveGestureLog.CompoundString;
|
||||
import com.android.quickstep.util.AssistUtilsBase;
|
||||
import com.android.systemui.shared.recents.IOverviewProxy;
|
||||
import com.android.systemui.shared.recents.ISystemUiProxy;
|
||||
import com.android.systemui.shared.system.ActivityManagerWrapper;
|
||||
@@ -280,6 +281,20 @@ public class TouchInteractionService extends Service {
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sent when the assistant has been invoked with the given type (defined in AssistManager)
|
||||
* and should be shown. This method is used if SystemUiProxy#setAssistantOverridesRequested
|
||||
* was previously called including this invocation type.
|
||||
*/
|
||||
@Override
|
||||
public void onAssistantOverrideInvoked(int invocationType) {
|
||||
executeForTouchInteractionService(tis -> {
|
||||
if (!AssistUtilsBase.newInstance(tis).tryStartAssistOverride(invocationType)) {
|
||||
Log.w(TAG, "Failed to invoke Assist override");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNavigationBarSurface(SurfaceControl surface) {
|
||||
// TODO: implement
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.quickstep.util;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.android.launcher3.R;
|
||||
import com.android.launcher3.util.ResourceBasedOverride;
|
||||
|
||||
/** Utilities to work with Assistant functionality. */
|
||||
public class AssistUtilsBase implements ResourceBasedOverride {
|
||||
|
||||
public AssistUtilsBase() {}
|
||||
|
||||
/** Creates AssistUtils as specified by overrides */
|
||||
public static AssistUtilsBase newInstance(Context context) {
|
||||
return Overrides.getObject(AssistUtilsBase.class, context, R.string.assist_utils_class);
|
||||
}
|
||||
|
||||
/** @return Array of AssistUtils.INVOCATION_TYPE_* that we want to handle instead of SysUI. */
|
||||
public int[] getSysUiAssistOverrideInvocationTypes() {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {@code true} if the override was handled, i.e. an assist surface was shown or the
|
||||
* request should be ignored. {@code false} means the caller should start assist another way.
|
||||
*/
|
||||
public boolean tryStartAssistOverride(int invocationType) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -26,6 +26,7 @@ import static org.mockito.Mockito.when;
|
||||
import android.os.Handler;
|
||||
import android.view.View;
|
||||
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import com.android.launcher3.logging.StatsLogManager;
|
||||
@@ -70,6 +71,9 @@ public class TaskbarNavButtonControllerTest {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
when(mockService.getDisplayId()).thenReturn(DISPLAY_ID);
|
||||
when(mockService.getOverviewCommandHelper()).thenReturn(mockCommandHelper);
|
||||
when(mockService.getApplicationContext())
|
||||
.thenReturn(InstrumentationRegistry.getInstrumentation().getTargetContext()
|
||||
.getApplicationContext());
|
||||
when(mockStatsLogManager.logger()).thenReturn(mockStatsLogger);
|
||||
when(mockTaskbarControllers.getTaskbarActivityContext())
|
||||
.thenReturn(mockTaskbarActivityContext);
|
||||
|
||||
@@ -25,6 +25,8 @@ import static org.junit.Assume.assumeTrue;
|
||||
|
||||
import android.content.Intent;
|
||||
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import androidx.test.filters.LargeTest;
|
||||
import androidx.test.platform.app.InstrumentationRegistry;
|
||||
|
||||
import com.android.launcher3.config.FeatureFlags;
|
||||
@@ -36,7 +38,10 @@ import com.android.quickstep.TaskbarModeSwitchRule.TaskbarModeSwitch;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
|
||||
@LargeTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class TaplTestsSplitscreen extends AbstractQuickStepTest {
|
||||
private static final String CALCULATOR_APP_NAME = "Calculator";
|
||||
private static final String CALCULATOR_APP_PACKAGE =
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.launcher3;
|
||||
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_CURSOR_HOVER_STATES;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_DOWNLOAD_APP_UX_V2;
|
||||
import static com.android.launcher3.config.FeatureFlags.ENABLE_ICON_LABEL_AUTO_SCALING;
|
||||
import static com.android.launcher3.graphics.PreloadIconDrawable.newPendingIcon;
|
||||
@@ -152,7 +153,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
|
||||
private final CheckLongPressHelper mLongPressHelper;
|
||||
|
||||
private final boolean mLayoutHorizontal;
|
||||
private boolean mLayoutHorizontal;
|
||||
private final boolean mIsRtl;
|
||||
private final int mIconSize;
|
||||
|
||||
@@ -197,6 +198,7 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
public BubbleTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mActivity = ActivityContext.lookupContext(context);
|
||||
FastBitmapDrawable.setFlagHoverEnabled(ENABLE_CURSOR_HOVER_STATES.get());
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.BubbleTextView, defStyle, 0);
|
||||
@@ -665,6 +667,18 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the layout is horizontal.
|
||||
*/
|
||||
public void setLayoutHorizontal(boolean layoutHorizontal) {
|
||||
if (mLayoutHorizontal == layoutHorizontal) {
|
||||
return;
|
||||
}
|
||||
|
||||
mLayoutHorizontal = layoutHorizontal;
|
||||
applyCompoundDrawables(getIconOrTransparentColor());
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to vertically center the content.
|
||||
*/
|
||||
@@ -991,10 +1005,14 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver,
|
||||
if (!mIsIconVisible) {
|
||||
resetIconScale();
|
||||
}
|
||||
Drawable icon = visible ? mIcon : new ColorDrawable(Color.TRANSPARENT);
|
||||
Drawable icon = getIconOrTransparentColor();
|
||||
applyCompoundDrawables(icon);
|
||||
}
|
||||
|
||||
private Drawable getIconOrTransparentColor() {
|
||||
return mIsIconVisible ? mIcon : new ColorDrawable(Color.TRANSPARENT);
|
||||
}
|
||||
|
||||
/** Sets the icon visual state to disabled or not. */
|
||||
public void setIconDisabled(boolean isDisabled) {
|
||||
if (mIcon != null) {
|
||||
|
||||
@@ -245,6 +245,7 @@ public class CellLayout extends ViewGroup {
|
||||
// the user where a dragged item will land when dropped.
|
||||
setWillNotDraw(false);
|
||||
setClipToPadding(false);
|
||||
setClipChildren(false);
|
||||
mActivity = ActivityContext.lookupContext(context);
|
||||
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
|
||||
|
||||
|
||||
@@ -198,6 +198,7 @@ import com.android.launcher3.touch.ItemLongClickListener;
|
||||
import com.android.launcher3.uioverrides.plugins.PluginManagerWrapper;
|
||||
import com.android.launcher3.util.ActivityResultInfo;
|
||||
import com.android.launcher3.util.ActivityTracker;
|
||||
import com.android.launcher3.util.CannedAnimationCoordinator;
|
||||
import com.android.launcher3.util.ComponentKey;
|
||||
import com.android.launcher3.util.IntArray;
|
||||
import com.android.launcher3.util.IntSet;
|
||||
@@ -421,6 +422,9 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
private StartupLatencyLogger mStartupLatencyLogger;
|
||||
private CellPosMapper mCellPosMapper = CellPosMapper.DEFAULT;
|
||||
|
||||
private final CannedAnimationCoordinator mAnimationCoordinator =
|
||||
new CannedAnimationCoordinator(this);
|
||||
|
||||
@Override
|
||||
@TargetApi(Build.VERSION_CODES.S)
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
@@ -3422,4 +3426,11 @@ public class Launcher extends StatefulActivity<LauncherState>
|
||||
public void launchAppPair(WorkspaceItemInfo app1, WorkspaceItemInfo app2) {
|
||||
// Overridden
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the animation coordinator for playing one-off animations
|
||||
*/
|
||||
public CannedAnimationCoordinator getAnimationCoordinator() {
|
||||
return mAnimationCoordinator;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +66,7 @@ public class ShortcutAndWidgetContainer extends ViewGroup implements FolderIcon.
|
||||
mActivity = ActivityContext.lookupContext(context);
|
||||
mWallpaperManager = WallpaperManager.getInstance(context);
|
||||
mContainerType = containerType;
|
||||
setClipChildren(false);
|
||||
}
|
||||
|
||||
public void setCellDimensions(int cellWidth, int cellHeight, int countX, int countY,
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License
|
||||
*/
|
||||
|
||||
package com.android.launcher3.util
|
||||
|
||||
import android.animation.AnimatorSet
|
||||
import android.animation.ValueAnimator
|
||||
import android.util.Log
|
||||
import android.view.ViewTreeObserver.OnGlobalLayoutListener
|
||||
import androidx.core.view.OneShotPreDrawListener
|
||||
import com.android.app.animation.Interpolators.LINEAR
|
||||
import com.android.launcher3.anim.AnimatorListeners
|
||||
import com.android.launcher3.anim.AnimatorPlaybackController
|
||||
import com.android.launcher3.anim.PendingAnimation
|
||||
import com.android.launcher3.statemanager.StatefulActivity
|
||||
import java.util.function.Consumer
|
||||
|
||||
private const val TAG = "CannedAnimCoordinator"
|
||||
|
||||
/**
|
||||
* Utility class to run a canned animation on Launcher.
|
||||
*
|
||||
* This class takes care to registering animations with stateManager and ensures that only one
|
||||
* animation is playing at a time.
|
||||
*/
|
||||
class CannedAnimationCoordinator(private val activity: StatefulActivity<*>) {
|
||||
|
||||
private val launcherLayoutListener = OnGlobalLayoutListener { scheduleRecreateAnimOnPreDraw() }
|
||||
private var recreatePending = false
|
||||
|
||||
private var animationProvider: Any? = null
|
||||
|
||||
private var animationDuration: Long = 0L
|
||||
private var animationFactory: Consumer<PendingAnimation>? = null
|
||||
private var animationController: AnimatorPlaybackController? = null
|
||||
|
||||
private var currentAnim: AnimatorPlaybackController? = null
|
||||
|
||||
/**
|
||||
* Sets the current animation cancelling any previously set animation.
|
||||
*
|
||||
* Callers can control the animation using {@link #getPlaybackController}. The state is
|
||||
* automatically cleared when the playback controller ends. The animation is automatically
|
||||
* recreated when any layout change happens. Callers can also ask for recreation by calling
|
||||
* {@link #recreateAnimation}
|
||||
*/
|
||||
fun setAnimation(provider: Any, factory: Consumer<PendingAnimation>, duration: Long) {
|
||||
if (provider != animationProvider) {
|
||||
Log.e(TAG, "Trying to play two animations together, $provider and $animationProvider")
|
||||
}
|
||||
|
||||
// Cancel any previously running animation
|
||||
endCurrentAnimation(false)
|
||||
animationController?.dispatchOnCancel()?.dispatchOnEnd()
|
||||
|
||||
animationProvider = provider
|
||||
animationFactory = factory
|
||||
animationDuration = duration
|
||||
|
||||
// Setup a new controller and link it with launcher state animation
|
||||
val anim = AnimatorSet()
|
||||
anim.play(
|
||||
ValueAnimator.ofFloat(0f, 1f).apply {
|
||||
interpolator = LINEAR
|
||||
this.duration = duration
|
||||
addUpdateListener { anim -> currentAnim?.setPlayFraction(anim.animatedFraction) }
|
||||
}
|
||||
)
|
||||
val controller = AnimatorPlaybackController.wrap(anim, duration)
|
||||
anim.addListener(
|
||||
AnimatorListeners.forEndCallback { success ->
|
||||
if (animationController != controller) {
|
||||
return@forEndCallback
|
||||
}
|
||||
|
||||
endCurrentAnimation(success)
|
||||
animationController = null
|
||||
animationFactory = null
|
||||
animationProvider = null
|
||||
|
||||
activity.rootView.viewTreeObserver.apply {
|
||||
if (isAlive) {
|
||||
removeOnGlobalLayoutListener(launcherLayoutListener)
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// Recreate animation whenever layout happens in case transforms change during layout
|
||||
activity.rootView.viewTreeObserver.apply {
|
||||
if (isAlive) {
|
||||
addOnGlobalLayoutListener(launcherLayoutListener)
|
||||
}
|
||||
}
|
||||
// Link this to the state manager so that it auto-cancels when state changes
|
||||
recreatePending = false
|
||||
animationController =
|
||||
controller.apply { activity.stateManager.setCurrentUserControlledAnimation(this) }
|
||||
recreateAnimation(provider)
|
||||
}
|
||||
|
||||
private fun endCurrentAnimation(success: Boolean) {
|
||||
currentAnim?.apply {
|
||||
// When cancelling an animation, apply final progress so that all transformations
|
||||
// are restored
|
||||
setPlayFraction(1f)
|
||||
if (!success) dispatchOnCancel()
|
||||
dispatchOnEnd()
|
||||
}
|
||||
currentAnim = null
|
||||
}
|
||||
|
||||
/** Returns the current animation controller to control the animation */
|
||||
fun getPlaybackController(provider: Any): AnimatorPlaybackController? {
|
||||
return if (provider == animationProvider) animationController
|
||||
else {
|
||||
Log.d(TAG, "Wrong controller access from $provider, actual provider $animationProvider")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun scheduleRecreateAnimOnPreDraw() {
|
||||
if (!recreatePending) {
|
||||
recreatePending = true
|
||||
OneShotPreDrawListener.add(activity.rootView) {
|
||||
if (recreatePending) {
|
||||
recreatePending = false
|
||||
animationProvider?.apply { recreateAnimation(this) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Notify the controller to recreate the animation. The animation progress is preserved */
|
||||
fun recreateAnimation(provider: Any) {
|
||||
if (provider != animationProvider) {
|
||||
Log.e(TAG, "Ignore recreate request from $provider, actual provider $animationProvider")
|
||||
return
|
||||
}
|
||||
endCurrentAnimation(false /* success */)
|
||||
|
||||
if (animationFactory == null || animationController == null) {
|
||||
return
|
||||
}
|
||||
currentAnim =
|
||||
PendingAnimation(animationDuration)
|
||||
.apply { animationFactory?.accept(this) }
|
||||
.createPlaybackController()
|
||||
.apply { setPlayFraction(animationController!!.progressFraction) }
|
||||
}
|
||||
}
|
||||
@@ -40,8 +40,7 @@ public class MultiScalePropertyFactory<T extends View> {
|
||||
private static final boolean DEBUG = false;
|
||||
private static final String TAG = "MultiScaleProperty";
|
||||
private final String mName;
|
||||
private final ArrayMap<Integer, MultiScaleProperty> mProperties =
|
||||
new ArrayMap<Integer, MultiScaleProperty>();
|
||||
private final ArrayMap<Integer, MultiScaleProperty> mProperties = new ArrayMap<>();
|
||||
|
||||
// This is an optimization for cases when set is called repeatedly with the same setterIndex.
|
||||
private float mMinOfOthers = 0;
|
||||
@@ -55,7 +54,7 @@ public class MultiScalePropertyFactory<T extends View> {
|
||||
}
|
||||
|
||||
/** Returns the [MultiFloatProperty] associated with [inx], creating it if not present. */
|
||||
public MultiScaleProperty get(Integer index) {
|
||||
public FloatProperty<T> get(Integer index) {
|
||||
return mProperties.computeIfAbsent(index,
|
||||
(k) -> new MultiScaleProperty(index, mName + "_" + index));
|
||||
}
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.icons;
|
||||
|
||||
import static com.android.launcher3.icons.FastBitmapDrawable.CLICK_FEEDBACK_DURATION;
|
||||
import static com.android.launcher3.icons.FastBitmapDrawable.HOVERED_SCALE;
|
||||
import static com.android.launcher3.icons.FastBitmapDrawable.HOVER_FEEDBACK_DURATION;
|
||||
import static com.android.launcher3.icons.FastBitmapDrawable.PRESSED_SCALE;
|
||||
import static com.android.launcher3.icons.FastBitmapDrawable.SCALE;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
import static org.mockito.Mockito.spy;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.view.animation.AccelerateInterpolator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.PathInterpolator;
|
||||
|
||||
import androidx.test.annotation.UiThreadTest;
|
||||
import androidx.test.filters.SmallTest;
|
||||
import androidx.test.runner.AndroidJUnit4;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.Spy;
|
||||
|
||||
/**
|
||||
* Tests for FastBitmapDrawable.
|
||||
*/
|
||||
@SmallTest
|
||||
@UiThreadTest
|
||||
@RunWith(AndroidJUnit4.class)
|
||||
public class FastBitmapDrawableTest {
|
||||
private static final float EPSILON = 0.00001f;
|
||||
|
||||
@Spy
|
||||
FastBitmapDrawable mFastBitmapDrawable =
|
||||
spy(new FastBitmapDrawable(Bitmap.createBitmap(100, 100, Bitmap.Config.ARGB_8888)));
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
FastBitmapDrawable.setFlagHoverEnabled(true);
|
||||
when(mFastBitmapDrawable.isVisible()).thenReturn(true);
|
||||
mFastBitmapDrawable.mIsPressed = false;
|
||||
mFastBitmapDrawable.mIsHovered = false;
|
||||
mFastBitmapDrawable.resetScale();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_noState() {
|
||||
int[] state = new int[]{};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// No scale changes without state change.
|
||||
assertFalse("State change handled.", isHandled);
|
||||
assertNull("Scale animation not null.", mFastBitmapDrawable.mScaleAnimation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_statePressed() {
|
||||
int[] state = new int[]{android.R.attr.state_pressed};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// Animate to state pressed.
|
||||
assertTrue("State change not handled.", isHandled);
|
||||
assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
|
||||
CLICK_FEEDBACK_DURATION);
|
||||
mFastBitmapDrawable.mScaleAnimation.end();
|
||||
assertEquals("End value not correct.",
|
||||
(float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
|
||||
assertTrue("Wrong interpolator used.",
|
||||
mFastBitmapDrawable.mScaleAnimation.getInterpolator()
|
||||
instanceof AccelerateInterpolator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateHovered() {
|
||||
int[] state = new int[]{android.R.attr.state_hovered};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// Animate to state hovered.
|
||||
assertTrue("State change not handled.", isHandled);
|
||||
assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
|
||||
HOVER_FEEDBACK_DURATION);
|
||||
mFastBitmapDrawable.mScaleAnimation.end();
|
||||
assertEquals("End value not correct.",
|
||||
(float) SCALE.get(mFastBitmapDrawable), HOVERED_SCALE, EPSILON);
|
||||
assertTrue("Wrong interpolator used.",
|
||||
mFastBitmapDrawable.mScaleAnimation.getInterpolator() instanceof PathInterpolator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateHoveredFlagDisabled() {
|
||||
FastBitmapDrawable.setFlagHoverEnabled(false);
|
||||
int[] state = new int[]{android.R.attr.state_hovered};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// No state change with flag disabled.
|
||||
assertFalse("Hover state change handled with flag disabled.", isHandled);
|
||||
assertNull("Animation should not run with hover flag disabled.",
|
||||
mFastBitmapDrawable.mScaleAnimation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_statePressedAndHovered() {
|
||||
int[] state = new int[]{android.R.attr.state_pressed, android.R.attr.state_hovered};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// Animate to pressed state only.
|
||||
assertTrue("State change not handled.", isHandled);
|
||||
assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
|
||||
CLICK_FEEDBACK_DURATION);
|
||||
mFastBitmapDrawable.mScaleAnimation.end();
|
||||
assertEquals("End value not correct.",
|
||||
(float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
|
||||
assertTrue("Wrong interpolator used.",
|
||||
mFastBitmapDrawable.mScaleAnimation.getInterpolator()
|
||||
instanceof AccelerateInterpolator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateHoveredAndPressed() {
|
||||
int[] state = new int[]{android.R.attr.state_hovered, android.R.attr.state_pressed};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// Animate to pressed state only.
|
||||
assertTrue("State change not handled.", isHandled);
|
||||
assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
|
||||
CLICK_FEEDBACK_DURATION);
|
||||
mFastBitmapDrawable.mScaleAnimation.end();
|
||||
assertEquals("End value not correct.",
|
||||
(float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
|
||||
assertTrue("Wrong interpolator used.",
|
||||
mFastBitmapDrawable.mScaleAnimation.getInterpolator()
|
||||
instanceof AccelerateInterpolator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateHoveredAndPressedToPressed() {
|
||||
mFastBitmapDrawable.mIsPressed = true;
|
||||
mFastBitmapDrawable.mIsHovered = true;
|
||||
SCALE.setValue(mFastBitmapDrawable, PRESSED_SCALE);
|
||||
int[] state = new int[]{android.R.attr.state_pressed};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// No scale change from pressed state to pressed state.
|
||||
assertTrue("State not changed.", isHandled);
|
||||
assertEquals("End value not correct.",
|
||||
(float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateHoveredAndPressedToHovered() {
|
||||
mFastBitmapDrawable.mIsPressed = true;
|
||||
mFastBitmapDrawable.mIsHovered = true;
|
||||
SCALE.setValue(mFastBitmapDrawable, PRESSED_SCALE);
|
||||
int[] state = new int[]{android.R.attr.state_hovered};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// No scale change from pressed state to hovered state.
|
||||
assertTrue("State not changed.", isHandled);
|
||||
assertEquals("End value not correct.",
|
||||
(float) SCALE.get(mFastBitmapDrawable), HOVERED_SCALE, EPSILON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateHoveredToPressed() {
|
||||
mFastBitmapDrawable.mIsHovered = true;
|
||||
SCALE.setValue(mFastBitmapDrawable, HOVERED_SCALE);
|
||||
int[] state = new int[]{android.R.attr.state_pressed};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// No scale change from pressed state to hovered state.
|
||||
assertTrue("State not changed.", isHandled);
|
||||
assertEquals("End value not correct.",
|
||||
(float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_statePressedToHovered() {
|
||||
mFastBitmapDrawable.mIsPressed = true;
|
||||
SCALE.setValue(mFastBitmapDrawable, PRESSED_SCALE);
|
||||
int[] state = new int[]{android.R.attr.state_hovered};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// No scale change from pressed state to hovered state.
|
||||
assertTrue("State not changed.", isHandled);
|
||||
assertEquals("End value not correct.",
|
||||
(float) SCALE.get(mFastBitmapDrawable), HOVERED_SCALE, EPSILON);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateDefaultFromPressed() {
|
||||
mFastBitmapDrawable.mIsPressed = true;
|
||||
SCALE.setValue(mFastBitmapDrawable, PRESSED_SCALE);
|
||||
int[] state = new int[]{};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// Animate to default state from pressed state.
|
||||
assertTrue("State change not handled.", isHandled);
|
||||
assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
|
||||
CLICK_FEEDBACK_DURATION);
|
||||
mFastBitmapDrawable.mScaleAnimation.end();
|
||||
assertEquals("End value not correct.", (float) SCALE.get(mFastBitmapDrawable), 1f, EPSILON);
|
||||
assertTrue("Wrong interpolator used.",
|
||||
mFastBitmapDrawable.mScaleAnimation.getInterpolator()
|
||||
instanceof DecelerateInterpolator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateDefaultFromHovered() {
|
||||
mFastBitmapDrawable.mIsHovered = true;
|
||||
SCALE.setValue(mFastBitmapDrawable, HOVERED_SCALE);
|
||||
int[] state = new int[]{};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// Animate to default state from hovered state.
|
||||
assertTrue("State change not handled.", isHandled);
|
||||
assertEquals("Duration not correct.", mFastBitmapDrawable.mScaleAnimation.getDuration(),
|
||||
HOVER_FEEDBACK_DURATION);
|
||||
mFastBitmapDrawable.mScaleAnimation.end();
|
||||
assertEquals("End value not correct.", (float) SCALE.get(mFastBitmapDrawable), 1f, EPSILON);
|
||||
assertTrue("Wrong interpolator used.",
|
||||
mFastBitmapDrawable.mScaleAnimation.getInterpolator() instanceof PathInterpolator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateHoveredWhilePartiallyScaled() {
|
||||
SCALE.setValue(mFastBitmapDrawable, 0.5f);
|
||||
int[] state = new int[]{android.R.attr.state_hovered};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// Animate to hovered state from midway to pressed state.
|
||||
assertTrue("State change not handled.", isHandled);
|
||||
assertEquals("Duration not correct.",
|
||||
mFastBitmapDrawable.mScaleAnimation.getDuration(), HOVER_FEEDBACK_DURATION);
|
||||
mFastBitmapDrawable.mScaleAnimation.end();
|
||||
assertEquals("End value not correct.",
|
||||
(float) SCALE.get(mFastBitmapDrawable), HOVERED_SCALE, EPSILON);
|
||||
assertTrue("Wrong interpolator used.",
|
||||
mFastBitmapDrawable.mScaleAnimation.getInterpolator() instanceof PathInterpolator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_statePressedWhilePartiallyScaled() {
|
||||
SCALE.setValue(mFastBitmapDrawable, 0.5f);
|
||||
int[] state = new int[]{android.R.attr.state_pressed};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// Animate to pressed state from midway to hovered state.
|
||||
assertTrue("State change not handled.", isHandled);
|
||||
assertEquals("Duration not correct.",
|
||||
mFastBitmapDrawable.mScaleAnimation.getDuration(), CLICK_FEEDBACK_DURATION);
|
||||
mFastBitmapDrawable.mScaleAnimation.end();
|
||||
assertEquals("End value not correct.",
|
||||
(float) SCALE.get(mFastBitmapDrawable), PRESSED_SCALE, EPSILON);
|
||||
assertTrue("Wrong interpolator used.",
|
||||
mFastBitmapDrawable.mScaleAnimation.getInterpolator()
|
||||
instanceof AccelerateInterpolator);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateDefaultFromPressedNotVisible() {
|
||||
when(mFastBitmapDrawable.isVisible()).thenReturn(false);
|
||||
mFastBitmapDrawable.mIsPressed = true;
|
||||
SCALE.setValue(mFastBitmapDrawable, PRESSED_SCALE);
|
||||
clearInvocations(mFastBitmapDrawable);
|
||||
int[] state = new int[]{};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// No animations when state was pressed but drawable no longer visible. Set values directly.
|
||||
assertTrue("State change not handled.", isHandled);
|
||||
assertNull("Scale animation not null.", mFastBitmapDrawable.mScaleAnimation);
|
||||
assertEquals("End value not correct.", (float) SCALE.get(mFastBitmapDrawable), 1f, EPSILON);
|
||||
verify(mFastBitmapDrawable).invalidateSelf();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnStateChange_stateDefaultFromHoveredNotVisible() {
|
||||
when(mFastBitmapDrawable.isVisible()).thenReturn(false);
|
||||
mFastBitmapDrawable.mIsHovered = true;
|
||||
SCALE.setValue(mFastBitmapDrawable, HOVERED_SCALE);
|
||||
clearInvocations(mFastBitmapDrawable);
|
||||
int[] state = new int[]{};
|
||||
|
||||
boolean isHandled = mFastBitmapDrawable.onStateChange(state);
|
||||
|
||||
// No animations when state was hovered but drawable no longer visible. Set values directly.
|
||||
assertTrue("State change not handled.", isHandled);
|
||||
assertNull("Scale animation not null.", mFastBitmapDrawable.mScaleAnimation);
|
||||
assertEquals("End value not correct.", (float) SCALE.get(mFastBitmapDrawable), 1f, EPSILON);
|
||||
verify(mFastBitmapDrawable).invalidateSelf();
|
||||
}
|
||||
}
|
||||
@@ -395,6 +395,28 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLaunchHomeScreenMenuItem() {
|
||||
// Drag the test app icon to home screen and open short cut menu from the icon
|
||||
final HomeAllApps allApps = mLauncher.getWorkspace().switchToAllApps();
|
||||
allApps.freeze();
|
||||
try {
|
||||
allApps.getAppIcon(APP_NAME).dragToWorkspace(false, false);
|
||||
final AppIconMenu menu = mLauncher.getWorkspace().getWorkspaceAppIcon(
|
||||
APP_NAME).openDeepShortcutMenu();
|
||||
|
||||
executeOnLauncher(
|
||||
launcher -> assertTrue("Launcher internal state didn't switch to Showing Menu",
|
||||
isOptionsPopupVisible(launcher)));
|
||||
|
||||
final AppIconMenuItem menuItem = menu.getMenuItem(1);
|
||||
assertEquals("Wrong menu item", "Shortcut 2", menuItem.getText());
|
||||
menuItem.launch(getAppPackageName());
|
||||
} finally {
|
||||
allApps.unfreeze();
|
||||
}
|
||||
}
|
||||
|
||||
@PlatinumTest(focusArea = "launcher")
|
||||
@Test
|
||||
@PortraitLandscape
|
||||
|
||||
@@ -56,7 +56,10 @@ final class FlashDetector extends AnomalyDetector {
|
||||
RECENTS_DRAG_LAYER + "FallbackRecentsView:id/overview_panel|TaskView|IconView:id/icon",
|
||||
DRAG_LAYER + "SearchContainerView:id/apps_view",
|
||||
DRAG_LAYER + "LauncherDragView",
|
||||
DRAG_LAYER + "FloatingTaskView|FloatingTaskThumbnailView:id/thumbnail"
|
||||
DRAG_LAYER + "FloatingTaskView|FloatingTaskThumbnailView:id/thumbnail",
|
||||
DRAG_LAYER
|
||||
+ "WidgetsFullSheet|SpringRelativeLayout:id/container|WidgetsRecyclerView:id"
|
||||
+ "/primary_widgets_list_view|WidgetsListHeader:id/widgets_list_header"
|
||||
));
|
||||
|
||||
// Per-AnalysisNode data that's specific to this detector.
|
||||
|
||||
@@ -336,4 +336,11 @@ public abstract class AllApps extends LauncherInstrumentation.VisibleContainer {
|
||||
final Bundle testInfo = mLauncher.getTestInfo(TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS);
|
||||
return testInfo == null ? 0 : testInfo.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the QSB UI object on the AllApps screen.
|
||||
* @return the QSB UI object.
|
||||
*/
|
||||
@NonNull
|
||||
public abstract Qsb getQsb();
|
||||
}
|
||||
@@ -62,4 +62,10 @@ public class AllAppsFromTaskbar extends AllApps {
|
||||
return mLauncher.getTestInfo(TestProtocol.REQUEST_TASKBAR_APPS_LIST_SCROLL_Y)
|
||||
.getInt(TestProtocol.TEST_INFO_RESPONSE_FIELD);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public TaskbarAllAppsQsb getQsb() {
|
||||
return new TaskbarAllAppsQsb(mLauncher, verifyActiveContainer());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,16 +22,7 @@ import androidx.test.uiautomator.UiObject2;
|
||||
*/
|
||||
class AllAppsQsb extends Qsb {
|
||||
|
||||
private final UiObject2 mAllAppsContainer;
|
||||
|
||||
AllAppsQsb(LauncherInstrumentation launcher, UiObject2 allAppsContainer) {
|
||||
super(launcher);
|
||||
mAllAppsContainer = allAppsContainer;
|
||||
waitForQsbObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UiObject2 waitForQsbObject() {
|
||||
return mLauncher.waitForObjectInContainer(mAllAppsContainer, "search_container_all_apps");
|
||||
super(launcher, allAppsContainer, "search_container_all_apps");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -117,11 +117,8 @@ public class HomeAllApps extends AllApps {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the QSB UI object on the AllApps screen.
|
||||
* @return the QSB UI object.
|
||||
*/
|
||||
@NonNull
|
||||
@Override
|
||||
public Qsb getQsb() {
|
||||
return new AllAppsQsb(mLauncher, verifyActiveContainer());
|
||||
}
|
||||
|
||||
@@ -22,16 +22,7 @@ import androidx.test.uiautomator.UiObject2;
|
||||
*/
|
||||
class HomeQsb extends Qsb {
|
||||
|
||||
private final UiObject2 mHotSeat;
|
||||
|
||||
HomeQsb(LauncherInstrumentation launcher, UiObject2 hotseat) {
|
||||
super(launcher);
|
||||
mHotSeat = hotseat;
|
||||
waitForQsbObject();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UiObject2 waitForQsbObject() {
|
||||
return mLauncher.waitForObjectInContainer(mHotSeat, "search_container_hotseat");
|
||||
super(launcher, hotseat, "search_container_hotseat");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,13 +30,21 @@ public abstract class Qsb {
|
||||
private static final String ASSISTANT_APP_PACKAGE = "com.google.android.googlequicksearchbox";
|
||||
private static final String ASSISTANT_ICON_RES_ID = "mic_icon";
|
||||
protected final LauncherInstrumentation mLauncher;
|
||||
private final UiObject2 mContainer;
|
||||
private final String mQsbResName;
|
||||
|
||||
protected Qsb(LauncherInstrumentation launcher) {
|
||||
protected Qsb(LauncherInstrumentation launcher, UiObject2 container, String qsbResName) {
|
||||
mLauncher = launcher;
|
||||
mContainer = container;
|
||||
mQsbResName = qsbResName;
|
||||
waitForQsbObject();
|
||||
}
|
||||
|
||||
// Waits for the quick search box.
|
||||
protected abstract UiObject2 waitForQsbObject();
|
||||
private UiObject2 waitForQsbObject() {
|
||||
return mLauncher.waitForObjectInContainer(mContainer, mQsbResName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch assistant app by tapping mic icon on qsb.
|
||||
*/
|
||||
@@ -79,8 +87,12 @@ public abstract class Qsb {
|
||||
mLauncher.waitForIdle();
|
||||
try (LauncherInstrumentation.Closable c2 = mLauncher.addContextLayer(
|
||||
"clicked qsb to open search result page")) {
|
||||
return new SearchResultFromQsb(mLauncher);
|
||||
return createSearchResult();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected SearchResultFromQsb createSearchResult() {
|
||||
return new SearchResultFromQsb(mLauncher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ public class SearchResultFromQsb {
|
||||
|
||||
// This particular ID change should happen with caution
|
||||
private static final String SEARCH_CONTAINER_RES_ID = "search_results_list_view";
|
||||
private final LauncherInstrumentation mLauncher;
|
||||
protected final LauncherInstrumentation mLauncher;
|
||||
|
||||
SearchResultFromQsb(LauncherInstrumentation launcher) {
|
||||
mLauncher = launcher;
|
||||
@@ -49,8 +49,12 @@ public class SearchResultFromQsb {
|
||||
}
|
||||
|
||||
/** Find the app from search results with app name. */
|
||||
public Launchable findAppIcon(String appName) {
|
||||
public AppIcon findAppIcon(String appName) {
|
||||
UiObject2 icon = mLauncher.waitForLauncherObject(By.clazz(TextView.class).text(appName));
|
||||
return createAppIcon(icon);
|
||||
}
|
||||
|
||||
protected AppIcon createAppIcon(UiObject2 icon) {
|
||||
return new AllAppsAppIcon(mLauncher, icon);
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.tapl;
|
||||
|
||||
import androidx.test.uiautomator.UiObject2;
|
||||
|
||||
/**
|
||||
* Operations on search result page opened from Taskbar qsb.
|
||||
*/
|
||||
public class SearchResultFromTaskbarQsb extends SearchResultFromQsb {
|
||||
|
||||
SearchResultFromTaskbarQsb(LauncherInstrumentation launcher) {
|
||||
super(launcher);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TaskbarAppIcon findAppIcon(String appName) {
|
||||
return (TaskbarAppIcon) super.findAppIcon(appName);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TaskbarAppIcon createAppIcon(UiObject2 icon) {
|
||||
return new TaskbarAppIcon(mLauncher, icon);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.android.launcher3.tapl;
|
||||
|
||||
import androidx.test.uiautomator.UiObject2;
|
||||
|
||||
/**
|
||||
* Operations on Taskbar AllApp screen qsb.
|
||||
*/
|
||||
public class TaskbarAllAppsQsb extends Qsb {
|
||||
|
||||
TaskbarAllAppsQsb(LauncherInstrumentation launcher, UiObject2 allAppsContainer) {
|
||||
super(launcher, allAppsContainer, "search_container_all_apps");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SearchResultFromTaskbarQsb showSearchResult() {
|
||||
return (SearchResultFromTaskbarQsb) super.showSearchResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SearchResultFromTaskbarQsb createSearchResult() {
|
||||
return new SearchResultFromTaskbarQsb(mLauncher);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user