diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java index 965f474b51..53afd211a9 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickSwitchState.java @@ -35,7 +35,13 @@ public class QuickSwitchState extends BackgroundAppState { float shiftRange = launcher.getAllAppsController().getShiftRange(); float shiftProgress = getVerticalProgress(launcher) - NORMAL.getVerticalProgress(launcher); float translationY = shiftProgress * shiftRange; - return new ScaleAndTranslation(1, 0, translationY); + return new ScaleAndTranslation(0.9f, 0, translationY); + } + + @Override + public float getVerticalProgress(Launcher launcher) { + // Don't move all apps shelf while quick-switching (just let it fade). + return 1f; } @Override diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java index 697516d113..77b0804dd5 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NoButtonQuickSwitchTouchController.java @@ -23,7 +23,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW_ACTIONS; import static com.android.launcher3.LauncherState.QUICK_SWITCH; import static com.android.launcher3.anim.AlphaUpdateListener.ALPHA_CUTOFF_THRESHOLD; import static com.android.launcher3.anim.Interpolators.ACCEL_0_75; -import static com.android.launcher3.anim.Interpolators.DEACCEL_5; +import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity; import static com.android.launcher3.logging.StatsLogManager.LAUNCHER_STATE_HOME; @@ -31,9 +31,10 @@ import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCH import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_UNKNOWN_SWIPEUP; import static com.android.launcher3.logging.StatsLogManager.getLauncherAtomEvent; import static com.android.launcher3.states.StateAnimationConfig.ANIM_ALL_APPS_FADE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_DEPTH; import static com.android.launcher3.states.StateAnimationConfig.ANIM_VERTICAL_PROGRESS; import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_FADE; -import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_TRANSLATE; +import static com.android.launcher3.states.StateAnimationConfig.ANIM_WORKSPACE_SCALE; import static com.android.launcher3.states.StateAnimationConfig.SKIP_ALL_ANIMATIONS; import static com.android.launcher3.states.StateAnimationConfig.SKIP_OVERVIEW; import static com.android.launcher3.touch.BothAxesSwipeDetector.DIRECTION_RIGHT; @@ -80,9 +81,8 @@ import com.android.quickstep.views.LauncherRecentsView; public class NoButtonQuickSwitchTouchController implements TouchController, BothAxesSwipeDetector.Listener { - /** The minimum progress of the scale/translationY animation until drag end. */ private static final float Y_ANIM_MIN_PROGRESS = 0.25f; - private static final Interpolator FADE_OUT_INTERPOLATOR = DEACCEL_5; + private static final Interpolator FADE_OUT_INTERPOLATOR = DEACCEL_3; private static final Interpolator TRANSLATE_OUT_INTERPOLATOR = ACCEL_0_75; private static final Interpolator SCALE_DOWN_INTERPOLATOR = LINEAR; private static final long ATOMIC_DURATION_FROM_PAUSED_TO_OVERVIEW = 300; @@ -187,7 +187,8 @@ public class NoButtonQuickSwitchTouchController implements TouchController, StateAnimationConfig nonOverviewBuilder = new StateAnimationConfig(); nonOverviewBuilder.setInterpolator(ANIM_WORKSPACE_FADE, FADE_OUT_INTERPOLATOR); nonOverviewBuilder.setInterpolator(ANIM_ALL_APPS_FADE, FADE_OUT_INTERPOLATOR); - nonOverviewBuilder.setInterpolator(ANIM_WORKSPACE_TRANSLATE, TRANSLATE_OUT_INTERPOLATOR); + nonOverviewBuilder.setInterpolator(ANIM_WORKSPACE_SCALE, FADE_OUT_INTERPOLATOR); + nonOverviewBuilder.setInterpolator(ANIM_DEPTH, FADE_OUT_INTERPOLATOR); nonOverviewBuilder.setInterpolator(ANIM_VERTICAL_PROGRESS, TRANSLATE_OUT_INTERPOLATOR); updateNonOverviewAnim(QUICK_SWITCH, nonOverviewBuilder); mNonOverviewAnim.dispatchOnStart(); @@ -207,7 +208,7 @@ public class NoButtonQuickSwitchTouchController implements TouchController, /** Create state animation to control non-overview components. */ private void updateNonOverviewAnim(LauncherState toState, StateAnimationConfig config) { config.duration = (long) (Math.max(mXRange, mYRange) * 2); - config.animFlags = config.animFlags | SKIP_OVERVIEW; + config.animFlags |= SKIP_OVERVIEW; mNonOverviewAnim = mLauncher.getStateManager() .createAnimationToNewWorkspace(toState, config); mNonOverviewAnim.getTarget().addListener(mClearStateOnCancelListener); diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java index 3f7190f017..c4263290f7 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/TwoButtonNavbarTouchController.java @@ -24,11 +24,13 @@ import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import android.animation.ValueAnimator; import android.os.SystemClock; +import android.util.Log; import android.view.MotionEvent; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SingleAxisSwipeDetector; import com.android.quickstep.SystemUiProxy; @@ -76,9 +78,18 @@ public class TwoButtonNavbarTouchController extends AbstractStateChangeTouchCont return true; } if (AbstractFloatingView.getTopOpenView(mLauncher) != null) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.TWO_BUTTON_NORMAL_NOT_OVERVIEW, + "Didn't intercept touch due to top view: " + + AbstractFloatingView.getTopOpenView(mLauncher)); + } return false; } if ((ev.getEdgeFlags() & EDGE_NAV_BAR) == 0) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.TWO_BUTTON_NORMAL_NOT_OVERVIEW, + "Didn't intercept touch because event wasn't from nav bar"); + } return false; } if (!mIsTransposed && mLauncher.isInState(OVERVIEW)) { @@ -89,14 +100,21 @@ public class TwoButtonNavbarTouchController extends AbstractStateChangeTouchCont @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { + final LauncherState targetState; if (mIsTransposed) { boolean draggingFromNav = mLauncher.getDeviceProfile().isSeascape() == isDragTowardPositive; - return draggingFromNav ? HINT_STATE_TWO_BUTTON : NORMAL; + targetState = draggingFromNav ? HINT_STATE_TWO_BUTTON : NORMAL; } else { LauncherState startState = mStartState != null ? mStartState : fromState; - return isDragTowardPositive ^ (startState == OVERVIEW) ? HINT_STATE_TWO_BUTTON : NORMAL; + targetState = isDragTowardPositive ^ (startState == OVERVIEW) + ? HINT_STATE_TWO_BUTTON : NORMAL; } + + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.TWO_BUTTON_NORMAL_NOT_OVERVIEW, "Target state: " + targetState); + } + return targetState; } @Override diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java index 23e35f6307..4a191e16e7 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java @@ -138,7 +138,7 @@ public class RecentsAnimationDeviceState implements mDisplayId = mDisplayHolder.getInfo().id; mIsOneHandedModeSupported = SystemProperties.getBoolean(SUPPORT_ONE_HANDED_MODE, false); runOnDestroy(() -> mDisplayHolder.removeChangeListener(this)); - mRotationTouchHelper = new RotationTouchHelper(context, mDisplayHolder); + mRotationTouchHelper = RotationTouchHelper.INSTANCE.get(context); runOnDestroy(mRotationTouchHelper::destroy); // Register for user unlocked if necessary diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index ba24e6a6c7..c786167241 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -112,20 +112,19 @@ public class RecentsModel extends TaskStackChangeListener { } /** - * Finds and returns the task key associated with the given task id. + * Checks if a task has been removed or not. * - * @param callback The callback to receive the task key if it is found or null. This is always - * called on the UI thread. + * @param callback Receives true if task is removed, false otherwise */ - public void findTaskWithId(int taskId, Consumer callback) { + public void isTaskRemoved(int taskId, Consumer callback) { mTaskList.getTasks(true /* loadKeysOnly */, (tasks) -> { for (Task task : tasks) { if (task.key.id == taskId) { - callback.accept(task.key); + callback.accept(false); return; } } - callback.accept(null); + callback.accept(true); }); } diff --git a/quickstep/src/com/android/quickstep/RotationTouchHelper.java b/quickstep/src/com/android/quickstep/RotationTouchHelper.java index 2cf32122cf..1155482d37 100644 --- a/quickstep/src/com/android/quickstep/RotationTouchHelper.java +++ b/quickstep/src/com/android/quickstep/RotationTouchHelper.java @@ -28,9 +28,11 @@ import android.view.MotionEvent; import android.view.OrientationEventListener; import com.android.launcher3.testing.TestProtocol; +import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.DisplayController.DisplayHolder; import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener; import com.android.launcher3.util.DisplayController.Info; +import com.android.launcher3.util.MainThreadInitializedObject; import com.android.quickstep.util.RecentsOrientedState; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.QuickStepContract; @@ -43,6 +45,9 @@ public class RotationTouchHelper implements SysUINavigationMode.NavigationModeChangeListener, DisplayInfoChangeListener { + public static final MainThreadInitializedObject INSTANCE = + new MainThreadInitializedObject<>(RotationTouchHelper::new); + private final OrientationTouchTransformer mOrientationTouchTransformer; private final DisplayHolder mDisplayHolder; private final SysUINavigationMode mSysUiNavMode; @@ -121,9 +126,9 @@ public class RotationTouchHelper implements private final Context mContext; - public RotationTouchHelper(Context context, DisplayHolder displayHolder) { + private RotationTouchHelper(Context context) { mContext = context; - mDisplayHolder = displayHolder; + mDisplayHolder = DisplayController.getDefaultDisplay(context); Resources resources = mContext.getResources(); mSysUiNavMode = SysUINavigationMode.INSTANCE.get(context); mDisplayId = mDisplayHolder.getInfo().id; diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 0ee28bc63d..f6018d1c2f 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -255,18 +255,6 @@ public class SystemUiProxy implements ISystemUiProxy, } } - @Override - public Bundle monitorGestureInput(String name, int displayId) { - if (mSystemUiProxy != null) { - try { - return mSystemUiProxy.monitorGestureInput(name, displayId); - } catch (RemoteException e) { - Log.w(TAG, "Failed call monitorGestureInput: " + name, e); - } - } - return null; - } - @Override public void notifyAccessibilityButtonClicked(int displayId) { if (mSystemUiProxy != null) { diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 524bae160e..87c46bfe49 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -72,7 +72,6 @@ import android.graphics.RectF; import android.graphics.Typeface; import android.graphics.drawable.Drawable; import android.os.Build; -import android.os.Handler; import android.os.UserHandle; import android.text.Layout; import android.text.StaticLayout; @@ -96,6 +95,7 @@ import android.widget.FrameLayout; import android.widget.ListView; import androidx.annotation.Nullable; +import androidx.annotation.UiThread; import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseActivity.MultiWindowModeChangedListener; @@ -111,6 +111,7 @@ import com.android.launcher3.anim.PendingAnimation; import com.android.launcher3.anim.SpringProperty; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.icons.cache.HandlerRunnable; import com.android.launcher3.statehandlers.DepthController; import com.android.launcher3.statemanager.BaseState; import com.android.launcher3.statemanager.StatefulActivity; @@ -153,6 +154,7 @@ import com.android.systemui.shared.system.PackageManagerWrapper; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat.SurfaceParams; import com.android.systemui.shared.system.TaskStackChangeListener; +import com.android.systemui.shared.system.TaskStackChangeListeners; import com.android.wm.shell.pip.IPipAnimationListener; import java.util.ArrayList; @@ -394,34 +396,27 @@ public abstract class RecentsView { - TaskView taskView = getTaskView(taskId); - if (taskView == null) { - return; - } - Handler handler = taskView.getHandler(); - if (handler == null) { - return; - } - - // TODO: Add callbacks from AM reflecting adding/removing from the recents list, and - // remove all these checks - Task.TaskKey taskKey = taskView.getTask().key; - if (PackageManagerWrapper.getInstance().getActivityInfo(taskKey.getComponent(), - taskKey.userId) == null) { - // The package was uninstalled - handler.post(() -> - dismissTask(taskView, true /* animate */, false /* removeTask */)); - } else { - mModel.findTaskWithId(taskKey.id, (key) -> { - if (key == null) { - // The task was removed from the recents list - handler.post(() -> dismissTask(taskView, true /* animate */, - false /* removeTask */)); + TaskView taskView = getTaskView(taskId); + if (taskView == null) { + return; + } + Task.TaskKey taskKey = taskView.getTask().key; + UI_HELPER_EXECUTOR.execute(new HandlerRunnable<>( + UI_HELPER_EXECUTOR.getHandler(), + () -> PackageManagerWrapper.getInstance() + .getActivityInfo(taskKey.getComponent(), taskKey.userId) == null, + MAIN_EXECUTOR, + apkRemoved -> { + if (apkRemoved) { + dismissTask(taskId); + } else { + mModel.isTaskRemoved(taskKey.id, taskRemoved -> { + if (taskRemoved) { + dismissTask(taskId); + } + }); } - }); - } - }); + })); } }; @@ -668,7 +663,7 @@ public abstract class RecentsView 24dp - - 16sp - 14sp - 12sp - 36dp - 16dp - 4dp - 28dp - 1dp - 0dp diff --git a/res/values/strings.xml b/res/values/strings.xml index 9072907260..0f937fac16 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -110,12 +110,6 @@ App - - - Apps - - Try Now - Notifications diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index 699495c7f2..eef3980f96 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -130,6 +130,10 @@ public class LauncherModel extends LauncherApps.Callback implements InstallSessi mModelDelegate = ModelDelegate.newInstance(context, app, mBgAllAppsList, mBgDataModel); } + public ModelDelegate getModelDelegate() { + return mModelDelegate; + } + /** * Adds the provided items to the workspace. */ diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 406e785ad5..41865ce5e2 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -75,9 +75,9 @@ import com.android.launcher3.workprofile.PersonalWorkSlidingTabStrip.OnActivePag public class AllAppsContainerView extends SpringRelativeLayout implements DragSource, Insettable, OnDeviceProfileChangeListener, OnActivePageChangedListener { - private static final float FLING_VELOCITY_MULTIPLIER = 1000 * .8f; + private static final float FLING_VELOCITY_MULTIPLIER = 1000 * .2f; // Starts the springs after at least 55% of the animation has passed. - private static final float FLING_ANIMATION_THRESHOLD = 0.55f; + private static final float FLING_ANIMATION_THRESHOLD = 0.25f; protected final BaseDraggingActivity mLauncher; protected final AdapterHolder[] mAH; diff --git a/src/com/android/launcher3/anim/Interpolators.java b/src/com/android/launcher3/anim/Interpolators.java index 7980138370..7a389374dc 100644 --- a/src/com/android/launcher3/anim/Interpolators.java +++ b/src/com/android/launcher3/anim/Interpolators.java @@ -46,7 +46,6 @@ public class Interpolators { public static final Interpolator DEACCEL_2 = new DecelerateInterpolator(2); public static final Interpolator DEACCEL_2_5 = new DecelerateInterpolator(2.5f); public static final Interpolator DEACCEL_3 = new DecelerateInterpolator(3f); - public static final Interpolator DEACCEL_5 = new DecelerateInterpolator(5f); public static final Interpolator ACCEL_DEACCEL = new AccelerateDecelerateInterpolator(); diff --git a/src/com/android/launcher3/dragndrop/AddItemActivity.java b/src/com/android/launcher3/dragndrop/AddItemActivity.java index b7a7366108..fc635a91db 100644 --- a/src/com/android/launcher3/dragndrop/AddItemActivity.java +++ b/src/com/android/launcher3/dragndrop/AddItemActivity.java @@ -62,6 +62,7 @@ import com.android.launcher3.widget.LauncherAppWidgetProviderInfo; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; import com.android.launcher3.widget.WidgetCell; +import com.android.launcher3.widget.WidgetCellPreview; import com.android.launcher3.widget.WidgetHostViewLoader; import com.android.launcher3.widget.WidgetImageView; import com.android.launcher3.widget.WidgetManagerHelper; @@ -121,9 +122,10 @@ public class AddItemActivity extends BaseActivity implements OnLongClickListener } } - WidgetImageView preview = mWidgetCell.findViewById(R.id.widget_preview); - preview.setOnTouchListener(this); - preview.setOnLongClickListener(this); + WidgetCellPreview previewContainer = mWidgetCell.findViewById( + R.id.widget_preview_container); + previewContainer.setOnTouchListener(this); + previewContainer.setOnLongClickListener(this); // savedInstanceState is null when the activity is created the first time (i.e., avoids // duplicate logging during rotation) diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index 943d129047..9a02b66218 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -113,4 +113,5 @@ public final class TestProtocol { public static final String WORK_PROFILE_REMOVED = "b/159671700"; public static final String TIS_NO_EVENTS = "b/180915942"; public static final String GET_RECENTS_FAILED = "b/177472267"; + public static final String TWO_BUTTON_NORMAL_NOT_OVERVIEW = "b/13714484"; } diff --git a/src/com/android/launcher3/widget/WidgetsBottomSheet.java b/src/com/android/launcher3/widget/WidgetsBottomSheet.java index 0670928159..155a285e84 100644 --- a/src/com/android/launcher3/widget/WidgetsBottomSheet.java +++ b/src/com/android/launcher3/widget/WidgetsBottomSheet.java @@ -170,9 +170,9 @@ public class WidgetsBottomSheet extends BaseWidgetSheet implements Insettable { WidgetCell widget = (WidgetCell) LayoutInflater.from(getContext()) .inflate(R.layout.widget_cell, parent, false); - View preview_container = widget.findViewById(R.id.widget_preview_container); - preview_container.setOnClickListener(this); - preview_container.setOnLongClickListener(this); + View previewContainer = widget.findViewById(R.id.widget_preview_container); + previewContainer.setOnClickListener(this); + previewContainer.setOnLongClickListener(this); widget.setAnimatePreview(false); parent.addView(widget); diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 475a4ff374..cf935f382a 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -365,7 +365,7 @@ public final class LauncherInstrumentation { if (hasSystemUiObject("keyguard_status_view")) return "Phone is locked"; - if (!mDevice.wait(Until.hasObject(By.textStartsWith("")), WAIT_TIME_MS)) { + if (!mDevice.wait(Until.hasObject(getAnyObjectSelector()), WAIT_TIME_MS)) { return "Screen is empty"; } @@ -388,7 +388,7 @@ public final class LauncherInstrumentation { } private String getVisiblePackages() { - return mDevice.findObjects(By.textStartsWith("")) + return mDevice.findObjects(getAnyObjectSelector()) .stream() .map(LauncherInstrumentation::getApplicationPackageSafe) .distinct() @@ -692,6 +692,9 @@ public final class LauncherInstrumentation { try (LauncherInstrumentation.Closable c = addContextLayer( "Swiped up from context menu to home")) { waitUntilLauncherObjectGone(CONTEXT_MENU_RES_ID); + // Swiping up can temporarily bring Nexus Launcher if the current + // Launcher is a Launcher3 one. Wait for the current launcher to reappear. + waitForLauncherObject(getAnyObjectSelector()); } } if (hasLauncherObject(WORKSPACE_RES_ID)) { @@ -736,9 +739,13 @@ public final class LauncherInstrumentation { } } + private static BySelector getAnyObjectSelector() { + return By.textStartsWith(""); + } + boolean isLauncherVisible() { mDevice.waitForIdle(); - return hasLauncherObject(By.textStartsWith("")); + return hasLauncherObject(getAnyObjectSelector()); } /**