Snap for 11623990 from 017af39acb to 24Q3-release

Change-Id: Iec649149bb819fd4b5bf598a3fe07f51c1ad8ce8
This commit is contained in:
Android Build Coastguard Worker
2024-03-25 23:21:12 +00:00
20 changed files with 376 additions and 588 deletions
+4 -23
View File
@@ -17,7 +17,7 @@ package {
default_applicable_licenses: ["Android-Apache-2.0"],
}
min_launcher3_sdk_version = "26"
min_launcher3_sdk_version = "30"
// Common source files used to build launcher (java and kotlin)
// All sources are split so they can be reused in many other libraries/apps in other folders
@@ -69,22 +69,6 @@ filegroup {
],
}
filegroup {
name: "launcher-ext_tests",
srcs: [
"ext_tests/**/*.java",
"ext_tests/**/*.kt",
],
}
filegroup {
name: "launcher-quickstep-ext_tests",
srcs: [
"quickstep/ext_tests/**/*.java",
"quickstep/ext_tests/**/*.kt",
],
}
// Proguard files for Launcher3
filegroup {
name: "launcher-proguard-rules",
@@ -186,7 +170,7 @@ android_library {
sdk_version: "current",
min_sdk_version: min_launcher3_sdk_version,
lint: {
baseline_filename: "lint-baseline2.xml",
baseline_filename: "lint-baseline.xml",
},
}
@@ -212,7 +196,7 @@ android_library {
min_sdk_version: min_launcher3_sdk_version,
manifest: "AndroidManifest-common.xml",
lint: {
baseline_filename: "lint-baseline2.xml",
baseline_filename: "lint-baseline.xml",
},
}
@@ -229,11 +213,8 @@ android_app {
":launcher-src",
":launcher-src_shortcuts_overrides",
":launcher-src_ui_overrides",
":launcher-ext_tests",
],
resource_dirs: [
"ext_tests/res",
],
optimize: {
proguard_flags_files: ["proguard.flags"],
// Proguard is disable for testing. Derivarive prjects to keep proguard enabled
-5
View File
@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="test_information_handler_class" translatable="false">com.android.launcher3.testing.DebugTestInformationHandler</string>
</resources>
@@ -1,258 +0,0 @@
/*
* Copyright (C) 2020 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.testing;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Binder;
import android.os.Bundle;
import android.system.Os;
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.icons.ClockDrawableWrapper;
import com.android.launcher3.testing.shared.TestProtocol;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import java.util.WeakHashMap;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
/**
* Class to handle requests from tests, including debug ones.
*/
public class DebugTestInformationHandler extends TestInformationHandler {
private static Collection<String> sEvents;
private static Application.ActivityLifecycleCallbacks sActivityLifecycleCallbacks;
private static final Map<Activity, Boolean> sActivities =
Collections.synchronizedMap(new WeakHashMap<>());
private static int sActivitiesCreatedCount = 0;
public DebugTestInformationHandler(Context context) {
init(context);
if (sActivityLifecycleCallbacks == null) {
sActivityLifecycleCallbacks = new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
sActivities.put(activity, true);
++sActivitiesCreatedCount;
}
@Override
public void onActivityStarted(Activity activity) {
}
@Override
public void onActivityResumed(Activity activity) {
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle bundle) {
}
@Override
public void onActivityDestroyed(Activity activity) {
}
};
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(sActivityLifecycleCallbacks);
}
}
private static void runGcAndFinalizersSync() {
Runtime.getRuntime().gc();
Runtime.getRuntime().runFinalization();
final CountDownLatch fence = new CountDownLatch(1);
createFinalizationObserver(fence);
try {
do {
Runtime.getRuntime().gc();
Runtime.getRuntime().runFinalization();
} while (!fence.await(100, TimeUnit.MILLISECONDS));
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
// Create the observer in the scope of a method to minimize the chance that
// it remains live in a DEX/machine register at the point of the fence guard.
// This must be kept to avoid R8 inlining it.
@Keep
private static void createFinalizationObserver(CountDownLatch fence) {
new Object() {
@Override
protected void finalize() throws Throwable {
try {
fence.countDown();
} finally {
super.finalize();
}
}
};
}
@Override
public Bundle call(String method, String arg, @Nullable Bundle extras) {
final Bundle response = new Bundle();
switch (method) {
case TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS: {
return getLauncherUIProperty(Bundle::putInt,
l -> l.getAppsView().getAppsStore().getDeferUpdatesFlags());
}
case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
TestProtocol.sDebugTracing = true;
ClockDrawableWrapper.sRunningInTest = true;
return response;
case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
TestProtocol.sDebugTracing = false;
ClockDrawableWrapper.sRunningInTest = false;
return response;
case TestProtocol.REQUEST_PID: {
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, Os.getpid());
return response;
}
case TestProtocol.REQUEST_FORCE_GC: {
runGcAndFinalizersSync();
return response;
}
case TestProtocol.REQUEST_START_EVENT_LOGGING: {
sEvents = new ArrayList<>();
TestLogging.setEventConsumer(
(sequence, event) -> {
final Collection<String> events = sEvents;
if (events != null) {
synchronized (events) {
events.add(sequence + '/' + event);
}
}
});
return response;
}
case TestProtocol.REQUEST_STOP_EVENT_LOGGING: {
TestLogging.setEventConsumer(null);
sEvents = null;
return response;
}
case TestProtocol.REQUEST_GET_TEST_EVENTS: {
if (sEvents == null) {
// sEvents can be null if Launcher died and restarted after
// REQUEST_START_EVENT_LOGGING.
return response;
}
synchronized (sEvents) {
response.putStringArrayList(
TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents));
}
return response;
}
case TestProtocol.REQUEST_REINITIALIZE_DATA: {
final long identity = Binder.clearCallingIdentity();
try {
MODEL_EXECUTOR.execute(() -> {
LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
model.getModelDbController().createEmptyDB();
MAIN_EXECUTOR.execute(model::forceReload);
});
return response;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
case TestProtocol.REQUEST_CLEAR_DATA: {
final long identity = Binder.clearCallingIdentity();
try {
MODEL_EXECUTOR.execute(() -> {
LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
model.getModelDbController().createEmptyDB();
model.getModelDbController().clearEmptyDbFlag();
MAIN_EXECUTOR.execute(model::forceReload);
});
return response;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
case TestProtocol.REQUEST_HOTSEAT_ICON_NAMES: {
return getLauncherUIProperty(Bundle::putStringArrayList, l -> {
ShortcutAndWidgetContainer hotseatIconsContainer =
l.getHotseat().getShortcutsAndWidgets();
ArrayList<String> hotseatIconNames = new ArrayList<>();
for (int i = 0; i < hotseatIconsContainer.getChildCount(); i++) {
// Use unchecked cast to catch changes in hotseat layout
BubbleTextView icon = (BubbleTextView) hotseatIconsContainer.getChildAt(i);
hotseatIconNames.add((String) icon.getText());
}
return hotseatIconNames;
});
}
case TestProtocol.REQUEST_GET_ACTIVITIES_CREATED_COUNT: {
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, sActivitiesCreatedCount);
return response;
}
case TestProtocol.REQUEST_GET_ACTIVITIES: {
response.putStringArray(TestProtocol.TEST_INFO_RESPONSE_FIELD,
sActivities.keySet().stream().map(
a -> a.getClass().getSimpleName() + " ("
+ (a.isDestroyed() ? "destroyed" : "current") + ")")
.toArray(String[]::new));
return response;
}
case TestProtocol.REQUEST_MODEL_QUEUE_CLEARED:
return getFromExecutorSync(MODEL_EXECUTOR, Bundle::new);
default:
return super.call(method, arg, extras);
}
}
}
+6 -138
View File
@@ -3,13 +3,13 @@
<issue
id="NewApi"
message="Call requires API level 29 (current min is 26): `android.content.res.Resources#getFloat`"
errorLine1=" return mContext.getResources().getFloat(resId);"
errorLine2=" ~~~~~~~~">
message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)"
errorLine1=' &lt;corners android:radius="@android:dimen/system_app_widget_background_radius" /&gt;'
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/util/DynamicResource.java"
line="73"
column="40"/>
file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
line="20"
column="14"/>
</issue>
<issue
@@ -34,136 +34,4 @@
column="18"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 28 (current min is 26): `android.app.Person#getKey`"
errorLine1=" return people.stream().filter(person -&gt; person.getKey() != null)"
errorLine2=" ~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
line="72"
column="56"/>
</issue>
<issue
id="NewApi"
message="Method reference requires API level 28 (current min is 26): `Person::getKey`"
errorLine1=" .map(Person::getKey).sorted().toArray(String[]::new);"
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/notification/NotificationKeyData.java"
line="73"
column="22"/>
</issue>
<issue
id="NewApi"
message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`"
errorLine1=" AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
line="1814"
column="17"/>
</issue>
<issue
id="NewApi"
message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`"
errorLine1=" : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
line="1815"
column="19"/>
</issue>
<issue
id="NewApi"
message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_RIGHT`"
errorLine1=" AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
line="1823"
column="17"/>
</issue>
<issue
id="NewApi"
message="Field requires API level 29 (current min is 26): `android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_PAGE_LEFT`"
errorLine1=" : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT);"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/PagedView.java"
line="1824"
column="19"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 26): `android.graphics.Outline#setPath`"
errorLine1=" outline.setPath(mPath);"
errorLine2=" ~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/popup/RoundedArrowDrawable.java"
line="114"
column="17"/>
</issue>
<issue
id="NewApi"
message="Field requires API level 28 (current min is 26): `android.appwidget.AppWidgetProviderInfo#widgetFeatures`"
errorLine1=" int featureFlags = mProviderInfo.widgetFeatures;"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/widget/WidgetAddFlowHandler.java"
line="93"
column="28"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 26): `android.view.View#getWindowInsetsController`"
errorLine1=" WindowInsetsController insetsController = getWindowInsetsController();"
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
line="820"
column="51"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 26): `android.view.WindowInsets.Type#ime`"
errorLine1=" insetsController.hide(WindowInsets.Type.ime());"
errorLine2=" ~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
line="822"
column="53"/>
</issue>
<issue
id="NewApi"
message="Call requires API level 30 (current min is 26): `android.view.WindowInsetsController#hide`"
errorLine1=" insetsController.hide(WindowInsets.Type.ime());"
errorLine2=" ~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/widget/picker/WidgetsFullSheet.java"
line="822"
column="30"/>
</issue>
<issue
id="NewApi"
message="Method reference requires API level 28 (current min is 26): `Person::getKey`"
errorLine1=" : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new);"
errorLine2=" ~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/src/com/android/launcher3/model/data/WorkspaceItemInfo.java"
line="194"
column="42"/>
</issue>
</issues>
-37
View File
@@ -1,37 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<issues format="6" by="lint 8.4.0-alpha01" type="baseline" client="" dependencies="true" name="" variant="all" version="8.4.0-alpha01">
<issue
id="NewApi"
message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
errorLine1=' android:topLeftRadius="?android:attr/dialogCornerRadius"'
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
line="6"
column="9"/>
</issue>
<issue
id="NewApi"
message="`?android:attr/dialogCornerRadius` requires API level 28 (current min is 26)"
errorLine1=' android:topRightRadius="?android:attr/dialogCornerRadius" /&gt;'
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/res/drawable/add_item_dialog_background.xml"
line="7"
column="9"/>
</issue>
<issue
id="NewApi"
message="`@android:dimen/system_app_widget_background_radius` requires API level 31 (current min is 26)"
errorLine1=' &lt;corners android:radius="@android:dimen/system_app_widget_background_radius" /&gt;'
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
<location
file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
line="20"
column="14"/>
</issue>
</issues>
@@ -1,51 +0,0 @@
/*
* Copyright (C) 2022 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.quickstep;
import android.content.Context;
import android.os.Bundle;
import androidx.annotation.Nullable;
import com.android.launcher3.testing.DebugTestInformationHandler;
import com.android.launcher3.testing.shared.TestProtocol;
/**
* Class to handle requests from tests, including debug ones, to Quickstep Launcher builds.
*/
public abstract class DebugQuickstepTestInformationHandler extends QuickstepTestInformationHandler {
private final DebugTestInformationHandler mDebugTestInformationHandler;
public DebugQuickstepTestInformationHandler(Context context) {
super(context);
mDebugTestInformationHandler = new DebugTestInformationHandler(context);
}
@Override
public Bundle call(String method, String arg, @Nullable Bundle extras) {
Bundle response = new Bundle();
if (TestProtocol.REQUEST_RECREATE_TASKBAR.equals(method)) {
// Allow null-pointer to catch illegal states.
runOnTISBinder(tisBinder -> tisBinder.getTaskbarManager().recreateTaskbar());
return response;
}
response = super.call(method, arg, extras);
if (response != null) return response;
return mDebugTestInformationHandler.call(method, arg, extras);
}
}
@@ -0,0 +1,21 @@
<?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.
-->
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="@android:color/white" />
<corners android:radius="@dimen/keyboard_quick_switch_task_view_radius" />
</shape>
@@ -18,6 +18,6 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:background="@drawable/keyboard_quick_switch_task_view_background"
android:background="@drawable/keyboard_quick_switch_thumbnail_background"
android:clipToOutline="true"
android:importantForAccessibility="no"/>
@@ -97,7 +97,11 @@ public final class KeyboardQuickSwitchController implements
private void openQuickSwitchView(int currentFocusedIndex) {
if (mQuickSwitchViewController != null) {
return;
if (!mQuickSwitchViewController.isCloseAnimationRunning()) {
return;
}
// Allow the KQS to be reopened during the close animation to make it more responsive
closeQuickSwitchView(false);
}
TaskbarOverlayContext overlayContext =
mControllers.taskbarOverlayController.requestWindow();
@@ -23,6 +23,7 @@ import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
import android.view.View;
@@ -174,21 +175,23 @@ public class KeyboardQuickSwitchTaskView extends ConstraintLayout {
return;
}
if (updateFunction == null) {
applyThumbnail(thumbnailView, task.thumbnail);
applyThumbnail(thumbnailView, task.colorBackground, task.thumbnail);
return;
}
updateFunction.updateThumbnailInBackground(
task, thumbnailData -> applyThumbnail(thumbnailView, thumbnailData));
updateFunction.updateThumbnailInBackground(task, thumbnailData ->
applyThumbnail(thumbnailView, task.colorBackground, thumbnailData));
}
private void applyThumbnail(
@NonNull ImageView thumbnailView,
ThumbnailData thumbnailData) {
@ColorInt int backgroundColor,
@Nullable ThumbnailData thumbnailData) {
Bitmap bm = thumbnailData == null ? null : thumbnailData.thumbnail;
if (thumbnailView.getVisibility() != VISIBLE) {
thumbnailView.setVisibility(VISIBLE);
}
thumbnailView.getBackground().setTint(bm == null ? backgroundColor : Color.TRANSPARENT);
thumbnailView.setImageDrawable(new BlurredBitmapDrawable(bm, THUMBNAIL_BLUR_RADIUS));
}
@@ -94,8 +94,12 @@ public class KeyboardQuickSwitchViewController {
mViewCallbacks);
}
boolean isCloseAnimationRunning() {
return mCloseAnimation != null;
}
protected void closeQuickSwitchView(boolean animate) {
if (mCloseAnimation != null) {
if (isCloseAnimationRunning()) {
// Let currently-running animation finish.
if (!animate) {
mCloseAnimation.end();
@@ -130,7 +134,7 @@ public class KeyboardQuickSwitchViewController {
}
private int launchTaskAt(int index) {
if (mCloseAnimation != null) {
if (isCloseAnimationRunning()) {
// Ignore taps on task views and alt key unpresses while the close animation is running.
return -1;
}
@@ -138,7 +142,7 @@ public class KeyboardQuickSwitchViewController {
// views have been added in the KeyboardQuickSwitchView.
GroupTask task = mControllerCallbacks.getTaskAt(index);
if (task == null) {
return Math.max(0, index);
return mOnDesktop ? 1 : Math.max(0, index);
}
if (mControllerCallbacks.isTaskRunning(task)) {
// Ignore attempts to run the selected task if it is already running.
@@ -186,7 +190,7 @@ public class KeyboardQuickSwitchViewController {
pw.println(prefix + "KeyboardQuickSwitchViewController:");
pw.println(prefix + "\thasFocus=" + mKeyboardQuickSwitchView.hasFocus());
pw.println(prefix + "\tcloseAnimationRunning=" + (mCloseAnimation != null));
pw.println(prefix + "\tisCloseAnimationRunning=" + isCloseAnimationRunning());
pw.println(prefix + "\tmCurrentFocusIndex=" + mCurrentFocusIndex);
}
@@ -37,14 +37,12 @@ import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
import static com.android.launcher3.taskbar.TaskbarDragLayerController.TASKBAR_REAPPEAR_DELAY_MS;
import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.ActivityOptions;
import android.content.ActivityNotFoundException;
@@ -82,7 +80,6 @@ import com.android.launcher3.DeviceProfile;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.config.FeatureFlags;
@@ -1432,23 +1429,6 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
});
}
public void hideTaskbarWhenFolding() {
AnimatedFloat alphaAnim = mControllers.taskbarDragLayerController.getTaskbarAlpha();
alphaAnim.cancelAnimation();
alphaAnim.updateValue(0);
ObjectAnimator animator = alphaAnim.animateToValue(1).setDuration(0);
animator.setStartDelay(TASKBAR_REAPPEAR_DELAY_MS);
animator.start();
}
public void cancelHideTaskbarWhenFolding() {
mControllers.taskbarDragLayerController.getTaskbarAlpha().cancelAnimation();
}
public void resetHideTaskbarWhenUnfolding() {
mControllers.taskbarDragLayerController.getTaskbarAlpha().updateValue(1);
}
protected boolean isUserSetupComplete() {
return mIsUserSetupComplete;
}
@@ -44,12 +44,6 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
private static final boolean DEBUG = SystemProperties.getBoolean(
"persist.debug.draw_taskbar_debug_ui", false);
// Delay to reset the task bar alpha back to 1 after fading it for transition from unfold to
// fold. Normally this is not needed since the new task bar is recreated after fading, but in
// case something goes wrong this provides a fallback mechanism to make sure the task bar is
// visible after the transition finishes.
public static final long TASKBAR_REAPPEAR_DELAY_MS = 2000;
private final TaskbarActivityContext mActivity;
private final TaskbarDragLayer mTaskbarDragLayer;
private final int mFolderMargin;
@@ -29,7 +29,6 @@ import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
import static com.android.quickstep.util.SystemActionConstants.ACTION_SHOW_TASKBAR;
@@ -43,7 +42,6 @@ import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.hardware.devicestate.DeviceStateManager;
import android.hardware.display.DisplayManager;
import android.net.Uri;
import android.os.Handler;
@@ -111,7 +109,6 @@ public class TaskbarManager {
private final Context mContext;
private final @Nullable Context mNavigationBarPanelContext;
private final DeviceStateManager mDeviceStateManager;
private WindowManager mWindowManager;
private FrameLayout mTaskbarRootLayout;
private boolean mAddedWindow;
@@ -180,8 +177,7 @@ public class TaskbarManager {
}
};
private final UnfoldTransitionProgressProvider.TransitionProgressListener
mUnfoldTransitionProgressListener =
UnfoldTransitionProgressProvider.TransitionProgressListener mUnfoldTransitionProgressListener =
new UnfoldTransitionProgressProvider.TransitionProgressListener() {
@Override
public void onTransitionStarted() {
@@ -210,9 +206,6 @@ public class TaskbarManager {
}
};
private final DeviceStateManager.FoldStateListener mFoldStateListener;
private Boolean mFolded;
@SuppressLint("WrongConstant")
public TaskbarManager(
TouchInteractionService service, AllAppsActionManager allAppsActionManager) {
@@ -240,29 +233,6 @@ public class TaskbarManager {
}
};
}
// Temporary solution to mitigate the visual jump from folding the device. Currently, the
// screen turns on much earlier than we receive the onConfigurationChanged callback or
// receiving the correct device profile. While the ideal the solution is to align turning
// the screen on after onConfigurationChanged (by either delaying turning on the screen or
// figuring out what is causing the delay in getting onConfigurationChanged callback), one
// easy temporary mitigation is to dimming the bar so that the visual jump isn't as glaring.
mFoldStateListener = new DeviceStateManager.FoldStateListener(mContext, folded -> {
boolean firstTime = mFolded == null;
if (mTaskbarActivityContext == null) {
return;
}
if (!firstTime && mFolded.booleanValue() != folded) {
mTaskbarActivityContext.cancelHideTaskbarWhenFolding();
}
mFolded = folded;
if (folded && !firstTime) {
mTaskbarActivityContext.hideTaskbarWhenFolding();
} else {
mTaskbarActivityContext.resetHideTaskbarWhenUnfolding();
}
});
mDeviceStateManager = mContext.getSystemService(DeviceStateManager.class);
mDeviceStateManager.registerCallback(MAIN_EXECUTOR, mFoldStateListener);
mNavButtonController = new TaskbarNavButtonController(service,
SystemUiProxy.INSTANCE.get(mContext), new Handler(),
AssistUtils.newInstance(mContext));
@@ -619,7 +589,6 @@ public class TaskbarManager {
Log.d(TASKBAR_NOT_DESTROYED_TAG, "unregistering component callbacks from destroy().");
mContext.unregisterComponentCallbacks(mComponentCallbacks);
mContext.unregisterReceiver(mShutdownReceiver);
mDeviceStateManager.unregisterCallback(mFoldStateListener);
}
public @Nullable TaskbarActivityContext getCurrentActivityContext() {
@@ -22,6 +22,7 @@ import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static com.android.launcher3.tapl.LauncherInstrumentation.WAIT_TIME_MS;
import static com.android.launcher3.tapl.TestHelpers.getHomeIntentInPackage;
import static com.android.launcher3.tapl.TestHelpers.getLauncherInMyProcess;
import static com.android.launcher3.testing.shared.TestProtocol.UPDATE_OVERVIEW_TARGETS_RUNNING_LATE;
import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_ACTIVITY_TIMEOUT;
import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_BROADCAST_TIMEOUT_SECS;
import static com.android.launcher3.ui.AbstractLauncherUiTest.DEFAULT_UI_TIMEOUT;
@@ -44,6 +45,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.RemoteException;
import android.util.Log;
import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;
@@ -59,6 +61,7 @@ import com.android.launcher3.tapl.TestHelpers;
import com.android.launcher3.testcomponent.TestCommandReceiver;
import com.android.launcher3.ui.AbstractLauncherUiTest;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ExtendedLongPressTimeoutRule;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.launcher3.util.rule.SamplerRule;
import com.android.launcher3.util.rule.ScreenRecordRule;
@@ -105,6 +108,9 @@ public class FallbackRecentsTest {
@Rule
public ScreenRecordRule mScreenRecordRule = new ScreenRecordRule();
@Rule
public ExtendedLongPressTimeoutRule mLongPressTimeoutRule = new ExtendedLongPressTimeoutRule();
public FallbackRecentsTest() throws RemoteException {
Instrumentation instrumentation = getInstrumentation();
Context context = instrumentation.getContext();
@@ -129,6 +135,13 @@ public class FallbackRecentsTest {
getLauncherCommand(mOtherLauncherActivity));
updateHandler.mChangeCounter
.await(DEFAULT_BROADCAST_TIMEOUT_SECS, TimeUnit.SECONDS);
Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
"AFTER AWAIT: mObserver home intent package name="
+ updateHandler.mObserver.getHomeIntent()
.getComponent().getPackageName());
Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
"AFTER AWAIT: mOtherLauncherActivity package name="
+ mOtherLauncherActivity.packageName);
try {
base.evaluate();
} finally {
@@ -340,12 +353,25 @@ public class FallbackRecentsTest {
mRads = new RecentsAnimationDeviceState(ctx);
mObserver = new OverviewComponentObserver(ctx, mRads);
mChangeCounter = new CountDownLatch(1);
Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
"OverviewUpdateHandler(Constructor): mObserver home intent package name="
+ mObserver.getHomeIntent().getComponent().getPackageName());
Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
"OverviewUpdateHandler(Constructor): mOtherLauncherActivity package name="
+ mOtherLauncherActivity.packageName);
if (mObserver.getHomeIntent().getComponent()
.getPackageName().equals(mOtherLauncherActivity.packageName)) {
// Home already same
mChangeCounter.countDown();
} else {
mObserver.setOverviewChangeListener(b -> mChangeCounter.countDown());
mObserver.setOverviewChangeListener(b -> {
Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
"OverviewChangeListener(Callback): isHomeAndOverviewSame=" + b);
Log.d(UPDATE_OVERVIEW_TARGETS_RUNNING_LATE,
"OverviewChangeListener(Callback): mObserver home intent package name="
+ mObserver.getHomeIntent().getComponent().getPackageName());
mChangeCounter.countDown();
});
}
}
@@ -23,39 +23,56 @@ import static com.android.launcher3.config.FeatureFlags.enableAppPairs;
import static com.android.launcher3.config.FeatureFlags.enableSplitContextually;
import static com.android.launcher3.testing.shared.TestProtocol.TEST_INFO_RESPONSE_FIELD;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.Binder;
import android.os.Bundle;
import android.system.Os;
import android.view.WindowInsets;
import androidx.annotation.Keep;
import androidx.annotation.Nullable;
import androidx.core.view.WindowInsetsCompat;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.CellLayout;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Hotseat;
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherModel;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Workspace;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.icons.ClockDrawableWrapper;
import com.android.launcher3.testing.shared.HotseatCellCenterRequest;
import com.android.launcher3.testing.shared.TestProtocol;
import com.android.launcher3.testing.shared.WorkspaceCellCenterRequest;
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.ResourceBasedOverride;
import com.android.launcher3.widget.picker.WidgetsFullSheet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -69,6 +86,12 @@ public class TestInformationHandler implements ResourceBasedOverride {
context, R.string.test_information_handler_class);
}
private static Collection<String> sEvents;
private static Application.ActivityLifecycleCallbacks sActivityLifecycleCallbacks;
private static final Set<Activity> sActivities =
Collections.synchronizedSet(Collections.newSetFromMap(new WeakHashMap<>()));
private static int sActivitiesCreatedCount = 0;
protected Context mContext;
protected DeviceProfile mDeviceProfile;
protected LauncherAppState mLauncherAppState;
@@ -78,6 +101,17 @@ public class TestInformationHandler implements ResourceBasedOverride {
mDeviceProfile = InvariantDeviceProfile.INSTANCE.
get(context).getDeviceProfile(context);
mLauncherAppState = LauncherAppState.getInstanceNoCreate();
if (sActivityLifecycleCallbacks == null) {
sActivityLifecycleCallbacks = new ActivityLifecycleCallbacksAdapter() {
@Override
public void onActivityCreated(Activity activity, Bundle bundle) {
sActivities.add(activity);
++sActivitiesCreatedCount;
}
};
((Application) context.getApplicationContext())
.registerActivityLifecycleCallbacks(sActivityLifecycleCallbacks);
}
}
/**
@@ -309,6 +343,127 @@ public class TestInformationHandler implements ResourceBasedOverride {
return response;
}
case TestProtocol.REQUEST_APP_LIST_FREEZE_FLAGS: {
return getLauncherUIProperty(Bundle::putInt,
l -> l.getAppsView().getAppsStore().getDeferUpdatesFlags());
}
case TestProtocol.REQUEST_ENABLE_DEBUG_TRACING:
TestProtocol.sDebugTracing = true;
ClockDrawableWrapper.sRunningInTest = true;
return response;
case TestProtocol.REQUEST_DISABLE_DEBUG_TRACING:
TestProtocol.sDebugTracing = false;
ClockDrawableWrapper.sRunningInTest = false;
return response;
case TestProtocol.REQUEST_PID: {
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, Os.getpid());
return response;
}
case TestProtocol.REQUEST_FORCE_GC: {
runGcAndFinalizersSync();
return response;
}
case TestProtocol.REQUEST_START_EVENT_LOGGING: {
sEvents = new ArrayList<>();
TestLogging.setEventConsumer(
(sequence, event) -> {
final Collection<String> events = sEvents;
if (events != null) {
synchronized (events) {
events.add(sequence + '/' + event);
}
}
});
return response;
}
case TestProtocol.REQUEST_STOP_EVENT_LOGGING: {
TestLogging.setEventConsumer(null);
sEvents = null;
return response;
}
case TestProtocol.REQUEST_GET_TEST_EVENTS: {
if (sEvents == null) {
// sEvents can be null if Launcher died and restarted after
// REQUEST_START_EVENT_LOGGING.
return response;
}
synchronized (sEvents) {
response.putStringArrayList(
TestProtocol.TEST_INFO_RESPONSE_FIELD, new ArrayList<>(sEvents));
}
return response;
}
case TestProtocol.REQUEST_REINITIALIZE_DATA: {
final long identity = Binder.clearCallingIdentity();
try {
MODEL_EXECUTOR.execute(() -> {
LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
model.getModelDbController().createEmptyDB();
MAIN_EXECUTOR.execute(model::forceReload);
});
return response;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
case TestProtocol.REQUEST_CLEAR_DATA: {
final long identity = Binder.clearCallingIdentity();
try {
MODEL_EXECUTOR.execute(() -> {
LauncherModel model = LauncherAppState.getInstance(mContext).getModel();
model.getModelDbController().createEmptyDB();
model.getModelDbController().clearEmptyDbFlag();
MAIN_EXECUTOR.execute(model::forceReload);
});
return response;
} finally {
Binder.restoreCallingIdentity(identity);
}
}
case TestProtocol.REQUEST_HOTSEAT_ICON_NAMES: {
return getLauncherUIProperty(Bundle::putStringArrayList, l -> {
ShortcutAndWidgetContainer hotseatIconsContainer =
l.getHotseat().getShortcutsAndWidgets();
ArrayList<String> hotseatIconNames = new ArrayList<>();
for (int i = 0; i < hotseatIconsContainer.getChildCount(); i++) {
// Use unchecked cast to catch changes in hotseat layout
BubbleTextView icon = (BubbleTextView) hotseatIconsContainer.getChildAt(i);
hotseatIconNames.add((String) icon.getText());
}
return hotseatIconNames;
});
}
case TestProtocol.REQUEST_GET_ACTIVITIES_CREATED_COUNT: {
response.putInt(TestProtocol.TEST_INFO_RESPONSE_FIELD, sActivitiesCreatedCount);
return response;
}
case TestProtocol.REQUEST_GET_ACTIVITIES: {
response.putStringArray(TestProtocol.TEST_INFO_RESPONSE_FIELD,
sActivities.stream().map(
a -> a.getClass().getSimpleName() + " ("
+ (a.isDestroyed() ? "destroyed" : "current") + ")")
.toArray(String[]::new));
return response;
}
case TestProtocol.REQUEST_MODEL_QUEUE_CLEARED:
return getFromExecutorSync(MODEL_EXECUTOR, Bundle::new);
default:
return null;
}
@@ -387,4 +542,38 @@ public class TestInformationHandler implements ResourceBasedOverride {
*/
void set(Bundle b, String key, T value);
}
private static void runGcAndFinalizersSync() {
Runtime.getRuntime().gc();
Runtime.getRuntime().runFinalization();
final CountDownLatch fence = new CountDownLatch(1);
createFinalizationObserver(fence);
try {
do {
Runtime.getRuntime().gc();
Runtime.getRuntime().runFinalization();
} while (!fence.await(100, TimeUnit.MILLISECONDS));
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
}
// Create the observer in the scope of a method to minimize the chance that
// it remains live in a DEX/machine register at the point of the fence guard.
// This must be kept to avoid R8 inlining it.
@Keep
private static void createFinalizationObserver(CountDownLatch fence) {
new Object() {
@Override
protected void finalize() throws Throwable {
try {
fence.countDown();
} finally {
super.finalize();
}
}
};
}
}
@@ -180,6 +180,7 @@ public final class TestProtocol {
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 UPDATE_OVERVIEW_TARGETS_RUNNING_LATE = "b/321775748";
public static final String REQUEST_EMULATE_DISPLAY = "emulate-display";
public static final String REQUEST_STOP_EMULATE_DISPLAY = "stop-emulate-display";
@@ -66,6 +66,7 @@ import com.android.launcher3.util.LooperExecutor;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.launcher3.util.TestUtil;
import com.android.launcher3.util.Wait;
import com.android.launcher3.util.rule.ExtendedLongPressTimeoutRule;
import com.android.launcher3.util.rule.FailureWatcher;
import com.android.launcher3.util.rule.SamplerRule;
import com.android.launcher3.util.rule.ScreenRecordRule;
@@ -219,6 +220,9 @@ public abstract class AbstractLauncherUiTest {
@Rule
public SetFlagsRule mSetFlagsRule = new SetFlagsRule(DEVICE_DEFAULT);
@Rule
public ExtendedLongPressTimeoutRule mLongPressTimeoutRule = new ExtendedLongPressTimeoutRule();
public static void initialize(AbstractLauncherUiTest test) throws Exception {
test.reinitializeLauncherData();
test.mDevice.pressHome();
@@ -0,0 +1,74 @@
/*
* 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.launcher3.util.rule;
import android.content.ContentResolver;
import android.provider.Settings;
import android.util.Log;
import android.view.ViewConfiguration;
import androidx.test.InstrumentationRegistry;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
public class ExtendedLongPressTimeoutRule implements TestRule {
private static final String TAG = "ExtendedLongPressTimeoutRule";
private static final float LONG_PRESS_TIMEOUT_MULTIPLIER = 10f;
@Override
public Statement apply(Statement base, Description description) {
return new Statement() {
@Override
public void evaluate() throws Throwable {
ContentResolver contentResolver = InstrumentationRegistry.getInstrumentation()
.getContext()
.getContentResolver();
int prevLongPressTimeout = Settings.Secure.getInt(
contentResolver,
Settings.Secure.LONG_PRESS_TIMEOUT,
ViewConfiguration.getLongPressTimeout());
int newLongPressTimeout =
(int) (prevLongPressTimeout * LONG_PRESS_TIMEOUT_MULTIPLIER);
try {
Log.d(TAG, "In try-block: Setting long press timeout from "
+ prevLongPressTimeout + "ms to " + newLongPressTimeout + "ms");
Settings.Secure.putInt(
contentResolver,
Settings.Secure.LONG_PRESS_TIMEOUT,
(int) (prevLongPressTimeout * LONG_PRESS_TIMEOUT_MULTIPLIER));
base.evaluate();
} catch (Exception e) {
Log.e(TAG, "Error", e);
throw e;
} finally {
Log.d(TAG, "In finally-block: resetting long press timeout to "
+ prevLongPressTimeout + "ms");
Settings.Secure.putInt(
contentResolver,
Settings.Secure.LONG_PRESS_TIMEOUT,
prevLongPressTimeout);
}
}
};
}
}
@@ -1919,17 +1919,21 @@ public final class LauncherInstrumentation {
}
private static MotionEvent getMotionEvent(long downTime, long eventTime, int action,
float x, float y, int source) {
float x, float y, int source, int toolType) {
return MotionEvent.obtain(downTime, eventTime, action, 1,
new MotionEvent.PointerProperties[]{getPointerProperties(0)},
new MotionEvent.PointerProperties[]{getPointerProperties(0, toolType)},
new MotionEvent.PointerCoords[]{getPointerCoords(x, y)},
0, 0, 1.0f, 1.0f, 0, 0, source, 0);
}
private static MotionEvent.PointerProperties getPointerProperties(int pointerId) {
return getPointerProperties(pointerId, Configurator.getInstance().getToolType());
}
private static MotionEvent.PointerProperties getPointerProperties(int pointerId, int toolType) {
MotionEvent.PointerProperties properties = new MotionEvent.PointerProperties();
properties.id = pointerId;
properties.toolType = Configurator.getInstance().getToolType();
properties.toolType = toolType;
return properties;
}
@@ -1975,6 +1979,19 @@ public final class LauncherInstrumentation {
public void sendPointer(long downTime, long currentTime, int action, Point point,
GestureScope gestureScope, int source, boolean isRightClick) {
sendPointer(
downTime,
currentTime,
action,
point,
gestureScope,
source,
isRightClick,
Configurator.getInstance().getToolType());
}
public void sendPointer(long downTime, long currentTime, int action, Point point,
GestureScope gestureScope, int source, boolean isRightClick, int toolType) {
final boolean hasTIS = hasTIS();
int pointerCount = mPointerCount;
@@ -2009,13 +2026,13 @@ public final class LauncherInstrumentation {
? getTrackpadMotionEvent(
downTime, currentTime, action, point.x, point.y, pointerCount,
mTrackpadGestureType)
: getMotionEvent(downTime, currentTime, action, point.x, point.y, source);
: getMotionEvent(downTime, currentTime, action, point.x, point.y, source, toolType);
if (action == MotionEvent.ACTION_BUTTON_PRESS
|| action == MotionEvent.ACTION_BUTTON_RELEASE) {
event.setActionButton(MotionEvent.BUTTON_PRIMARY);
}
if (isRightClick) {
event.setButtonState(event.getButtonState() & MotionEvent.BUTTON_SECONDARY);
event.setButtonState(event.getButtonState() | MotionEvent.BUTTON_SECONDARY);
}
injectEvent(event);
}
@@ -2114,15 +2131,19 @@ public final class LauncherInstrumentation {
@NonNull final UiObject2 target, @NonNull String resName, Pattern longClickEvent) {
final Point targetCenter = target.getVisibleCenter();
final long downTime = SystemClock.uptimeMillis();
// Use stylus secondary button press to prevent using the exteded long press timeout rule
// unnecessarily
sendPointer(downTime, downTime, MotionEvent.ACTION_DOWN, targetCenter,
GestureScope.DONT_EXPECT_PILFER);
GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_TOUCHSCREEN,
/* isRightClick= */ true, MotionEvent.TOOL_TYPE_STYLUS);
try {
expectEvent(TestProtocol.SEQUENCE_MAIN, longClickEvent);
final UiObject2 result = waitForLauncherObject(resName);
return result;
} finally {
sendPointer(downTime, SystemClock.uptimeMillis(), MotionEvent.ACTION_UP, targetCenter,
GestureScope.DONT_EXPECT_PILFER);
GestureScope.DONT_EXPECT_PILFER, InputDevice.SOURCE_TOUCHSCREEN,
/* isRightClick= */ true, MotionEvent.TOOL_TYPE_STYLUS);
}
}