diff --git a/Android.bp b/Android.bp
index cdada0a87f..f45394a998 100644
--- a/Android.bp
+++ b/Android.bp
@@ -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
diff --git a/ext_tests/res/values/overrides.xml b/ext_tests/res/values/overrides.xml
deleted file mode 100644
index 3f071d4219..0000000000
--- a/ext_tests/res/values/overrides.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-
-
- com.android.launcher3.testing.DebugTestInformationHandler
-
-
diff --git a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java b/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
deleted file mode 100644
index 6e7a82ae5c..0000000000
--- a/ext_tests/src/com/android/launcher3/testing/DebugTestInformationHandler.java
+++ /dev/null
@@ -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 sEvents;
- private static Application.ActivityLifecycleCallbacks sActivityLifecycleCallbacks;
- private static final Map 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 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 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);
- }
- }
-}
diff --git a/lint-baseline.xml b/lint-baseline.xml
index fe005cadf0..2ee9531298 100644
--- a/lint-baseline.xml
+++ b/lint-baseline.xml
@@ -3,13 +3,13 @@
+ 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=" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~">
+ file="packages/apps/Launcher3/res/drawable/widget_resize_frame.xml"
+ line="20"
+ column="14"/>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/lint-baseline2.xml b/lint-baseline2.xml
deleted file mode 100644
index 84f1b15d54..0000000000
--- a/lint-baseline2.xml
+++ /dev/null
@@ -1,37 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java b/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java
deleted file mode 100644
index 0b17a7b7d7..0000000000
--- a/quickstep/ext_tests/src/com/android/quickstep/DebugQuickstepTestInformationHandler.java
+++ /dev/null
@@ -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);
- }
-}
-
diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java
index 12cdd67515..d5c9b9fa89 100644
--- a/src/com/android/launcher3/testing/TestInformationHandler.java
+++ b/src/com/android/launcher3/testing/TestInformationHandler.java
@@ -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 sEvents;
+ private static Application.ActivityLifecycleCallbacks sActivityLifecycleCallbacks;
+ private static final Set 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 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 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();
+ }
+ }
+ };
+ }
}