Removing ext_test directory
Except for a few methods, most of the testing code was already in the main codebase. Maintaining the additional source directory adds unnecessary overhead Bug: 330920490 Test: Presubmit Flag: None Change-Id: I56c43ab7a4869b26858d622d0b8b14f286d50e90
This commit is contained in:
1 parent
dc6ec50558
commit
9d2ece156d
7 files changed
+199
-512
No files matched your search
+4
-23
@@ -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
|
||||
|
||||
@@ -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
@@ -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=' <corners android:radius="@android:dimen/system_app_widget_background_radius" />'
|
||||
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 -> 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>
|
||||
@@ -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" />'
|
||||
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=' <corners android:radius="@android:dimen/system_app_widget_background_radius" />'
|
||||
errorLine2=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
|
||||
<location
|
||||
file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
|
||||
line="20"
|
||||
column="14"/>
|
||||
</issue>
|
||||
|
||||
</issues>
|
||||
-51
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user