From 80a4f8c139450352a37f1ce4359f656092d0a31a Mon Sep 17 00:00:00 2001 From: Bill Yi Date: Fri, 26 Jul 2019 11:34:59 -0700 Subject: [PATCH 01/31] Import translations. DO NOT MERGE Auto-generated-cl: translation import Bug: 64712476 Change-Id: Iefb999eacda55d43ebbdadc02c7eafc89e84a9be --- SecondaryDisplayLauncher/res/values-zh-rTW/strings.xml | 2 +- res/values-hi/strings.xml | 2 +- res/values-ta/strings.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/SecondaryDisplayLauncher/res/values-zh-rTW/strings.xml b/SecondaryDisplayLauncher/res/values-zh-rTW/strings.xml index bf76f29dec..c02fe2cdce 100644 --- a/SecondaryDisplayLauncher/res/values-zh-rTW/strings.xml +++ b/SecondaryDisplayLauncher/res/values-zh-rTW/strings.xml @@ -21,5 +21,5 @@ xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> "無法啟動活動" "新增應用程式捷徑" - "設定桌布" + "套用桌布" diff --git a/res/values-hi/strings.xml b/res/values-hi/strings.xml index b796140e5e..3b0432ee4a 100644 --- a/res/values-hi/strings.xml +++ b/res/values-hi/strings.xml @@ -88,7 +88,7 @@ "नई सूचनाएं बताने वाला गोल निशान" "चालू" "चालू" - "सूचना के एक्सेस की ज़रूरत है" + "सूचना के ऐक्सेस की ज़रूरत है" "सूचना बिंदु दिखाने के लिए, %1$s के ऐप्लिकेशन सूचना चालू करें" "सेटिंग बदलें" "नई सूचनाएं बताने वाला गोल निशान दिखाएं" diff --git a/res/values-ta/strings.xml b/res/values-ta/strings.xml index 672665e430..c926bc185b 100644 --- a/res/values-ta/strings.xml +++ b/res/values-ta/strings.xml @@ -89,7 +89,7 @@ "ஆன்" "ஆஃப்" "அறிவிப்பிற்கான அணுகல் தேவை" - "அறிவிப்புப் புள்ளிகளைக் காட்ட, %1$s இன் பயன்பாட்டு அறிவிப்புகளை இயக்கவும்" + "அறிவிப்புப் புள்ளிகளைக் காட்ட, %1$s இன் ஆப்ஸ் அறிவிப்புகளை இயக்கவும்" "அமைப்புகளை மாற்று" "அறிவிப்புப் புள்ளிகளைக் காட்டு" "முகப்புத் திரையில் ஐகானைச் சேர்" From 003c94f10fc04cfb447d71abe51f4ca088a2d156 Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 25 Jul 2019 12:01:45 -0700 Subject: [PATCH 02/31] Moving enabling rotation for test We needed to press home to wait until the launcher starts, now we simply enable rotation once the Launcher gets created. Change-Id: Ie99e5073c06f8da181262d32823116061c81d6f7 --- .../util/rule/LauncherActivityRule.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java index 204240324e..62fe26d13b 100644 --- a/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java +++ b/tests/src/com/android/launcher3/util/rule/LauncherActivityRule.java @@ -19,6 +19,7 @@ import android.app.Activity; import android.app.Application; import android.app.Application.ActivityLifecycleCallbacks; import android.os.Bundle; + import androidx.test.InstrumentationRegistry; import com.android.launcher3.Launcher; @@ -84,19 +85,27 @@ public class LauncherActivityRule implements TestRule { } @Override - public void onActivityStarted(Activity activity) { } + public void onActivityStarted(Activity activity) { + if (activity instanceof Launcher) { + mActivity.getRotationHelper().forceAllowRotationForTesting(true); + } + } @Override - public void onActivityResumed(Activity activity) { } + public void onActivityResumed(Activity activity) { + } @Override - public void onActivityPaused(Activity activity) { } + public void onActivityPaused(Activity activity) { + } @Override - public void onActivityStopped(Activity activity) { } + public void onActivityStopped(Activity activity) { + } @Override - public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { } + public void onActivitySaveInstanceState(Activity activity, Bundle bundle) { + } @Override public void onActivityDestroyed(Activity activity) { From 647d5014d8a7d5a37356165fe953b18c7b2384db Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 30 Jul 2019 10:36:31 -0700 Subject: [PATCH 03/31] Unconditionally logging RemoteActionShortcut events To help investigating DWB performance issues. Bug: 138273985 Change-Id: I15d7b220ac47f514c223ba6876549a0b0e9ca95b --- src/com/android/launcher3/popup/RemoteActionShortcut.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java index 41ab4df7bf..5a5fbabacf 100644 --- a/src/com/android/launcher3/popup/RemoteActionShortcut.java +++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java @@ -29,11 +29,12 @@ import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.ItemInfo; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.userevent.nano.LauncherLogProto; public class RemoteActionShortcut extends SystemShortcut { private static final String TAG = "RemoteActionShortcut"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = Utilities.IS_DEBUG_DEVICE; private final RemoteAction mAction; From 7d2795e185bc15e2451cee44df6e6ca96526b305 Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 30 Jul 2019 12:33:20 -0700 Subject: [PATCH 04/31] Not throwing NPE when can't resolve test provider Change-Id: I22fa6dc5de94ffa02e0121b4f929adffcb9c1ce9 --- .../tapl/com/android/launcher3/tapl/LauncherInstrumentation.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index fe7401ca62..1371b21193 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -178,6 +178,7 @@ public final class LauncherInstrumentation { PackageManager pm = getContext().getPackageManager(); ProviderInfo pi = pm.resolveContentProvider( testProviderAuthority, MATCH_ALL | MATCH_DISABLED_COMPONENTS); + assertNotNull("Cannot find content provider for " + testProviderAuthority, pi); ComponentName cn = new ComponentName(pi.packageName, pi.name); if (pm.getComponentEnabledSetting(cn) != COMPONENT_ENABLED_STATE_ENABLED) { From 4d1a0e2a7b859672a6aac52e9fd909d42a12b895 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Thu, 25 Jul 2019 20:26:54 -0700 Subject: [PATCH 05/31] show dot on shortcut when incoming notification contains exactly the same shortcut id Bug: 132336512 Change-Id: Iddf4cfe8ad60c12e8de8b171bed392f1bb0a6761 Merged-In: Iddf4cfe8ad60c12e8de8b171bed392f1bb0a6761 --- .../shortcuts/DeepShortcutManager.java | 6 +++ .../launcher3/popup/PopupDataProvider.java | 11 +++-- .../shortcuts/DeepShortcutManager.java | 45 +++++++++++++++++-- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java index 1e449108d8..73adaa14fa 100644 --- a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java +++ b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java @@ -25,6 +25,7 @@ import android.os.Bundle; import android.os.UserHandle; import com.android.launcher3.ItemInfo; +import com.android.launcher3.notification.NotificationKeyData; import java.util.Collections; import java.util.List; @@ -52,6 +53,11 @@ public class DeepShortcutManager { return false; } + public static boolean supportsNotificationDots( + ItemInfo info, List notifications) { + return false; + } + public boolean wasLastCallSuccess() { return false; } diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java index 2d301ac008..dd496b02bf 100644 --- a/src/com/android/launcher3/popup/PopupDataProvider.java +++ b/src/com/android/launcher3/popup/PopupDataProvider.java @@ -40,6 +40,7 @@ import java.util.Map; import java.util.function.Predicate; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * Provides data for the popup menu that appears after long-clicking on apps. @@ -167,12 +168,14 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan return count == null ? 0 : count; } - public DotInfo getDotInfoForItem(ItemInfo info) { - if (!DeepShortcutManager.supportsShortcuts(info)) { + public @Nullable DotInfo getDotInfoForItem(@NonNull ItemInfo info) { + DotInfo dotInfo = mPackageUserToDotInfos.get(PackageUserKey.fromItemInfo(info)); + List notifications = + dotInfo == null ? Collections.EMPTY_LIST : dotInfo.getNotificationKeys(); + if (!DeepShortcutManager.supportsNotificationDots(info, notifications)) { return null; } - - return mPackageUserToDotInfos.get(PackageUserKey.fromItemInfo(info)); + return dotInfo; } public @NonNull List getNotificationKeysForItem(ItemInfo info) { diff --git a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java index 6b6f70d7b6..f42bafe5e4 100644 --- a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java +++ b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java @@ -30,6 +30,7 @@ import android.util.Log; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherSettings; import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.notification.NotificationKeyData; import java.util.ArrayList; import java.util.Collections; @@ -64,10 +65,40 @@ public class DeepShortcutManager { } public static boolean supportsShortcuts(ItemInfo info) { - boolean isItemPromise = info instanceof WorkspaceItemInfo - && ((WorkspaceItemInfo) info).hasPromiseIconUi(); - return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION - && !info.isDisabled() && !isItemPromise; + return isActive(info) && isApp(info); + } + + public static boolean supportsNotificationDots( + ItemInfo info, List notifications) { + if (!isActive(info)) { + return false; + } + return isApp(info) || (isPinnedShortcut(info) + && shouldShowNotificationDotForPinnedShortcut(info, notifications)); + } + + private static boolean isApp(ItemInfo info) { + return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; + } + + private static boolean isPinnedShortcut(ItemInfo info) { + return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT + && info.container != ItemInfo.NO_ID + && info instanceof WorkspaceItemInfo; + } + + private static boolean shouldShowNotificationDotForPinnedShortcut( + ItemInfo info, List notifications) { + String shortcutId = ((WorkspaceItemInfo) info).getDeepShortcutId(); + if (shortcutId == null) { + return false; + } + for (NotificationKeyData notification : notifications) { + if (shortcutId.equals(notification.shortcutId)) { + return true; + } + } + return false; } public boolean wasLastCallSuccess() { @@ -183,6 +214,12 @@ public class DeepShortcutManager { return shortcutIds; } + private static boolean isActive(ItemInfo info) { + boolean isLoading = info instanceof WorkspaceItemInfo + && ((WorkspaceItemInfo) info).hasPromiseIconUi(); + return !isLoading && !info.isDisabled(); + } + /** * Query the system server for all the shortcuts matching the given parameters. * If packageName == null, we query for all shortcuts with the passed flags, regardless of app. From a8726dc93bdb1fc38090ba8b15c5651e08e2103b Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 31 Jul 2019 10:45:57 -0700 Subject: [PATCH 06/31] Tests: Use FLAG_ACTIVITY_CLEAR_TASK Change-Id: I58053db6f942737976afcaed26e449a1f9b98f6f --- .../launcher3/ui/AbstractLauncherUiTest.java | 32 +++++++++---------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java index 8dc8cea40d..fc19baace2 100644 --- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java +++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java @@ -38,6 +38,7 @@ import android.util.Log; import androidx.test.InstrumentationRegistry; import androidx.test.uiautomator.By; +import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.UiDevice; import androidx.test.uiautomator.Until; @@ -330,30 +331,27 @@ public abstract class AbstractLauncherUiTest { } protected void startAppFast(String packageName) { - final Instrumentation instrumentation = getInstrumentation(); - final Intent intent = instrumentation.getContext().getPackageManager(). - getLaunchIntentForPackage(packageName); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - instrumentation.getTargetContext().startActivity(intent); - assertTrue(packageName + " didn't start", - mDevice.wait(Until.hasObject(By.pkg(packageName).depth(0)), DEFAULT_UI_TIMEOUT)); + startIntent( + getInstrumentation().getContext().getPackageManager().getLaunchIntentForPackage( + packageName), + By.pkg(packageName).depth(0)); } protected void startTestActivity(int activityNumber) { final String packageName = getAppPackageName(); - final Instrumentation instrumentation = getInstrumentation(); - final Intent intent = instrumentation.getContext().getPackageManager(). + final Intent intent = getInstrumentation().getContext().getPackageManager(). getLaunchIntentForPackage(packageName); - intent.addCategory(Intent.CATEGORY_LAUNCHER); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setComponent(new ComponentName(packageName, "com.android.launcher3.tests.Activity" + activityNumber)); - instrumentation.getTargetContext().startActivity(intent); - assertTrue(packageName + " didn't start", - mDevice.wait( - Until.hasObject(By.pkg(packageName).text("TestActivity" + activityNumber)), - DEFAULT_UI_TIMEOUT)); + startIntent(intent, By.pkg(packageName).text("TestActivity" + activityNumber)); + } + + private void startIntent(Intent intent, BySelector selector) { + intent.addCategory(Intent.CATEGORY_LAUNCHER); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + getInstrumentation().getTargetContext().startActivity(intent); + assertTrue("App didn't start: " + selector, + mDevice.wait(Until.hasObject(selector), DEFAULT_UI_TIMEOUT)); } public static String resolveSystemApp(String category) { From 8a35c5cf94a2243c2f577f60e6124afd6108b7fb Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 31 Jul 2019 11:37:00 -0700 Subject: [PATCH 07/31] Improving system health diags Change-Id: Id3de46c48421051bc5680e05bcf77492aa793000 --- tests/tapl/com/android/launcher3/tapl/TestHelpers.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java index 399c59d36d..a089a527ef 100644 --- a/tests/tapl/com/android/launcher3/tapl/TestHelpers.java +++ b/tests/tapl/com/android/launcher3/tapl/TestHelpers.java @@ -109,7 +109,7 @@ public class TestHelpers { DropBoxManager.Entry entry; StringBuilder errorDetails = new StringBuilder(); while (null != (entry = dropbox.getNextEntry(label, timestamp))) { - if (errorDetails.length() != 0) errorDetails.append("------------------------------"); + errorDetails.append("------------------------------\n"); timestamp = entry.getTimeMillis(); errorDetails.append(new Date(timestamp)); errorDetails.append(": "); From 45c12ff1b5d7ffcd7cf7ce21cc05fb93df9df140 Mon Sep 17 00:00:00 2001 From: Vinit Nayak Date: Tue, 30 Jul 2019 15:33:12 -0700 Subject: [PATCH 08/31] Set recents view to be visible from alt+tab Recents was being initialized but was not marked as attached to app window. This was causing it's animator to never make it View.VISIBLE. Test: Open any app On physical keyboard press alt+tab Observe that overview shows up fixes: 138396234 Change-Id: I9e6c001242f4552027e79b162fb812f476823a37 --- .../com/android/quickstep/AppToOverviewAnimationProvider.java | 1 + .../src/com/android/quickstep/OverviewCommandHelper.java | 1 + 2 files changed, 2 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java index 5e77e0adee..5ebefa337f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/AppToOverviewAnimationProvider.java @@ -81,6 +81,7 @@ final class AppToOverviewAnimationProvider imple }); factory.onRemoteAnimationReceived(null); factory.createActivityController(RECENTS_LAUNCH_DURATION); + factory.setRecentsAttachedToAppWindow(true, false); mActivity = activity; mRecentsView = mActivity.getOverviewPanel(); return false; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java index 6533c63efa..a94f25d2b2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/OverviewCommandHelper.java @@ -99,6 +99,7 @@ public class OverviewCommandHelper { @Override protected void onTransitionComplete() { + // TODO(b/138729100) This doesn't execute first time launcher is run if (mTriggeredFromAltTab) { RecentsView rv = (RecentsView) mHelper.getVisibleRecentsView(); if (rv == null) { From 49a28a725afa366a1a0ef5a81846cdfced4be0f7 Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 31 Jul 2019 13:45:00 -0700 Subject: [PATCH 09/31] Improving getWorkspaceAppIcon() Change-Id: I71093b6c03b96ef608be9c8b847a372834b79d64 --- .../tapl/com/android/launcher3/tapl/AllApps.java | 2 +- .../com/android/launcher3/tapl/BaseOverview.java | 2 +- .../launcher3/tapl/LauncherInstrumentation.java | 7 ------- .../com/android/launcher3/tapl/Workspace.java | 15 +++++++++------ 4 files changed, 11 insertions(+), 15 deletions(-) diff --git a/tests/tapl/com/android/launcher3/tapl/AllApps.java b/tests/tapl/com/android/launcher3/tapl/AllApps.java index 9ff354a7eb..f070280ea2 100644 --- a/tests/tapl/com/android/launcher3/tapl/AllApps.java +++ b/tests/tapl/com/android/launcher3/tapl/AllApps.java @@ -120,7 +120,7 @@ public class AllApps extends LauncherInstrumentation.VisibleContainer { mLauncher.assertTrue("Unable to scroll to a clickable icon: " + appName, hasClickableIcon(allAppsContainer, appListRecycler, appIconSelector)); - final UiObject2 appIcon = mLauncher.getObjectInContainer(appListRecycler, + final UiObject2 appIcon = mLauncher.waitForObjectInContainer(appListRecycler, appIconSelector); return new AppIcon(mLauncher, appIcon); } diff --git a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java index bbd2c29e3e..25e6e8c8f7 100644 --- a/tests/tapl/com/android/launcher3/tapl/BaseOverview.java +++ b/tests/tapl/com/android/launcher3/tapl/BaseOverview.java @@ -74,7 +74,7 @@ public class BaseOverview extends LauncherInstrumentation.VisibleContainer { flingForward(); } - mLauncher.getObjectInContainer(verifyActiveContainer(), clearAllSelector).click(); + mLauncher.waitForObjectInContainer(verifyActiveContainer(), clearAllSelector).click(); try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer( "dismissed all tasks")) { return new Workspace(mLauncher); diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 1371b21193..6348c41af2 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -678,13 +678,6 @@ public final class LauncherInstrumentation { return object; } - @NonNull - UiObject2 getObjectInContainer(UiObject2 container, BySelector selector) { - final UiObject2 object = container.findObject(selector); - assertNotNull("Can't find an object with selector: " + selector, object); - return object; - } - @NonNull List getObjectsInContainer(UiObject2 container, String resName) { return container.findObjects(getLauncherObjectSelector(resName)); diff --git a/tests/tapl/com/android/launcher3/tapl/Workspace.java b/tests/tapl/com/android/launcher3/tapl/Workspace.java index 07f8b64433..639902fa0d 100644 --- a/tests/tapl/com/android/launcher3/tapl/Workspace.java +++ b/tests/tapl/com/android/launcher3/tapl/Workspace.java @@ -108,10 +108,13 @@ public final class Workspace extends Home { */ @NonNull public AppIcon getWorkspaceAppIcon(String appName) { - return new AppIcon(mLauncher, - mLauncher.getObjectInContainer( - verifyActiveContainer(), - AppIcon.getAppIconSelector(appName, mLauncher))); + try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( + "want to get a workspace icon")) { + return new AppIcon(mLauncher, + mLauncher.waitForObjectInContainer( + verifyActiveContainer(), + AppIcon.getAppIconSelector(appName, mLauncher))); + } } /** @@ -142,13 +145,13 @@ public final class Workspace extends Home { @NonNull public AppIcon getHotseatAppIcon(String appName) { - return new AppIcon(mLauncher, mLauncher.getObjectInContainer( + return new AppIcon(mLauncher, mLauncher.waitForObjectInContainer( mHotseat, AppIcon.getAppIconSelector(appName, mLauncher))); } @NonNull public Folder getHotseatFolder(String appName) { - return new Folder(mLauncher, mLauncher.getObjectInContainer( + return new Folder(mLauncher, mLauncher.waitForObjectInContainer( mHotseat, Folder.getSelector(appName, mLauncher))); } From 6b466783b70c4ab8511bdfbaf0a6939fafad3d5e Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 31 Jul 2019 14:47:11 -0700 Subject: [PATCH 10/31] Improvements in getting workspace app icon Bug: 138743792 Change-Id: I11981774397b82bdad0352343a52341c2e3a5099 --- tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java index 4dab44fadd..c2a3c1c524 100644 --- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java @@ -190,7 +190,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { launcher -> assertTrue("ensureScrollable didn't make workspace scrollable", isWorkspaceScrollable(launcher))); assertNotNull("ensureScrollable didn't add Chrome app", - workspace.tryGetWorkspaceAppIcon("Chrome")); + workspace.getWorkspaceAppIcon("Chrome")); // Test flinging workspace. workspace.flingBackward(); @@ -206,7 +206,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { assertTrue("Launcher internal state is not Home", isInState(LauncherState.NORMAL)); // Test starting a workspace app. - final AppIcon app = workspace.tryGetWorkspaceAppIcon("Chrome"); + final AppIcon app = workspace.getWorkspaceAppIcon("Chrome"); assertNotNull("No Chrome app in workspace", app); } From b90e363b2295645dd36e7f57fb57069ee3e05884 Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 31 Jul 2019 16:41:46 -0700 Subject: [PATCH 11/31] More tracing for wellbeing tests Bug: 138743758 Change-Id: I49765cf94575dd7ce251b36094dd82d55d8410d1 --- tests/src/com/android/launcher3/util/Wait.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/src/com/android/launcher3/util/Wait.java b/tests/src/com/android/launcher3/util/Wait.java index 593cce832b..899686bd61 100644 --- a/tests/src/com/android/launcher3/util/Wait.java +++ b/tests/src/com/android/launcher3/util/Wait.java @@ -1,6 +1,7 @@ package com.android.launcher3.util; import android.os.SystemClock; +import android.util.Log; import org.junit.Assert; @@ -16,7 +17,9 @@ public class Wait { } public static void atMost(String message, Condition condition, long timeout, long sleepMillis) { - long endTime = SystemClock.uptimeMillis() + timeout; + final long startTime = SystemClock.uptimeMillis(); + long endTime = startTime + timeout; + Log.d("Wait", "atMost: " + startTime + " - " + endTime); while (SystemClock.uptimeMillis() < endTime) { try { if (condition.isTrue()) { @@ -36,6 +39,7 @@ public class Wait { } catch (Throwable t) { throw new RuntimeException(t); } + Log.d("Wait", "atMost: timed out: " + SystemClock.uptimeMillis()); Assert.fail(message); } } From bf608722b933b5f72b58101cdc0f54e51f315d59 Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Tue, 30 Jul 2019 11:50:54 -0700 Subject: [PATCH 12/31] Ensure each dot contains only relevant notification to the shortcut and displays system shortcut when long click on deep shortcut. In this CR we 1) for each shortcut, we filters the notifications to ensure we only get notifications with identical shortcutId. 2) allow system shortcut to be displayed when user long click on a DeepShortcut Bug: 132336512 Change-Id: Idc9eaed55e900ed4027a43ee9c3fd7dc6f4480b2 Merged-In: Idc9eaed55e900ed4027a43ee9c3fd7dc6f4480b2 --- .../shortcuts/DeepShortcutManager.java | 7 ++-- .../launcher3/popup/PopupDataProvider.java | 35 +++++++++++++++---- .../shortcuts/DeepShortcutManager.java | 29 ++++----------- 3 files changed, 41 insertions(+), 30 deletions(-) diff --git a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java index 73adaa14fa..7fd4a9de06 100644 --- a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java +++ b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java @@ -53,11 +53,14 @@ public class DeepShortcutManager { return false; } - public static boolean supportsNotificationDots( - ItemInfo info, List notifications) { + public static boolean supportsDeepShortcuts(ItemInfo info) { return false; } + public static String getShortcutIdIfApplicable(ItemInfo info) { + return null; + } + public boolean wasLastCallSuccess() { return false; } diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java index dd496b02bf..6e4883e419 100644 --- a/src/com/android/launcher3/popup/PopupDataProvider.java +++ b/src/com/android/launcher3/popup/PopupDataProvider.java @@ -38,6 +38,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.function.Predicate; +import java.util.stream.Collectors; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -130,7 +131,8 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan for (PackageUserKey packageUserKey : mPackageUserToDotInfos.keySet()) { DotInfo prevDot = updatedDots.get(packageUserKey); DotInfo newDot = mPackageUserToDotInfos.get(packageUserKey); - if (prevDot == null) { + if (prevDot == null + || prevDot.getNotificationCount() != newDot.getNotificationCount()) { updatedDots.put(packageUserKey, newDot); } else { // No need to update the dot if it already existed (no visual change). @@ -156,7 +158,7 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan } public int getShortcutCountForItem(ItemInfo info) { - if (!DeepShortcutManager.supportsShortcuts(info)) { + if (!DeepShortcutManager.supportsDeepShortcuts(info)) { return 0; } ComponentName component = info.getTargetComponent(); @@ -169,10 +171,16 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan } public @Nullable DotInfo getDotInfoForItem(@NonNull ItemInfo info) { + if (!DeepShortcutManager.supportsShortcuts(info)) { + return null; + } DotInfo dotInfo = mPackageUserToDotInfos.get(PackageUserKey.fromItemInfo(info)); - List notifications = - dotInfo == null ? Collections.EMPTY_LIST : dotInfo.getNotificationKeys(); - if (!DeepShortcutManager.supportsNotificationDots(info, notifications)) { + if (dotInfo == null) { + return null; + } + List notifications = getNotificationsForItem( + info, dotInfo.getNotificationKeys()); + if (notifications.isEmpty()) { return null; } return dotInfo; @@ -180,7 +188,8 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan public @NonNull List getNotificationKeysForItem(ItemInfo info) { DotInfo dotInfo = getDotInfoForItem(info); - return dotInfo == null ? Collections.EMPTY_LIST : dotInfo.getNotificationKeys(); + return dotInfo == null ? Collections.EMPTY_LIST + : getNotificationsForItem(info, dotInfo.getNotificationKeys()); } /** This makes a potentially expensive binder call and should be run on a background thread. */ @@ -229,6 +238,20 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan return null; } + /** + * Returns a list of notifications that are relevant to given ItemInfo. + */ + public static @NonNull List getNotificationsForItem( + @NonNull ItemInfo info, @NonNull List notifications) { + String shortcutId = DeepShortcutManager.getShortcutIdIfApplicable(info); + if (shortcutId == null) { + return notifications; + } + return notifications.stream().filter((NotificationKeyData notification) -> + shortcutId.equals(notification.shortcutId) + ).collect(Collectors.toList()); + } + public interface PopupDataChangeListener { PopupDataChangeListener INSTANCE = new PopupDataChangeListener() { }; diff --git a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java index f42bafe5e4..aec2badf27 100644 --- a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java +++ b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java @@ -30,7 +30,6 @@ import android.util.Log; import com.android.launcher3.ItemInfo; import com.android.launcher3.LauncherSettings; import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.notification.NotificationKeyData; import java.util.ArrayList; import java.util.Collections; @@ -65,16 +64,16 @@ public class DeepShortcutManager { } public static boolean supportsShortcuts(ItemInfo info) { + return isActive(info) && (isApp(info) || isPinnedShortcut(info)); + } + + public static boolean supportsDeepShortcuts(ItemInfo info) { return isActive(info) && isApp(info); } - public static boolean supportsNotificationDots( - ItemInfo info, List notifications) { - if (!isActive(info)) { - return false; - } - return isApp(info) || (isPinnedShortcut(info) - && shouldShowNotificationDotForPinnedShortcut(info, notifications)); + public static String getShortcutIdIfApplicable(ItemInfo info) { + return isActive(info) && isPinnedShortcut(info) ? + ShortcutKey.fromItemInfo(info).getId() : null; } private static boolean isApp(ItemInfo info) { @@ -87,20 +86,6 @@ public class DeepShortcutManager { && info instanceof WorkspaceItemInfo; } - private static boolean shouldShowNotificationDotForPinnedShortcut( - ItemInfo info, List notifications) { - String shortcutId = ((WorkspaceItemInfo) info).getDeepShortcutId(); - if (shortcutId == null) { - return false; - } - for (NotificationKeyData notification : notifications) { - if (shortcutId.equals(notification.shortcutId)) { - return true; - } - } - return false; - } - public boolean wasLastCallSuccess() { return mWasLastCallSuccess; } From 84fa94e2fc79aac983b5048caec84ce93a1302fc Mon Sep 17 00:00:00 2001 From: Becky Qiu Date: Tue, 30 Jul 2019 15:08:50 -0700 Subject: [PATCH 13/31] Fill the log container as hotseat or workspace based on position. Test: manual Bug: 137953006 Swipe from workspace: 07-30 15:15:44.031 9779 9779 D UserEvent: action:FLING direction=UP direction=UP 07-30 15:15:44.031 9779 9779 D UserEvent: Source child:WORKSPACE id=0 span(951,1313) parent:WORKSPACE id=0 07-30 15:15:44.031 9779 9779 D UserEvent: Destination child:ALLAPPS 07-30 15:15:44.031 9779 9779 D UserEvent: Elapsed container 826 ms, session 9361 ms, action 0 ms Swipe from hotseat: 07-30 15:15:46.010 9779 9779 D UserEvent: action:FLING direction=UP direction=UP 07-30 15:15:46.010 9779 9779 D UserEvent: Source child:HOTSEAT id=0 span(786,1908) parent:WORKSPACE id=0 07-30 15:15:46.010 9779 9779 D UserEvent: Destination child:ALLAPPS 07-30 15:15:46.010 9779 9779 D UserEvent: Elapsed container 1139 ms, session 11339 ms, action 0 ms Change-Id: I959528889fda778efc569bb59e7f44d3bd5b81bc --- .../LandscapeStatesTouchController.java | 2 +- .../OverviewToAllAppsTouchController.java | 2 +- .../QuickSwitchTouchController.java | 2 +- .../LandscapeEdgeSwipeController.java | 2 +- .../PortraitStatesTouchController.java | 4 +-- .../AbstractStateChangeTouchController.java | 26 +++++++++++++------ .../uioverrides/AllAppsSwipeController.java | 2 +- 7 files changed, 25 insertions(+), 15 deletions(-) diff --git a/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java b/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java index 1ccd7d79ac..66aec40509 100644 --- a/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java +++ b/go/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeStatesTouchController.java @@ -64,7 +64,7 @@ public final class LandscapeStatesTouchController extends PortraitStatesTouchCon } @Override - protected int getLogContainerTypeForNormalState() { + protected int getLogContainerTypeForNormalState(MotionEvent ev) { return LauncherLogProto.ContainerType.WORKSPACE; } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java index 73f328bc1d..90911684ec 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/OverviewToAllAppsTouchController.java @@ -75,7 +75,7 @@ public class OverviewToAllAppsTouchController extends PortraitStatesTouchControl } @Override - protected int getLogContainerTypeForNormalState() { + protected int getLogContainerTypeForNormalState(MotionEvent ev) { return LauncherLogProto.ContainerType.WORKSPACE; } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java index 18b8af4fa7..eb571f607a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java @@ -154,7 +154,7 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll } @Override - protected int getLogContainerTypeForNormalState() { + protected int getLogContainerTypeForNormalState(MotionEvent ev) { return LauncherLogProto.ContainerType.NAVBAR; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java index 0605953dce..bb72315d3b 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/LandscapeEdgeSwipeController.java @@ -46,7 +46,7 @@ public class LandscapeEdgeSwipeController extends AbstractStateChangeTouchContro } @Override - protected int getLogContainerTypeForNormalState() { + protected int getLogContainerTypeForNormalState(MotionEvent ev) { return LauncherLogProto.ContainerType.NAVBAR; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java index a55f36b787..b81edfa4ca 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/PortraitStatesTouchController.java @@ -147,8 +147,8 @@ public class PortraitStatesTouchController extends AbstractStateChangeTouchContr } @Override - protected int getLogContainerTypeForNormalState() { - return ContainerType.HOTSEAT; + protected int getLogContainerTypeForNormalState(MotionEvent ev) { + return isTouchOverHotseat(mLauncher, ev) ? ContainerType.HOTSEAT : ContainerType.WORKSPACE; } private AnimatorSetBuilder getNormalToOverviewAnimation() { diff --git a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java index 0545344170..c5ba5bab6a 100644 --- a/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java +++ b/src/com/android/launcher3/touch/AbstractStateChangeTouchController.java @@ -69,6 +69,7 @@ public abstract class AbstractStateChangeTouchController protected final SwipeDetector.Direction mSwipeDirection; private boolean mNoIntercept; + private boolean mIsLogContainerSet; protected int mStartContainerType; protected LauncherState mStartState; @@ -180,7 +181,7 @@ public abstract class AbstractStateChangeTouchController /** * Returns the container that the touch started from when leaving NORMAL state. */ - protected abstract int getLogContainerTypeForNormalState(); + protected abstract int getLogContainerTypeForNormalState(MotionEvent ev); private boolean reinitCurrentAnimation(boolean reachedToState, boolean isDragTowardPositive) { LauncherState newFromState = mFromState == null ? mLauncher.getStateManager().getState() @@ -231,13 +232,7 @@ public abstract class AbstractStateChangeTouchController @Override public void onDragStart(boolean start) { mStartState = mLauncher.getStateManager().getState(); - if (mStartState == ALL_APPS) { - mStartContainerType = LauncherLogProto.ContainerType.ALLAPPS; - } else if (mStartState == NORMAL) { - mStartContainerType = getLogContainerTypeForNormalState(); - } else if (mStartState == OVERVIEW){ - mStartContainerType = LauncherLogProto.ContainerType.TASKSWITCHER; - } + mIsLogContainerSet = false; if (mCurrentAnimation == null) { mFromState = mStartState; mToState = null; @@ -285,6 +280,21 @@ public abstract class AbstractStateChangeTouchController return true; } + @Override + public boolean onDrag(float displacement, MotionEvent ev) { + if (!mIsLogContainerSet) { + if (mStartState == ALL_APPS) { + mStartContainerType = LauncherLogProto.ContainerType.ALLAPPS; + } else if (mStartState == NORMAL) { + mStartContainerType = getLogContainerTypeForNormalState(ev); + } else if (mStartState == OVERVIEW) { + mStartContainerType = LauncherLogProto.ContainerType.TASKSWITCHER; + } + mIsLogContainerSet = true; + } + return onDrag(displacement); + } + protected void updateProgress(float fraction) { mCurrentAnimation.setPlayFraction(fraction); if (mAtomicComponentsController != null) { diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java index e9dc800e3c..bd6ea502e4 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsSwipeController.java @@ -57,7 +57,7 @@ public class AllAppsSwipeController extends AbstractStateChangeTouchController { } @Override - protected int getLogContainerTypeForNormalState() { + protected int getLogContainerTypeForNormalState(MotionEvent ev) { return mLauncher.getDragLayer().isEventOverView(mLauncher.getHotseat(), mTouchDownEvent) ? ContainerType.HOTSEAT : ContainerType.WORKSPACE; } From bfc2da1fd824089eacd97ce8bbacc41138b14742 Mon Sep 17 00:00:00 2001 From: Becky Qiu Date: Thu, 1 Aug 2019 11:09:38 -0700 Subject: [PATCH 14/31] Log the right workspace id for -1 screen for stop and resume. Test: manual Bug: 137952354 Logs after this fix: 08-01 12:01:36.220 17105 17105 D UserEvent: action:STOP 08-01 12:01:36.220 17105 17105 D UserEvent: Source child:WORKSPACE id=-1 08-01 12:01:36.220 17105 17105 D UserEvent: Elapsed container 5511 ms, session 5511 ms, action 0 ms 08-01 12:01:36.220 17105 17105 D UserEvent: 08-01 12:01:38.042 17105 17105 D UserEvent: 08-01 12:01:38.042 17105 17105 D UserEvent: ----------------------------------------------------- 08-01 12:01:38.042 17105 17105 D UserEvent: action:RESUME 08-01 12:01:38.042 17105 17105 D UserEvent: Source child:WORKSPACE id=-1 08-01 12:01:38.042 17105 17105 D UserEvent: Elapsed container 7334 ms, session 7334 ms, action 0 ms 08-01 12:01:38.042 17105 17105 D UserEvent: Change-Id: Ic2d88eee3ff7a0e28d5c7e4cab8ee61952ed95ee --- src/com/android/launcher3/Launcher.java | 18 +++++++++++++----- src/com/android/launcher3/Workspace.java | 4 ++++ .../launcher3/logging/UserEventDispatcher.java | 8 ++++++++ 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 03fdc971dd..cf68f8680d 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -873,9 +873,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, if (mLauncherCallbacks != null) { mLauncherCallbacks.onStop(); } - - getUserEventDispatcher().logActionCommand(Action.Command.STOP, - mStateManager.getState().containerType, -1); + logStopAndResume(Action.Command.STOP); mAppWidgetHost.setListenIfResumed(false); @@ -901,8 +899,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, private void handleDeferredResume() { if (hasBeenResumed() && !mStateManager.getState().disableInteraction) { - getUserEventDispatcher().logActionCommand(Action.Command.RESUME, - mStateManager.getState().containerType, -1); + logStopAndResume(Action.Command.RESUME); getUserEventDispatcher().startSession(); UiFactory.onLauncherStateOrResumeChanged(this); @@ -929,6 +926,17 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, } } + private void logStopAndResume(int command) { + int containerType = mStateManager.getState().containerType; + if (containerType == ContainerType.WORKSPACE && mWorkspace != null) { + getUserEventDispatcher().logActionCommand(command, + containerType, -1, mWorkspace.isOverlayShown() ? -1 : 0); + } else { + getUserEventDispatcher().logActionCommand(command, containerType, -1); + } + + } + protected void onStateSet(LauncherState state) { getAppWidgetHost().setResumed(state == LauncherState.NORMAL); if (mDeferredResumePending) { diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 269a591115..82d4117e3d 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -3251,6 +3251,10 @@ public class Workspace extends PagedView } } + public boolean isOverlayShown() { + return mOverlayShown; + } + void moveToDefaultScreen() { int page = DEFAULT_PAGE; if (!workspaceInModalState() && getNextPage() != page) { diff --git a/src/com/android/launcher3/logging/UserEventDispatcher.java b/src/com/android/launcher3/logging/UserEventDispatcher.java index d81020ef3c..c72b07a7f6 100644 --- a/src/com/android/launcher3/logging/UserEventDispatcher.java +++ b/src/com/android/launcher3/logging/UserEventDispatcher.java @@ -187,6 +187,14 @@ public class UserEventDispatcher implements ResourceBasedOverride { dstContainerType >=0 ? newContainerTarget(dstContainerType) : null); } + public void logActionCommand(int command, int srcContainerType, int dstContainerType, + int pageIndex) { + Target srcTarget = newContainerTarget(srcContainerType); + srcTarget.pageIndex = pageIndex; + logActionCommand(command, srcTarget, + dstContainerType >=0 ? newContainerTarget(dstContainerType) : null); + } + public void logActionCommand(int command, Target srcTarget, Target dstTarget) { LauncherEvent event = newLauncherEvent(newCommandAction(command), srcTarget); if (command == Action.Command.STOP) { From bd7acf7665712c742af7f08dd76c3678cb5d52ab Mon Sep 17 00:00:00 2001 From: Tracy Zhou Date: Wed, 31 Jul 2019 15:15:03 -0700 Subject: [PATCH 15/31] Change RecentsAnimationListenerSet interface (Launcher) Bug: 138683199 Test: N/A Change-Id: Ic53ef92fe4d5b55ff1d105a250accdf6f6c0916b (cherry picked from commit 8e8a36f673de31a31e19131ab286de7798e23b78) --- .../quickstep/util/RecentsAnimationListenerSet.java | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java index 83601e6175..14083dd958 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RecentsAnimationListenerSet.java @@ -23,6 +23,7 @@ import android.util.ArraySet; import com.android.launcher3.Utilities; import com.android.launcher3.util.Preconditions; import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener; +import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; import com.android.systemui.shared.system.RecentsAnimationListener; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -39,7 +40,7 @@ import androidx.annotation.UiThread; public class RecentsAnimationListenerSet implements RecentsAnimationListener { // The actual app surface is replaced by a screenshot upon recents animation cancelation when - // deferredWithScreenshot is true. Launcher takes the responsibility to clean up this screenshot + // the thumbnailData exists. Launcher takes the responsibility to clean up this screenshot // after app transition is finished. This delay is introduced to cover the app transition // period of time. private final int TRANSITION_DELAY = 100; @@ -90,14 +91,14 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { } @Override - public final void onAnimationCanceled(boolean deferredWithScreenshot) { + public final void onAnimationCanceled(ThumbnailData thumbnailData) { Utilities.postAsyncCallback(MAIN_THREAD_EXECUTOR.getHandler(), () -> { for (SwipeAnimationListener listener : getListeners()) { listener.onRecentsAnimationCanceled(); } }); // TODO: handle the transition better instead of simply using a transition delay. - if (deferredWithScreenshot) { + if (thumbnailData != null) { MAIN_THREAD_EXECUTOR.getHandler().postDelayed(() -> mController.cleanupScreenshot(), TRANSITION_DELAY); } @@ -109,6 +110,6 @@ public class RecentsAnimationListenerSet implements RecentsAnimationListener { public void cancelListener() { mCancelled = true; - onAnimationCanceled(false); + onAnimationCanceled(null); } } From f1726290d46c1c7072d6741226d1973844a1b807 Mon Sep 17 00:00:00 2001 From: vadimt Date: Mon, 5 Aug 2019 13:52:36 -0700 Subject: [PATCH 16/31] Adding debug tracing to catch non-dragging to workspace Bug: 138729456 Change-Id: I28f1eaeb17a75cbc6f52b259d0226deaff42e0bb --- src/com/android/launcher3/Workspace.java | 10 ++++++++++ .../android/launcher3/dragndrop/DragController.java | 3 +++ src/com/android/launcher3/dragndrop/DragDriver.java | 5 +++++ src/com/android/launcher3/testing/TestProtocol.java | 1 + .../com/android/launcher3/ui/TaplTestsLauncher3.java | 6 ++++++ 5 files changed, 25 insertions(+) diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 269a591115..02b2d8d338 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -85,6 +85,7 @@ import com.android.launcher3.logging.UserEventDispatcher; import com.android.launcher3.pageindicators.WorkspacePageIndicator; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.WorkspaceTouchListener; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -420,6 +421,9 @@ public class Workspace extends PagedView } // Always enter the spring loaded mode + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "Switching to SPRING_LOADED"); + } mLauncher.getStateManager().goToState(SPRING_LOADED); } @@ -1741,6 +1745,9 @@ public class Workspace extends PagedView public void prepareAccessibilityDrop() { } public void onDrop(final DragObject d, DragOptions options) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "Workspace.onDrop"); + } mDragViewVisualCenter = d.getVisualCenter(mDragViewVisualCenter); CellLayout dropTargetLayout = mDropToLayout; @@ -2418,6 +2425,9 @@ public class Workspace extends PagedView * to add an item to one of the workspace screens. */ private void onDropExternal(final int[] touchXY, final CellLayout cellLayout, DragObject d) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "Workspace.onDropExternal"); + } if (d.dragInfo instanceof PendingAddShortcutInfo) { WorkspaceItemInfo si = ((PendingAddShortcutInfo) d.dragInfo) .activityInfo.createWorkspaceItemInfo(); diff --git a/src/com/android/launcher3/dragndrop/DragController.java b/src/com/android/launcher3/dragndrop/DragController.java index d32dd2eb98..b72fd988a3 100644 --- a/src/com/android/launcher3/dragndrop/DragController.java +++ b/src/com/android/launcher3/dragndrop/DragController.java @@ -579,6 +579,9 @@ public class DragController implements DragDriver.EventListener, TouchController } private void drop(DropTarget dropTarget, Runnable flingAnimation) { + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "DragController.drop"); + } final int[] coordinates = mCoordinatesTemp; mDragObject.x = coordinates[0]; mDragObject.y = coordinates[1]; diff --git a/src/com/android/launcher3/dragndrop/DragDriver.java b/src/com/android/launcher3/dragndrop/DragDriver.java index 84fc94dd25..bd2a03b6c2 100644 --- a/src/com/android/launcher3/dragndrop/DragDriver.java +++ b/src/com/android/launcher3/dragndrop/DragDriver.java @@ -17,10 +17,12 @@ package com.android.launcher3.dragndrop; import android.content.Context; +import android.util.Log; import android.view.DragEvent; import android.view.MotionEvent; import com.android.launcher3.DropTarget.DragObject; +import com.android.launcher3.testing.TestProtocol; /** * Base class for driving a drag/drop operation. @@ -52,6 +54,9 @@ public abstract class DragDriver { mEventListener.onDriverDragMove(ev.getX(), ev.getY()); break; case MotionEvent.ACTION_UP: + if (TestProtocol.sDebugTracing) { + Log.d(TestProtocol.NO_DRAG_TO_WORKSPACE, "DragDriver.ACTION_UP"); + } mEventListener.onDriverDragMove(ev.getX(), ev.getY()); mEventListener.onDriverDragEnd(ev.getX(), ev.getY()); break; diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index 9846a04271..cb8f811cb2 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -79,4 +79,5 @@ public final class TestProtocol { public static final String REQUEST_DISABLE_DEBUG_TRACING = "disable-debug-tracing"; public static final String NO_BACKGROUND_TO_OVERVIEW_TAG = "b/138251824"; + public static final String NO_DRAG_TO_WORKSPACE = "b/138729456"; } diff --git a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java index c2a3c1c524..0c87ab9089 100644 --- a/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java +++ b/tests/src/com/android/launcher3/ui/TaplTestsLauncher3.java @@ -173,6 +173,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @Test public void testWorkspace() throws Exception { + mLauncher.enableDebugTracing(); final Workspace workspace = mLauncher.getWorkspace(); // Test that ensureWorkspaceIsScrollable adds a page by dragging an icon there. @@ -208,6 +209,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { // Test starting a workspace app. final AppIcon app = workspace.getWorkspaceAppIcon("Chrome"); assertNotNull("No Chrome app in workspace", app); + mLauncher.disableDebugTracing(); } public static void runIconLaunchFromAllAppsTest(AbstractLauncherUiTest test, AllApps allApps) { @@ -298,6 +300,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { @Test @PortraitLandscape public void testDragAppIcon() throws Throwable { + mLauncher.enableDebugTracing(); // 1. Open all apps and wait for load complete. // 2. Drag icon to homescreen. // 3. Verify that the icon works on homescreen. @@ -314,11 +317,13 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { "Launcher activity is the top activity; expecting another activity to be the top " + "one", isInBackground(launcher))); + mLauncher.disableDebugTracing(); } @Test @PortraitLandscape public void testDragShortcut() throws Throwable { + mLauncher.enableDebugTracing(); // 1. Open all apps and wait for load complete. // 2. Find the app and long press it to show shortcuts. // 3. Press icon center until shortcuts appear @@ -338,6 +343,7 @@ public class TaplTestsLauncher3 extends AbstractLauncherUiTest { } finally { allApps.unfreeze(); } + mLauncher.disableDebugTracing(); } public static String getAppPackageName() { From 94734217551e44ed747472dd9db05c812cc454f2 Mon Sep 17 00:00:00 2001 From: vadimt Date: Mon, 5 Aug 2019 17:31:53 -0700 Subject: [PATCH 17/31] Adding system health permissions to Launcher3 tests Change-Id: Id4ae4731274bef243801e3a15bc87e9c3fa9e0c4 --- tests/AndroidManifest-common.xml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml index 61c7306e57..c6f55a7178 100644 --- a/tests/AndroidManifest-common.xml +++ b/tests/AndroidManifest-common.xml @@ -20,6 +20,9 @@ + + + From e4061fc931cb8bc50306a76e617761936a74b97f Mon Sep 17 00:00:00 2001 From: Pinyao Ting Date: Fri, 26 Jul 2019 12:28:38 -0700 Subject: [PATCH 18/31] show dot in deep shortcuts when notification contains exactly identical set of person Bug: 132336512 Change-Id: I975524e28168c10a186cdc24b188c161faf433cf Merged-In: I975524e28168c10a186cdc24b188c161faf433cf --- .../shortcuts/DeepShortcutManager.java | 12 ---- .../launcher3/uioverrides/UiFactory.java | 7 +++ src/com/android/launcher3/Launcher.java | 3 +- src/com/android/launcher3/Utilities.java | 4 ++ .../android/launcher3/WorkspaceItemInfo.java | 23 ++++++++ .../LauncherAccessibilityDelegate.java | 3 +- .../notification/NotificationKeyData.java | 25 +++++++- .../popup/PopupContainerWithArrow.java | 3 +- .../launcher3/popup/PopupDataProvider.java | 22 +++++-- .../launcher3/util/PackageUserKey.java | 2 +- .../android/launcher3/util/ShortcutUtil.java | 59 +++++++++++++++++++ .../shortcuts/DeepShortcutManager.java | 33 ----------- .../launcher3/uioverrides/UiFactory.java | 6 ++ 13 files changed, 144 insertions(+), 58 deletions(-) create mode 100644 src/com/android/launcher3/util/ShortcutUtil.java diff --git a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java index 7fd4a9de06..ee113dfebf 100644 --- a/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java +++ b/go/src/com/android/launcher3/shortcuts/DeepShortcutManager.java @@ -49,18 +49,6 @@ public class DeepShortcutManager { private DeepShortcutManager(Context context) { } - public static boolean supportsShortcuts(ItemInfo info) { - return false; - } - - public static boolean supportsDeepShortcuts(ItemInfo info) { - return false; - } - - public static String getShortcutIdIfApplicable(ItemInfo info) { - return null; - } - public boolean wasLastCallSuccess() { return false; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index 97cd38a117..c02df9386c 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -32,9 +32,11 @@ import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN; import android.animation.AnimatorSet; import android.animation.ValueAnimator; import android.app.Activity; +import android.app.Person; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ShortcutInfo; import android.os.Bundle; import android.os.CancellationSignal; import android.util.Base64; @@ -244,4 +246,9 @@ public class UiFactory extends RecentsUiFactory { } return new ScaleAndTranslation(1.1f, 0f, 0f); } + + public static Person[] getPersons(ShortcutInfo si) { + Person[] persons = si.getPersons(); + return persons == null ? Utilities.EMPTY_PERSON_ARRAY : persons; + } } diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 8a2fef277b..d79230f8be 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -127,6 +127,7 @@ import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PackageUserKey; import com.android.launcher3.util.PendingRequestArgs; import com.android.launcher3.util.RaceConditionTracker; +import com.android.launcher3.util.ShortcutUtil; import com.android.launcher3.util.SystemUiController; import com.android.launcher3.util.Themes; import com.android.launcher3.util.Thunk; @@ -2502,7 +2503,7 @@ public class Launcher extends BaseDraggingActivity implements LauncherExterns, KeyEvent.KEYCODE_O, KeyEvent.META_CTRL_ON)); } if (currentFocus.getTag() instanceof ItemInfo - && DeepShortcutManager.supportsShortcuts((ItemInfo) currentFocus.getTag())) { + && ShortcutUtil.supportsShortcuts((ItemInfo) currentFocus.getTag())) { shortcutInfos.add(new KeyboardShortcutInfo( getString(R.string.shortcuts_menu_with_notifications_description), KeyEvent.KEYCODE_S, KeyEvent.META_CTRL_ON)); diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index fc5cd8a888..3bef5986d7 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -21,6 +21,7 @@ import static com.android.launcher3.ItemInfoWithIcon.FLAG_ICON_BADGED; import android.animation.ValueAnimator; import android.annotation.TargetApi; import android.app.ActivityManager; +import android.app.Person; import android.app.WallpaperManager; import android.content.BroadcastReceiver; import android.content.ComponentName; @@ -109,6 +110,9 @@ public final class Utilities { private static final Matrix sMatrix = new Matrix(); private static final Matrix sInverseMatrix = new Matrix(); + public static final String[] EMPTY_STRING_ARRAY = new String[0]; + public static final Person[] EMPTY_PERSON_ARRAY = new Person[0]; + public static final boolean ATLEAST_Q = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q; public static final boolean ATLEAST_P = diff --git a/src/com/android/launcher3/WorkspaceItemInfo.java b/src/com/android/launcher3/WorkspaceItemInfo.java index 5a2373b996..b72866c266 100644 --- a/src/com/android/launcher3/WorkspaceItemInfo.java +++ b/src/com/android/launcher3/WorkspaceItemInfo.java @@ -16,17 +16,23 @@ package com.android.launcher3; +import android.app.Person; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.ShortcutInfo; import android.text.TextUtils; +import androidx.annotation.NonNull; + import com.android.launcher3.LauncherSettings.Favorites; import com.android.launcher3.icons.IconCache; import com.android.launcher3.shortcuts.ShortcutKey; +import com.android.launcher3.uioverrides.UiFactory; import com.android.launcher3.util.ContentWriter; +import java.util.Arrays; + /** * Represents a launchable icon on the workspaces and in folders. */ @@ -82,11 +88,18 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { public int status; + /** + * A set of person's Id associated with the WorkspaceItemInfo, this is only used if the item + * represents a deep shortcut. + */ + @NonNull private String[] personKeys = Utilities.EMPTY_STRING_ARRAY; + /** * The installation progress [0-100] of the package that this shortcut represents. */ private int mInstallProgress; + public WorkspaceItemInfo() { itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT; } @@ -98,6 +111,7 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { iconResource = info.iconResource; status = info.status; mInstallProgress = info.mInstallProgress; + personKeys = info.personKeys.clone(); } /** TODO: Remove this. It's only called by ApplicationInfo.makeWorkspaceItem. */ @@ -175,6 +189,10 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { runtimeStatusFlags |= FLAG_DISABLED_BY_PUBLISHER; } disabledMessage = shortcutInfo.getDisabledMessage(); + + Person[] persons = UiFactory.getPersons(shortcutInfo); + personKeys = persons.length == 0 ? Utilities.EMPTY_STRING_ARRAY + : Arrays.stream(persons).map(Person::getKey).sorted().toArray(String[]::new); } /** Returns the WorkspaceItemInfo id associated with the deep shortcut. */ @@ -183,6 +201,11 @@ public class WorkspaceItemInfo extends ItemInfoWithIcon { getIntent().getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID) : null; } + @NonNull + public String[] getPersonKeys() { + return personKeys; + } + @Override public ComponentName getTargetComponent() { ComponentName cn = super.getTargetComponent(); diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java index fd4df5247e..0c1303b64b 100644 --- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java +++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java @@ -40,6 +40,7 @@ import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.util.IntArray; +import com.android.launcher3.util.ShortcutUtil; import com.android.launcher3.util.Thunk; import com.android.launcher3.widget.LauncherAppWidgetHostView; @@ -115,7 +116,7 @@ public class LauncherAccessibilityDelegate extends AccessibilityDelegate impleme // If the request came from keyboard, do not add custom shortcuts as that is already // exposed as a direct shortcut - if (!fromKeyboard && DeepShortcutManager.supportsShortcuts(item)) { + if (!fromKeyboard && ShortcutUtil.supportsShortcuts(item)) { info.addAction(mActions.get(NotificationListener.getInstanceIfConnected() != null ? SHORTCUTS_AND_NOTIFICATIONS : DEEP_SHORTCUTS)); } diff --git a/src/com/android/launcher3/notification/NotificationKeyData.java b/src/com/android/launcher3/notification/NotificationKeyData.java index 5050457b9b..bfa4ba9ab3 100644 --- a/src/com/android/launcher3/notification/NotificationKeyData.java +++ b/src/com/android/launcher3/notification/NotificationKeyData.java @@ -17,12 +17,18 @@ package com.android.launcher3.notification; import android.app.Notification; +import android.app.Person; import android.service.notification.StatusBarNotification; +import com.android.launcher3.Utilities; import java.util.ArrayList; +import java.util.Collections; +import java.util.HashSet; import java.util.List; +import java.util.Set; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; /** * The key data associated with the notification, used to determine what to include @@ -34,19 +40,25 @@ public class NotificationKeyData { public final String notificationKey; public final String shortcutId; public int count; + @NonNull public final String[] personKeysFromNotification; - private NotificationKeyData(String notificationKey, String shortcutId, int count) { + private NotificationKeyData(String notificationKey, String shortcutId, int count, + String[] personKeysFromNotification) { this.notificationKey = notificationKey; this.shortcutId = shortcutId; this.count = Math.max(1, count); + this.personKeysFromNotification = personKeysFromNotification; } public static NotificationKeyData fromNotification(StatusBarNotification sbn) { Notification notif = sbn.getNotification(); - return new NotificationKeyData(sbn.getKey(), notif.getShortcutId(), notif.number); + return new NotificationKeyData(sbn.getKey(), notif.getShortcutId(), notif.number, + extractPersonKeyOnly(notif.extras.getParcelableArrayList( + Notification.EXTRA_PEOPLE_LIST))); } - public static List extractKeysOnly(@NonNull List notificationKeys) { + public static List extractKeysOnly( + @NonNull List notificationKeys) { List keysOnly = new ArrayList<>(notificationKeys.size()); for (NotificationKeyData notificationKeyData : notificationKeys) { keysOnly.add(notificationKeyData.notificationKey); @@ -54,6 +66,13 @@ public class NotificationKeyData { return keysOnly; } + private static String[] extractPersonKeyOnly(@Nullable ArrayList people) { + if (people == null || people.isEmpty()) { + return Utilities.EMPTY_STRING_ARRAY; + } + return people.stream().map(Person::getKey).sorted().toArray(String[]::new); + } + @Override public boolean equals(Object obj) { if (!(obj instanceof NotificationKeyData)) { diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 25d9f7976a..baaad65736 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -72,6 +72,7 @@ import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.touch.ItemLongClickListener; import com.android.launcher3.util.PackageUserKey; +import com.android.launcher3.util.ShortcutUtil; import com.android.launcher3.views.BaseDragLayer; import java.util.ArrayList; @@ -201,7 +202,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, return null; } ItemInfo itemInfo = (ItemInfo) icon.getTag(); - if (!DeepShortcutManager.supportsShortcuts(itemInfo)) { + if (!ShortcutUtil.supportsShortcuts(itemInfo)) { return null; } diff --git a/src/com/android/launcher3/popup/PopupDataProvider.java b/src/com/android/launcher3/popup/PopupDataProvider.java index 6e4883e419..4612b2a474 100644 --- a/src/com/android/launcher3/popup/PopupDataProvider.java +++ b/src/com/android/launcher3/popup/PopupDataProvider.java @@ -29,14 +29,17 @@ import com.android.launcher3.notification.NotificationListener; import com.android.launcher3.shortcuts.DeepShortcutManager; import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.PackageUserKey; +import com.android.launcher3.util.ShortcutUtil; import com.android.launcher3.widget.WidgetListRowEntry; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; import java.util.function.Predicate; import java.util.stream.Collectors; @@ -158,7 +161,7 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan } public int getShortcutCountForItem(ItemInfo info) { - if (!DeepShortcutManager.supportsDeepShortcuts(info)) { + if (!ShortcutUtil.supportsDeepShortcuts(info)) { return 0; } ComponentName component = info.getTargetComponent(); @@ -171,7 +174,7 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan } public @Nullable DotInfo getDotInfoForItem(@NonNull ItemInfo info) { - if (!DeepShortcutManager.supportsShortcuts(info)) { + if (!ShortcutUtil.supportsShortcuts(info)) { return null; } DotInfo dotInfo = mPackageUserToDotInfos.get(PackageUserKey.fromItemInfo(info)); @@ -243,13 +246,20 @@ public class PopupDataProvider implements NotificationListener.NotificationsChan */ public static @NonNull List getNotificationsForItem( @NonNull ItemInfo info, @NonNull List notifications) { - String shortcutId = DeepShortcutManager.getShortcutIdIfApplicable(info); + String shortcutId = ShortcutUtil.getShortcutIdIfPinnedShortcut(info); if (shortcutId == null) { return notifications; } - return notifications.stream().filter((NotificationKeyData notification) -> - shortcutId.equals(notification.shortcutId) - ).collect(Collectors.toList()); + String[] personKeys = ShortcutUtil.getPersonKeysIfPinnedShortcut(info); + return notifications.stream().filter((NotificationKeyData notification) -> { + if (notification.shortcutId != null) { + return notification.shortcutId.equals(shortcutId); + } + if (notification.personKeysFromNotification.length != 0) { + return Arrays.equals(notification.personKeysFromNotification, personKeys); + } + return false; + }).collect(Collectors.toList()); } public interface PopupDataChangeListener { diff --git a/src/com/android/launcher3/util/PackageUserKey.java b/src/com/android/launcher3/util/PackageUserKey.java index 1ce2822109..e624517581 100644 --- a/src/com/android/launcher3/util/PackageUserKey.java +++ b/src/com/android/launcher3/util/PackageUserKey.java @@ -38,7 +38,7 @@ public class PackageUserKey { * @return Whether this PackageUserKey was successfully updated - it shouldn't be used if not. */ public boolean updateFromItemInfo(ItemInfo info) { - if (DeepShortcutManager.supportsShortcuts(info)) { + if (ShortcutUtil.supportsShortcuts(info)) { update(info.getTargetComponent().getPackageName(), info.user); return true; } diff --git a/src/com/android/launcher3/util/ShortcutUtil.java b/src/com/android/launcher3/util/ShortcutUtil.java new file mode 100644 index 0000000000..792d69fc36 --- /dev/null +++ b/src/com/android/launcher3/util/ShortcutUtil.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.util; + +import com.android.launcher3.ItemInfo; +import com.android.launcher3.LauncherSettings; +import com.android.launcher3.Utilities; +import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.config.FeatureFlags; +import com.android.launcher3.shortcuts.ShortcutKey; + +public class ShortcutUtil { + public static boolean supportsShortcuts(ItemInfo info) { + return isActive(info) && (isApp(info) || isPinnedShortcut(info)); + } + + public static boolean supportsDeepShortcuts(ItemInfo info) { + return isActive(info) && isApp(info); + } + + public static String getShortcutIdIfPinnedShortcut(ItemInfo info) { + return isActive(info) && isPinnedShortcut(info) ? + ShortcutKey.fromItemInfo(info).getId() : null; + } + + public static String[] getPersonKeysIfPinnedShortcut(ItemInfo info) { + return isActive(info) && isPinnedShortcut(info) ? + ((WorkspaceItemInfo) info).getPersonKeys() : Utilities.EMPTY_STRING_ARRAY; + } + + private static boolean isActive(ItemInfo info) { + boolean isLoading = info instanceof WorkspaceItemInfo + && ((WorkspaceItemInfo) info).hasPromiseIconUi(); + return !isLoading && !info.isDisabled() && !FeatureFlags.GO_DISABLE_WIDGETS; + } + + private static boolean isApp(ItemInfo info) { + return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; + } + + private static boolean isPinnedShortcut(ItemInfo info) { + return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT + && info.container != ItemInfo.NO_ID + && info instanceof WorkspaceItemInfo; + } +} \ No newline at end of file diff --git a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java index aec2badf27..7119aeadf6 100644 --- a/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java +++ b/src_shortcuts_overrides/com/android/launcher3/shortcuts/DeepShortcutManager.java @@ -27,10 +27,6 @@ import android.os.Bundle; import android.os.UserHandle; import android.util.Log; -import com.android.launcher3.ItemInfo; -import com.android.launcher3.LauncherSettings; -import com.android.launcher3.WorkspaceItemInfo; - import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -63,29 +59,6 @@ public class DeepShortcutManager { mLauncherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE); } - public static boolean supportsShortcuts(ItemInfo info) { - return isActive(info) && (isApp(info) || isPinnedShortcut(info)); - } - - public static boolean supportsDeepShortcuts(ItemInfo info) { - return isActive(info) && isApp(info); - } - - public static String getShortcutIdIfApplicable(ItemInfo info) { - return isActive(info) && isPinnedShortcut(info) ? - ShortcutKey.fromItemInfo(info).getId() : null; - } - - private static boolean isApp(ItemInfo info) { - return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; - } - - private static boolean isPinnedShortcut(ItemInfo info) { - return info.itemType == LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT - && info.container != ItemInfo.NO_ID - && info instanceof WorkspaceItemInfo; - } - public boolean wasLastCallSuccess() { return mWasLastCallSuccess; } @@ -199,12 +172,6 @@ public class DeepShortcutManager { return shortcutIds; } - private static boolean isActive(ItemInfo info) { - boolean isLoading = info instanceof WorkspaceItemInfo - && ((WorkspaceItemInfo) info).hasPromiseIconUi(); - return !isLoading && !info.isDisabled(); - } - /** * Query the system server for all the shortcuts matching the given parameters. * If packageName == null, we query for all shortcuts with the passed flags, regardless of app. diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index 5cc64dc9aa..467ae02d5c 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -17,9 +17,11 @@ package com.android.launcher3.uioverrides; import android.app.Activity; +import android.app.Person; import android.content.Context; import android.content.Intent; import android.content.IntentSender; +import android.content.pm.ShortcutInfo; import android.os.Bundle; import android.os.CancellationSignal; @@ -27,6 +29,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState.ScaleAndTranslation; import com.android.launcher3.LauncherStateManager.StateHandler; +import com.android.launcher3.Utilities; import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.util.TouchController; @@ -95,4 +98,7 @@ public class UiFactory { public static void clearSwipeSharedState(boolean finishAnimation) {} + public static Person[] getPersons(ShortcutInfo si) { + return Utilities.EMPTY_PERSON_ARRAY; + } } From c1a2764a6e488bfdc9952fa9270b6a78309741cd Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 8 Aug 2019 11:49:24 -0700 Subject: [PATCH 19/31] Support for memory tests Change-Id: I867a232a293f7bddbc630f563f18c0db94ac4b6e --- .../android/launcher3/testing/TestInformationHandler.java | 7 +++++++ src/com/android/launcher3/testing/TestProtocol.java | 1 + .../android/launcher3/tapl/LauncherInstrumentation.java | 5 +++++ 3 files changed, 13 insertions(+) diff --git a/src/com/android/launcher3/testing/TestInformationHandler.java b/src/com/android/launcher3/testing/TestInformationHandler.java index bab454f070..4fd0f884d6 100644 --- a/src/com/android/launcher3/testing/TestInformationHandler.java +++ b/src/com/android/launcher3/testing/TestInformationHandler.java @@ -112,6 +112,13 @@ public class TestInformationHandler implements ResourceBasedOverride { } break; } + + case TestProtocol.REQUEST_ALLOCATED_MEMORY: { + final Runtime runtime = Runtime.getRuntime(); + response.putLong(TestProtocol.TEST_INFO_RESPONSE_FIELD, + runtime.totalMemory() - runtime.freeMemory()); + break; + } } return response; } diff --git a/src/com/android/launcher3/testing/TestProtocol.java b/src/com/android/launcher3/testing/TestProtocol.java index cb8f811cb2..f9f5dc42ab 100644 --- a/src/com/android/launcher3/testing/TestProtocol.java +++ b/src/com/android/launcher3/testing/TestProtocol.java @@ -73,6 +73,7 @@ public final class TestProtocol { public static final String REQUEST_APP_LIST_FREEZE_FLAGS = "app-list-freeze-flags"; public static final String REQUEST_OVERVIEW_LEFT_GESTURE_MARGIN = "overview-left-margin"; public static final String REQUEST_OVERVIEW_RIGHT_GESTURE_MARGIN = "overview-right-margin"; + public static final String REQUEST_ALLOCATED_MEMORY = "allocated-memory"; public static boolean sDebugTracing = false; public static final String REQUEST_ENABLE_DEBUG_TRACING = "enable-debug-tracing"; diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 6348c41af2..c012628c15 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -956,4 +956,9 @@ public final class LauncherInstrumentation { public void disableDebugTracing() { getTestInfo(TestProtocol.REQUEST_DISABLE_DEBUG_TRACING); } + + public long getAllocatedMemory() { + return getTestInfo(TestProtocol.REQUEST_ALLOCATED_MEMORY). + getLong(TestProtocol.TEST_INFO_RESPONSE_FIELD); + } } \ No newline at end of file From 90ea00b39908c5e999b54a629fb2d5dca85a0b04 Mon Sep 17 00:00:00 2001 From: Becky Qiu Date: Thu, 8 Aug 2019 11:33:53 -0700 Subject: [PATCH 20/31] Log the event for swiping up to dismiss a task in Overview. Test: manual Bug: 137777105 Demo logging for dismissing a task: data { elapsed_timestamp_nanos: 70772067228810 atom { launcher_event { action: DISMISS_TASK src_state: OVERVIEW dst_state: BACKGROUND is_swipe_up_enabled: true } } } Change-Id: I5569b80e2e1f35661bc5e9e343c6c298791a1ec1 --- .../src/com/android/quickstep/views/RecentsView.java | 6 ++++-- .../quickstep/logging/StatsLogCompatManager.java | 11 +++++++++++ .../android/launcher3/logging/StatsLogManager.java | 1 + 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java index 9b157d163a..1bf77f53cb 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/RecentsView.java @@ -97,6 +97,7 @@ import com.android.launcher3.graphics.RotationMode; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; +import com.android.launcher3.util.ComponentKey; import com.android.launcher3.util.OverScroller; import com.android.launcher3.util.PendingAnimation; import com.android.launcher3.util.Themes; @@ -1051,9 +1052,10 @@ public abstract class RecentsView extends PagedView impl if (task != null) { ActivityManagerWrapper.getInstance().removeTask(task.key.id); if (shouldLog) { + ComponentKey componentKey = TaskUtils.getLaunchComponentKeyForTask(task.key); mActivity.getUserEventDispatcher().logTaskLaunchOrDismiss( - onEndListener.logAction, Direction.UP, index, - TaskUtils.getLaunchComponentKeyForTask(task.key)); + onEndListener.logAction, Direction.UP, index, componentKey); + mActivity.getStatsLogManager().logTaskDismiss(this, componentKey); } } } diff --git a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java index 2f411efc7b..13a8dc26aa 100644 --- a/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java +++ b/quickstep/src/com/android/quickstep/logging/StatsLogCompatManager.java @@ -25,6 +25,7 @@ import static android.stats.launcher.nano.Launcher.ALLAPPS; import static android.stats.launcher.nano.Launcher.HOME; import static android.stats.launcher.nano.Launcher.LAUNCH_APP; import static android.stats.launcher.nano.Launcher.LAUNCH_TASK; +import static android.stats.launcher.nano.Launcher.DISMISS_TASK; import static android.stats.launcher.nano.Launcher.BACKGROUND; import static android.stats.launcher.nano.Launcher.OVERVIEW; @@ -74,6 +75,16 @@ public class StatsLogCompatManager extends StatsLogManager { MessageNano.toByteArray(ext), true); } + @Override + public void logTaskDismiss(View v, ComponentKey componentKey) { + LauncherExtension ext = new LauncherExtension(); + ext.srcTarget = new LauncherTarget[SUPPORTED_TARGET_DEPTH]; + int srcState = OVERVIEW; + fillInLauncherExtension(v, ext); + StatsLogCompat.write(DISMISS_TASK, srcState, BACKGROUND /* dstState */, + MessageNano.toByteArray(ext), true); + } + public static boolean fillInLauncherExtension(View v, LauncherExtension extension) { StatsLogUtils.LogContainerProvider provider = StatsLogUtils.getLaunchProviderRecursive(v); if (v == null || !(v.getTag() instanceof ItemInfo) || provider == null) { diff --git a/src/com/android/launcher3/logging/StatsLogManager.java b/src/com/android/launcher3/logging/StatsLogManager.java index 9b9543ec34..d11d434df1 100644 --- a/src/com/android/launcher3/logging/StatsLogManager.java +++ b/src/com/android/launcher3/logging/StatsLogManager.java @@ -40,5 +40,6 @@ public class StatsLogManager implements ResourceBasedOverride { public void logAppLaunch(View v, Intent intent) { } public void logTaskLaunch(View v, ComponentKey key) { } + public void logTaskDismiss(View v, ComponentKey key) { } public void verify() {} // TODO: should move into robo tests } From cc5b17b351503e53be177b41ae4b7dfdb1c8ce7c Mon Sep 17 00:00:00 2001 From: vadimt Date: Mon, 12 Aug 2019 14:46:48 -0700 Subject: [PATCH 21/31] Improving screenshot path Change-Id: If61bbf0bbc8ace31142bc0e2d598d72ce48de360 --- tests/src/com/android/launcher3/util/rule/FailureWatcher.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java index eef2f24baa..e7a2bcab6b 100644 --- a/tests/src/com/android/launcher3/util/rule/FailureWatcher.java +++ b/tests/src/com/android/launcher3/util/rule/FailureWatcher.java @@ -15,7 +15,6 @@ import java.io.IOException; public class FailureWatcher extends TestWatcher { private static final String TAG = "FailureWatcher"; - private static int sScreenshotCount = 0; final private UiDevice mDevice; public FailureWatcher(UiDevice device) { @@ -40,7 +39,8 @@ public class FailureWatcher extends TestWatcher { protected void failed(Throwable e, Description description) { if (mDevice == null) return; final String pathname = getInstrumentation().getTargetContext(). - getFilesDir().getPath() + "/TaplTestScreenshot" + sScreenshotCount++ + ".png"; + getFilesDir().getPath() + "/TestScreenshot-" + description.getMethodName() + + ".png"; Log.e(TAG, "Failed test " + description.getMethodName() + ", screenshot will be saved to " + pathname + ", track trace is below, UI object dump is further below:\n" + From 02cc84889625ada6f601203e494aae94577db199 Mon Sep 17 00:00:00 2001 From: yingleiw Date: Fri, 2 Aug 2019 16:14:27 -0700 Subject: [PATCH 22/31] Add directional accessibility page actions to PagedView For PagedView, when isPageOrderFlipped is true, it means the LTR mode is flipped. For the "recents" in launcher, isPageOrderFlipped is true. However, this doesn't affect the directional page operations since scrollLeft()/Right() already has correct Rtl considerations. See b/78788182 for more information on the LTR mode. Test: Tested with the "recents" in launcher. Verified that page left action always move pages to the right (so that the next page from the left side shows), and page right actions always move pages to the left (so that the next page from the right side shows). Also tested with the home screen 1/2, 2/2 paging. Bug: 136277517 Change-Id: I965d651c37d258eaa8ea347d1ad6f698f9b590bf --- src/com/android/launcher3/PagedView.java | 31 ++++++++++++++++++++---- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index d2b8d4e300..bbb3915b58 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1562,12 +1562,20 @@ public abstract class PagedView extends ViewGrou final boolean pagesFlipped = isPageOrderFlipped(); info.setScrollable(getPageCount() > 1); if (getCurrentPage() < getPageCount() - 1) { - info.addAction(pagesFlipped ? AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD - : AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + info.addAction(pagesFlipped ? + AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD + : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD); + info.addAction(mIsRtl ? + AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT + : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT); } if (getCurrentPage() > 0) { - info.addAction(pagesFlipped ? AccessibilityNodeInfo.ACTION_SCROLL_FORWARD - : AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + info.addAction(pagesFlipped ? + AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_FORWARD + : AccessibilityNodeInfo.AccessibilityAction.ACTION_SCROLL_BACKWARD); + info.addAction(mIsRtl ? + AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_RIGHT + : AccessibilityNodeInfo.AccessibilityAction.ACTION_PAGE_LEFT); } // Accessibility-wise, PagedView doesn't support long click, so disabling it. @@ -1607,8 +1615,21 @@ public abstract class PagedView extends ViewGrou if (pagesFlipped ? scrollRight() : scrollLeft()) { return true; } + } break; + case android.R.id.accessibilityActionPageRight: { + if (!mIsRtl) { + return scrollRight(); + } else { + return scrollLeft(); + } + } + case android.R.id.accessibilityActionPageLeft: { + if (!mIsRtl) { + return scrollLeft(); + } else { + return scrollRight(); + } } - break; } return false; } From 713cd6fd56bcb8e1345feb905a6636de5593b3d3 Mon Sep 17 00:00:00 2001 From: Alex Mang Date: Thu, 8 Aug 2019 12:22:26 -0700 Subject: [PATCH 23/31] Adding app search improvement flag Bug: 125027540 Change-Id: I68fd7710b108e9f2fa1f5ff335326585a92deb23 Merged-In: I68fd7710b108e9f2fa1f5ff335326585a92deb23 (cherry picked from commit d27e31995b337625dcc65a255289b26b23bb7a3a) --- src/com/android/launcher3/config/BaseFlags.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index 54efcb7868..31e8267f41 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -112,6 +112,10 @@ abstract class BaseFlags { "FAKE_LANDSCAPE_UI", false, "Rotate launcher UI instead of using transposed layout"); + public static final TogglableFlag APP_SEARCH_IMPROVEMENTS = new TogglableFlag( + "APP_SEARCH_IMPROVEMENTS", false, + "Adds localized title and keyword search and ranking"); + public static void initialize(Context context) { // Avoid the disk read for user builds if (Utilities.IS_DEBUG_DEVICE) { From 7ca46ba2ee185cf9a199172b94bf37163d06f2d7 Mon Sep 17 00:00:00 2001 From: Felipe Leme Date: Wed, 14 Aug 2019 09:40:04 -0700 Subject: [PATCH 24/31] Fixed PredictionAppTracker as service might not be available on device. Fixes: 139416391 Bug: 135218095 Test: echo 'in TreeHugger we trust' Change-Id: Iea89b3d379792327657e01869c9494975e7b0306 (cherry picked from commit 214a45ee02674712542dabdb7d8c70ace21f4501) --- .../android/launcher3/appprediction/PredictionAppTracker.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java index 8f1282dedc..24fc61bef9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java @@ -95,6 +95,10 @@ public class PredictionAppTracker extends AppLaunchTracker { private AppPredictor createPredictor(Client client, int count) { AppPredictionManager apm = mContext.getSystemService(AppPredictionManager.class); + if (apm == null) { + return null; + } + AppPredictor predictor = apm.createAppPredictionSession( new AppPredictionContext.Builder(mContext) .setUiSurface(client.id) From 934ebd087b90ad0afbb620f16c14843ea640cc3b Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 6 Aug 2019 09:48:36 -0700 Subject: [PATCH 25/31] Adding support for storing keywords in iconCache Change-Id: I1183e63a6556ebfb3eee5df23d149e09728193a9 Merged-In: I1183e63a6556ebfb3eee5df23d149e09728193a9 (cherry picked from commit e529a86fbd2eaf7b13575af6b6adf0eb6e25e45c) --- .../launcher3/icons/cache/BaseIconCache.java | 87 +++++++++++-------- .../launcher3/icons/cache/CachingLogic.java | 11 +++ .../android/quickstep/TaskOverlayFactory.java | 5 +- .../com/android/quickstep/RecentsModel.java | 6 +- res/values/config.xml | 1 + src/com/android/launcher3/IconProvider.java | 9 +- .../android/launcher3/LauncherAppState.java | 4 +- .../launcher3/graphics/DrawableFactory.java | 8 +- .../android/launcher3/icons/IconCache.java | 10 +-- ...java => LauncherActivityCachingLogic.java} | 25 ++++-- .../launcher3/model/AppLaunchTracker.java | 9 +- .../android/launcher3/model/LoaderTask.java | 6 +- .../popup/SystemShortcutFactory.java | 9 +- .../util/MainThreadInitializedObject.java | 13 ++- 14 files changed, 124 insertions(+), 79 deletions(-) rename src/com/android/launcher3/icons/{LauncherActivtiyCachingLogic.java => LauncherActivityCachingLogic.java} (67%) diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java index d84633d563..36d1c3eccc 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/BaseIconCache.java @@ -36,12 +36,16 @@ import android.graphics.BitmapFactory; import android.graphics.drawable.Drawable; import android.os.Build; import android.os.Handler; +import android.os.LocaleList; import android.os.Looper; import android.os.Process; import android.os.UserHandle; import android.text.TextUtils; import android.util.Log; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import com.android.launcher3.icons.BaseIconFactory; import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.icons.BitmapRenderer; @@ -57,8 +61,6 @@ import java.util.Map; import java.util.Set; import java.util.function.Supplier; -import androidx.annotation.NonNull; - public abstract class BaseIconCache { private static final String TAG = "BaseIconCache"; @@ -84,6 +86,7 @@ public abstract class BaseIconCache { protected int mIconDpi; protected IconDB mIconDb; + protected LocaleList mLocaleList = LocaleList.getEmptyLocaleList(); protected String mSystemState = ""; private final String mDbFileName; @@ -227,12 +230,12 @@ public abstract class BaseIconCache { /** * Refreshes the system state definition used to check the validity of the cache. It - * incorporates all the properties that can affect the cache like locale and system-version. + * incorporates all the properties that can affect the cache like the list of enabled locale + * and system-version. */ private void updateSystemState() { - final String locale = - mContext.getResources().getConfiguration().getLocales().toLanguageTags(); - mSystemState = locale + "," + Build.VERSION.SDK_INT; + mLocaleList = mContext.getResources().getConfiguration().getLocales(); + mSystemState = mLocaleList.toLanguageTags() + "," + Build.VERSION.SDK_INT; } protected String getIconSystemState(String packageName) { @@ -269,7 +272,7 @@ public abstract class BaseIconCache { mCache.put(key, entry); ContentValues values = newContentValues(entry, entry.title.toString(), - componentName.getPackageName()); + componentName.getPackageName(), cachingLogic.getKeywords(object, mLocaleList)); addIconToDB(values, componentName, info, userSerial); } @@ -445,7 +448,7 @@ public abstract class BaseIconCache { // Add the icon in the DB here, since these do not get written during // package updates. ContentValues values = newContentValues( - iconInfo, entry.title.toString(), packageName); + iconInfo, entry.title.toString(), packageName, null); addIconToDB(values, cacheKey.componentName, info, getSerialNumberForUser(user)); } catch (NameNotFoundException e) { @@ -504,23 +507,35 @@ public abstract class BaseIconCache { return false; } - static final class IconDB extends SQLiteCacheHelper { - private final static int RELEASE_VERSION = 26; + /** + * Returns a cursor for an arbitrary query to the cache db + */ + public synchronized Cursor queryCacheDb(String[] columns, String selection, + String[] selectionArgs) { + return mIconDb.query(columns, selection, selectionArgs); + } - public final static String TABLE_NAME = "icons"; - public final static String COLUMN_ROWID = "rowid"; - public final static String COLUMN_COMPONENT = "componentName"; - public final static String COLUMN_USER = "profileId"; - public final static String COLUMN_LAST_UPDATED = "lastUpdated"; - public final static String COLUMN_VERSION = "version"; - public final static String COLUMN_ICON = "icon"; - public final static String COLUMN_ICON_COLOR = "icon_color"; - public final static String COLUMN_LABEL = "label"; - public final static String COLUMN_SYSTEM_STATE = "system_state"; + /** + * Cache class to store the actual entries on disk + */ + public static final class IconDB extends SQLiteCacheHelper { + private static final int RELEASE_VERSION = 27; - public final static String[] COLUMNS_HIGH_RES = new String[] { + public static final String TABLE_NAME = "icons"; + public static final String COLUMN_ROWID = "rowid"; + public static final String COLUMN_COMPONENT = "componentName"; + public static final String COLUMN_USER = "profileId"; + public static final String COLUMN_LAST_UPDATED = "lastUpdated"; + public static final String COLUMN_VERSION = "version"; + public static final String COLUMN_ICON = "icon"; + public static final String COLUMN_ICON_COLOR = "icon_color"; + public static final String COLUMN_LABEL = "label"; + public static final String COLUMN_SYSTEM_STATE = "system_state"; + public static final String COLUMN_KEYWORDS = "keywords"; + + public static final String[] COLUMNS_HIGH_RES = new String[] { IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL, IconDB.COLUMN_ICON }; - public final static String[] COLUMNS_LOW_RES = new String[] { + public static final String[] COLUMNS_LOW_RES = new String[] { IconDB.COLUMN_ICON_COLOR, IconDB.COLUMN_LABEL }; public IconDB(Context context, String dbFileName, int iconPixelSize) { @@ -529,21 +544,23 @@ public abstract class BaseIconCache { @Override protected void onCreateTable(SQLiteDatabase db) { - db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + - COLUMN_COMPONENT + " TEXT NOT NULL, " + - COLUMN_USER + " INTEGER NOT NULL, " + - COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " + - COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " + - COLUMN_ICON + " BLOB, " + - COLUMN_ICON_COLOR + " INTEGER NOT NULL DEFAULT 0, " + - COLUMN_LABEL + " TEXT, " + - COLUMN_SYSTEM_STATE + " TEXT, " + - "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " + - ");"); + db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" + + COLUMN_COMPONENT + " TEXT NOT NULL, " + + COLUMN_USER + " INTEGER NOT NULL, " + + COLUMN_LAST_UPDATED + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_VERSION + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_ICON + " BLOB, " + + COLUMN_ICON_COLOR + " INTEGER NOT NULL DEFAULT 0, " + + COLUMN_LABEL + " TEXT, " + + COLUMN_SYSTEM_STATE + " TEXT, " + + COLUMN_KEYWORDS + " TEXT, " + + "PRIMARY KEY (" + COLUMN_COMPONENT + ", " + COLUMN_USER + ") " + + ");"); } } - private ContentValues newContentValues(BitmapInfo bitmapInfo, String label, String packageName) { + private ContentValues newContentValues(BitmapInfo bitmapInfo, String label, + String packageName, @Nullable String keywords) { ContentValues values = new ContentValues(); values.put(IconDB.COLUMN_ICON, bitmapInfo.isLowRes() ? null : GraphicsUtils.flattenBitmap(bitmapInfo.icon)); @@ -551,7 +568,7 @@ public abstract class BaseIconCache { values.put(IconDB.COLUMN_LABEL, label); values.put(IconDB.COLUMN_SYSTEM_STATE, getIconSystemState(packageName)); - + values.put(IconDB.COLUMN_KEYWORDS, keywords); return values; } diff --git a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java index addb51fa78..09f59b84c2 100644 --- a/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java +++ b/iconloaderlib/src/com/android/launcher3/icons/cache/CachingLogic.java @@ -17,8 +17,11 @@ package com.android.launcher3.icons.cache; import android.content.ComponentName; import android.content.Context; +import android.os.LocaleList; import android.os.UserHandle; +import androidx.annotation.Nullable; + import com.android.launcher3.icons.BitmapInfo; public interface CachingLogic { @@ -30,4 +33,12 @@ public interface CachingLogic { CharSequence getLabel(T object); void loadIcon(Context context, T object, BitmapInfo target); + + /** + * Provides a option list of keywords to associate with this object + */ + @Nullable + default String getKeywords(T object, LocaleList localeList) { + return null; + } } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java index b90f6c2b17..17457aace6 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java @@ -16,6 +16,8 @@ package com.android.quickstep; +import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; + import android.graphics.Matrix; import android.view.View; @@ -47,8 +49,7 @@ public class TaskOverlayFactory implements ResourceBasedOverride { }; public static final MainThreadInitializedObject INSTANCE = - new MainThreadInitializedObject<>(c -> Overrides.getObject(TaskOverlayFactory.class, - c, R.string.task_overlay_factory_class)); + forOverride(TaskOverlayFactory.class, R.string.task_overlay_factory_class); public List getEnabledShortcuts(TaskView taskView) { final ArrayList shortcuts = new ArrayList<>(); diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java index 9f12484589..dfab43459d 100644 --- a/quickstep/src/com/android/quickstep/RecentsModel.java +++ b/quickstep/src/com/android/quickstep/RecentsModel.java @@ -16,15 +16,12 @@ package com.android.quickstep; import static com.android.quickstep.TaskUtils.checkCurrentOrManagedUserId; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SUPPORTS_WINDOW_CORNERS; -import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_WINDOW_CORNER_RADIUS; import android.annotation.TargetApi; import android.app.ActivityManager; import android.content.ComponentCallbacks2; import android.content.Context; import android.os.Build; -import android.os.Bundle; import android.os.HandlerThread; import android.os.Process; import android.os.RemoteException; @@ -35,7 +32,6 @@ import com.android.systemui.shared.recents.ISystemUiProxy; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.TaskStackChangeListener; import java.util.ArrayList; @@ -52,7 +48,7 @@ public class RecentsModel extends TaskStackChangeListener { // We do not need any synchronization for this variable as its only written on UI thread. public static final MainThreadInitializedObject INSTANCE = - new MainThreadInitializedObject<>(c -> new RecentsModel(c)); + new MainThreadInitializedObject<>(RecentsModel::new); private final List mThumbnailChangeListeners = new ArrayList<>(); private final Context mContext; diff --git a/res/values/config.xml b/res/values/config.xml index 638a411be6..038718473b 100644 --- a/res/values/config.xml +++ b/res/values/config.xml @@ -72,6 +72,7 @@ + diff --git a/src/com/android/launcher3/IconProvider.java b/src/com/android/launcher3/IconProvider.java index e1ef9548cd..0f006f7c19 100644 --- a/src/com/android/launcher3/IconProvider.java +++ b/src/com/android/launcher3/IconProvider.java @@ -1,16 +1,17 @@ package com.android.launcher3; -import android.content.Context; +import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; + import android.content.pm.LauncherActivityInfo; import android.graphics.drawable.Drawable; +import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.ResourceBasedOverride; public class IconProvider implements ResourceBasedOverride { - public static IconProvider newInstance(Context context) { - return Overrides.getObject(IconProvider.class, context, R.string.icon_provider_class); - } + public static MainThreadInitializedObject INSTANCE = + forOverride(IconProvider.class, R.string.icon_provider_class); public IconProvider() { } diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index d07638a5c1..2a801d6ef8 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -19,14 +19,12 @@ package com.android.launcher3; import static com.android.launcher3.InvariantDeviceProfile.CHANGE_FLAG_ICON_PARAMS; import static com.android.launcher3.util.SecureSettingsObserver.newNotificationSettingsObserver; -import android.app.KeyguardManager; import android.content.ComponentName; import android.content.ContentProviderClient; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.os.Handler; -import android.os.Process; import android.util.Log; import com.android.launcher3.compat.LauncherAppsCompat; @@ -46,7 +44,7 @@ public class LauncherAppState { // We do not need any synchronization for this variable as its only written on UI thread. private static final MainThreadInitializedObject INSTANCE = - new MainThreadInitializedObject<>((c) -> new LauncherAppState(c)); + new MainThreadInitializedObject<>(LauncherAppState::new); private final Context mContext; private final LauncherModel mModel; diff --git a/src/com/android/launcher3/graphics/DrawableFactory.java b/src/com/android/launcher3/graphics/DrawableFactory.java index c9566cb145..288749fa7e 100644 --- a/src/com/android/launcher3/graphics/DrawableFactory.java +++ b/src/com/android/launcher3/graphics/DrawableFactory.java @@ -17,6 +17,7 @@ package com.android.launcher3.graphics; import static com.android.launcher3.graphics.IconShape.getShapePath; +import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; import android.content.Context; import android.content.pm.ActivityInfo; @@ -31,6 +32,8 @@ import android.os.Process; import android.os.UserHandle; import android.util.ArrayMap; +import androidx.annotation.UiThread; + import com.android.launcher3.FastBitmapDrawable; import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.R; @@ -38,16 +41,13 @@ import com.android.launcher3.icons.BitmapInfo; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.ResourceBasedOverride; -import androidx.annotation.UiThread; - /** * Factory for creating new drawables. */ public class DrawableFactory implements ResourceBasedOverride { public static final MainThreadInitializedObject INSTANCE = - new MainThreadInitializedObject<>(c -> Overrides.getObject(DrawableFactory.class, - c.getApplicationContext(), R.string.drawable_factory_class)); + forOverride(DrawableFactory.class, R.string.drawable_factory_class); protected final UserHandle mMyUser = Process.myUserHandle(); protected final ArrayMap mUserBadges = new ArrayMap<>(); diff --git a/src/com/android/launcher3/icons/IconCache.java b/src/com/android/launcher3/icons/IconCache.java index 648445e40c..55d58b9c09 100644 --- a/src/com/android/launcher3/icons/IconCache.java +++ b/src/com/android/launcher3/icons/IconCache.java @@ -29,6 +29,8 @@ import android.os.Process; import android.os.UserHandle; import android.util.Log; +import androidx.annotation.NonNull; + import com.android.launcher3.AppInfo; import com.android.launcher3.IconProvider; import com.android.launcher3.InvariantDeviceProfile; @@ -36,8 +38,8 @@ import com.android.launcher3.ItemInfoWithIcon; import com.android.launcher3.LauncherFiles; import com.android.launcher3.LauncherModel; import com.android.launcher3.MainThreadExecutor; -import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.Utilities; +import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.UserManagerCompat; import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; @@ -50,8 +52,6 @@ import com.android.launcher3.util.Preconditions; import java.util.function.Supplier; -import androidx.annotation.NonNull; - /** * Cache of application icons. Icons can be made from any thread. */ @@ -75,11 +75,11 @@ public class IconCache extends BaseIconCache { super(context, LauncherFiles.APP_ICONS_DB, LauncherModel.getWorkerLooper(), inv.fillResIconDpi, inv.iconBitmapSize, true /* inMemoryCache */); mComponentWithLabelCachingLogic = new ComponentCachingLogic(context); - mLauncherActivityInfoCachingLogic = new LauncherActivtiyCachingLogic(this); + mLauncherActivityInfoCachingLogic = LauncherActivityCachingLogic.newInstance(context); mLauncherApps = LauncherAppsCompat.getInstance(mContext); mUserManager = UserManagerCompat.getInstance(mContext); mInstantAppResolver = InstantAppResolver.newInstance(mContext); - mIconProvider = IconProvider.newInstance(context); + mIconProvider = IconProvider.INSTANCE.get(context); } @Override diff --git a/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java similarity index 67% rename from src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java rename to src/com/android/launcher3/icons/LauncherActivityCachingLogic.java index 7c996339bd..f9a94daf53 100644 --- a/src/com/android/launcher3/icons/LauncherActivtiyCachingLogic.java +++ b/src/com/android/launcher3/icons/LauncherActivityCachingLogic.java @@ -20,14 +20,23 @@ import android.content.Context; import android.content.pm.LauncherActivityInfo; import android.os.UserHandle; +import com.android.launcher3.IconProvider; +import com.android.launcher3.R; import com.android.launcher3.icons.cache.CachingLogic; +import com.android.launcher3.util.ResourceBasedOverride; -public class LauncherActivtiyCachingLogic implements CachingLogic { +/** + * Caching logic for LauncherActivityInfo. + */ +public class LauncherActivityCachingLogic + implements CachingLogic, ResourceBasedOverride { - private final IconCache mCache; - - public LauncherActivtiyCachingLogic(IconCache cache) { - mCache = cache; + /** + * Creates and returns a new instance + */ + public static LauncherActivityCachingLogic newInstance(Context context) { + return Overrides.getObject(LauncherActivityCachingLogic.class, context, + R.string.launcher_activity_logic_class); } @Override @@ -49,8 +58,10 @@ public class LauncherActivtiyCachingLogic implements CachingLogic INSTANCE = - new MainThreadInitializedObject<>(c -> - getObject(AppLaunchTracker.class, c, R.string.app_launch_tracker_class)); + forOverride(AppLaunchTracker.class, R.string.app_launch_tracker_class); public void onStartShortcut(String packageName, String shortcutId, UserHandle user, @Nullable String container) { } diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 0138572d0c..4b01b5ed17 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -49,8 +49,8 @@ import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherAppWidgetInfo; import com.android.launcher3.LauncherModel; import com.android.launcher3.LauncherSettings; -import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.Utilities; +import com.android.launcher3.WorkspaceItemInfo; import com.android.launcher3.compat.AppWidgetManagerCompat; import com.android.launcher3.compat.LauncherAppsCompat; import com.android.launcher3.compat.PackageInstallerCompat; @@ -61,7 +61,7 @@ import com.android.launcher3.folder.FolderIconPreviewVerifier; import com.android.launcher3.icons.ComponentWithLabel; import com.android.launcher3.icons.ComponentWithLabel.ComponentCachingLogic; import com.android.launcher3.icons.IconCache; -import com.android.launcher3.icons.LauncherActivtiyCachingLogic; +import com.android.launcher3.icons.LauncherActivityCachingLogic; import com.android.launcher3.icons.LauncherIcons; import com.android.launcher3.icons.cache.IconCacheUpdateHandler; import com.android.launcher3.logging.FileLog; @@ -196,7 +196,7 @@ public class LoaderTask implements Runnable { IconCacheUpdateHandler updateHandler = mIconCache.getUpdateHandler(); setIgnorePackages(updateHandler); updateHandler.updateIcons(allActivityList, - new LauncherActivtiyCachingLogic(mApp.getIconCache()), + LauncherActivityCachingLogic.newInstance(mApp.getContext()), mApp.getModel()::onPackageIconsUpdated); // Take a break diff --git a/src/com/android/launcher3/popup/SystemShortcutFactory.java b/src/com/android/launcher3/popup/SystemShortcutFactory.java index 516fafad54..37a209289e 100644 --- a/src/com/android/launcher3/popup/SystemShortcutFactory.java +++ b/src/com/android/launcher3/popup/SystemShortcutFactory.java @@ -15,6 +15,10 @@ */ package com.android.launcher3.popup; +import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; + +import androidx.annotation.NonNull; + import com.android.launcher3.ItemInfo; import com.android.launcher3.Launcher; import com.android.launcher3.R; @@ -24,13 +28,10 @@ import com.android.launcher3.util.ResourceBasedOverride; import java.util.ArrayList; import java.util.List; -import androidx.annotation.NonNull; - public class SystemShortcutFactory implements ResourceBasedOverride { public static final MainThreadInitializedObject INSTANCE = - new MainThreadInitializedObject<>(c -> Overrides.getObject( - SystemShortcutFactory.class, c, R.string.system_shortcut_factory_class)); + forOverride(SystemShortcutFactory.class, R.string.system_shortcut_factory_class); /** Note that these are in order of priority. */ private final SystemShortcut[] mAllShortcuts; diff --git a/src/com/android/launcher3/util/MainThreadInitializedObject.java b/src/com/android/launcher3/util/MainThreadInitializedObject.java index 2ee0328597..e185a31990 100644 --- a/src/com/android/launcher3/util/MainThreadInitializedObject.java +++ b/src/com/android/launcher3/util/MainThreadInitializedObject.java @@ -18,12 +18,13 @@ package com.android.launcher3.util; import android.content.Context; import android.os.Looper; +import androidx.annotation.VisibleForTesting; + import com.android.launcher3.MainThreadExecutor; +import com.android.launcher3.util.ResourceBasedOverride.Overrides; import java.util.concurrent.ExecutionException; -import androidx.annotation.VisibleForTesting; - /** * Utility class for defining singletons which are initiated on main thread. */ @@ -60,6 +61,14 @@ public class MainThreadInitializedObject { mValue = value; } + /** + * Initializes a provider based on resource overrides + */ + public static MainThreadInitializedObject forOverride( + Class clazz, int resourceId) { + return new MainThreadInitializedObject<>(c -> Overrides.getObject(clazz, c, resourceId)); + } + public interface ObjectProvider { T get(Context context); From 849b201de0608160d5a132c020e28faad286c38b Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 14 Aug 2019 15:38:34 -0700 Subject: [PATCH 26/31] Temporary workaround for UIAutomator not recognizing a new window Bug: 112282235 Change-Id: I145bb88d72689f8c6d61ba3481f25d8978933ab2 --- .../com/android/launcher3/tapl/Launchable.java | 14 ++++++++------ .../launcher3/tapl/LauncherInstrumentation.java | 2 +- .../com/android/launcher3/tapl/OverviewTask.java | 14 +++++++------- 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/tests/tapl/com/android/launcher3/tapl/Launchable.java b/tests/tapl/com/android/launcher3/tapl/Launchable.java index 82af7b03ac..df80a51fd7 100644 --- a/tests/tapl/com/android/launcher3/tapl/Launchable.java +++ b/tests/tapl/com/android/launcher3/tapl/Launchable.java @@ -16,6 +16,8 @@ package com.android.launcher3.tapl; +import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; + import android.graphics.Point; import androidx.test.uiautomator.By; @@ -23,13 +25,10 @@ import androidx.test.uiautomator.BySelector; import androidx.test.uiautomator.UiObject2; import androidx.test.uiautomator.Until; -import com.android.launcher3.testing.TestProtocol; - /** * Ancestor for AppIcon and AppMenuItem. */ abstract class Launchable { - private static final int WAIT_TIME_MS = 60000; protected final LauncherInstrumentation mLauncher; protected final UiObject2 mObject; @@ -53,9 +52,12 @@ abstract class Launchable { private Background launch(BySelector selector) { LauncherInstrumentation.log("Launchable.launch before click " + mObject.getVisibleCenter() + " in " + mObject.getVisibleBounds()); - mLauncher.assertTrue( - "Launching an app didn't open a new window: " + mObject.getText(), - mObject.clickAndWait(Until.newWindow(), WAIT_TIME_MS)); + + mLauncher.executeAndWaitForEvent( + () -> mObject.click(), + event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED, + "Launching an app didn't open a new window: " + mObject.getText()); + mLauncher.assertTrue( "App didn't start: " + selector, mLauncher.getDevice().wait(Until.hasObject(selector), diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index c012628c15..34879a9eb7 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -124,7 +124,7 @@ public final class LauncherInstrumentation { private static final String APPS_RES_ID = "apps_view"; private static final String OVERVIEW_RES_ID = "overview_panel"; private static final String WIDGETS_RES_ID = "widgets_list_view"; - public static final int WAIT_TIME_MS = 60000; + public static final int WAIT_TIME_MS = 10000; private static final String SYSTEMUI_PACKAGE = "com.android.systemui"; private static WeakReference sActiveContainer = new WeakReference<>(null); diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java index 6e3332260b..91f0fc4c83 100644 --- a/tests/tapl/com/android/launcher3/tapl/OverviewTask.java +++ b/tests/tapl/com/android/launcher3/tapl/OverviewTask.java @@ -16,18 +16,16 @@ package com.android.launcher3.tapl; +import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; + import android.graphics.Rect; import androidx.test.uiautomator.UiObject2; -import androidx.test.uiautomator.Until; - -import com.android.launcher3.testing.TestProtocol; /** * A recent task in the overview panel carousel. */ public final class OverviewTask { - private static final long WAIT_TIME_MS = 60000; private final LauncherInstrumentation mLauncher; private final UiObject2 mTask; private final BaseOverview mOverview; @@ -66,9 +64,11 @@ public final class OverviewTask { verifyActiveContainer(); try (LauncherInstrumentation.Closable c = mLauncher.addContextLayer( "clicking an overview task")) { - mLauncher.assertTrue("Launching task didn't open a new window: " + - mTask.getParent().getContentDescription(), - mTask.clickAndWait(Until.newWindow(), WAIT_TIME_MS)); + mLauncher.executeAndWaitForEvent( + () -> mTask.click(), + event -> event.getEventType() == TYPE_WINDOW_STATE_CHANGED, + "Launching task didn't open a new window: " + + mTask.getParent().getContentDescription()); } return new Background(mLauncher); } From a81be5003ce6c951a012578746c7d5c33cf66b98 Mon Sep 17 00:00:00 2001 From: vadimt Date: Wed, 14 Aug 2019 17:16:57 -0700 Subject: [PATCH 27/31] Extending the list of test owners Otherwise, changes in tests would require my-only approval. Change-Id: Ia957a28a5a8e55dc2ee4efdf9a46c91511d3e611 --- quickstep/tests/OWNERS | 3 +++ tests/OWNERS | 3 +++ 2 files changed, 6 insertions(+) diff --git a/quickstep/tests/OWNERS b/quickstep/tests/OWNERS index 046d871163..02e8ebcaba 100644 --- a/quickstep/tests/OWNERS +++ b/quickstep/tests/OWNERS @@ -1 +1,4 @@ vadimt@google.com +sunnygoyal@google.com +winsonc@google.com +hyunyoungs@google.com diff --git a/tests/OWNERS b/tests/OWNERS index 046d871163..02e8ebcaba 100644 --- a/tests/OWNERS +++ b/tests/OWNERS @@ -1 +1,4 @@ vadimt@google.com +sunnygoyal@google.com +winsonc@google.com +hyunyoungs@google.com From d4204437de888756d2cf8ccb8e9244960bd6d423 Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Tue, 13 Aug 2019 15:57:15 -0700 Subject: [PATCH 28/31] Make TogglableFlag backed by DeviceConfig for e2e testing Bug: 138964490 TL;DR;; need this to be part of QQ1 or QD1 to verify if DeviceConfig can be supported for launcher toggleableFlags. Not handled in this CL: - When flag is locally modified, that will override the flag value How that scenario is handled should be discussed separately and is not within scope of this CL. Change-Id: I2e6694a40bee9202ed0b0d559e3b5607634071bf --- .../launcher3/uioverrides/TogglableFlag.java | 32 ++++++++ .../launcher3/config/FlagOverrideRule.java | 8 +- .../android/launcher3/config/BaseFlags.java | 74 ++++--------------- .../launcher3/config/FlagTogglerPrefUi.java | 11 +-- .../launcher3/uioverrides/TogglableFlag.java | 31 ++++++++ 5 files changed, 87 insertions(+), 69 deletions(-) create mode 100644 quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java create mode 100644 src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java diff --git a/quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java b/quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java new file mode 100644 index 0000000000..e425088147 --- /dev/null +++ b/quickstep/src/com/android/launcher3/uioverrides/TogglableFlag.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 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.uioverrides; + +import android.provider.DeviceConfig; +import com.android.launcher3.config.BaseFlags.BaseTogglableFlag; + +public class TogglableFlag extends BaseTogglableFlag { + + public TogglableFlag(String key, boolean defaultValue, String description) { + super(key, defaultValue, description); + } + + @Override + public boolean getInitialValue(boolean value) { + return DeviceConfig.getBoolean("launcher", getKey(), value); + } +} diff --git a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java index 92bcc64348..a3d121676f 100644 --- a/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java +++ b/robolectric_tests/src/com/android/launcher3/config/FlagOverrideRule.java @@ -1,6 +1,8 @@ package com.android.launcher3.config; +import com.android.launcher3.config.BaseFlags.BaseTogglableFlag; +import com.android.launcher3.uioverrides.TogglableFlag; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.Statement; @@ -70,7 +72,7 @@ public final class FlagOverrideRule implements TestRule { }; } - private void override(BaseFlags.TogglableFlag flag, boolean newValue) { + private void override(BaseTogglableFlag flag, boolean newValue) { if (!ruleInProgress) { throw new IllegalStateException( "Rule isn't in progress. Did you remember to mark it with @Rule?"); @@ -93,7 +95,7 @@ public final class FlagOverrideRule implements TestRule { private void applyAnnotation(FlagOverride flagOverride) { boolean found = false; - for (BaseFlags.TogglableFlag flag : FeatureFlags.getTogglableFlags()) { + for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) { if (flag.getKey().equals(flagOverride.key())) { override(flag, flagOverride.value()); found = true; @@ -109,7 +111,7 @@ public final class FlagOverrideRule implements TestRule { * Resets all flags to their default values. */ private void clearOverrides() { - for (BaseFlags.TogglableFlag flag : FeatureFlags.getTogglableFlags()) { + for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) { flag.setForTests(flag.getDefaultValue()); } } diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java index 54efcb7868..6436e4c1e3 100644 --- a/src/com/android/launcher3/config/BaseFlags.java +++ b/src/com/android/launcher3/config/BaseFlags.java @@ -18,20 +18,16 @@ package com.android.launcher3.config; import static androidx.core.util.Preconditions.checkNotNull; -import android.content.ContentResolver; import android.content.Context; import android.content.SharedPreferences; -import android.database.ContentObserver; -import android.os.Handler; -import android.os.Looper; -import android.provider.Settings; import androidx.annotation.GuardedBy; import androidx.annotation.Keep; -import androidx.annotation.VisibleForTesting; +import androidx.annotation.VisibleForTesting; import com.android.launcher3.Utilities; +import com.android.launcher3.uioverrides.TogglableFlag; import java.util.ArrayList; import java.util.List; import java.util.SortedMap; @@ -41,11 +37,9 @@ import java.util.TreeMap; * Defines a set of flags used to control various launcher behaviors. * *

All the flags should be defined here with appropriate default values. - * - *

This class is kept package-private to prevent direct access. */ @Keep -abstract class BaseFlags { +public abstract class BaseFlags { private static final Object sLock = new Object(); @GuardedBy("sLock") @@ -116,7 +110,7 @@ abstract class BaseFlags { // Avoid the disk read for user builds if (Utilities.IS_DEBUG_DEVICE) { synchronized (sLock) { - for (TogglableFlag flag : sFlags) { + for (BaseTogglableFlag flag : sFlags) { flag.initialize(context); } } @@ -132,27 +126,27 @@ abstract class BaseFlags { SortedMap flagsByKey = new TreeMap<>(); synchronized (sLock) { for (TogglableFlag flag : sFlags) { - flagsByKey.put(flag.key, flag); + flagsByKey.put(((BaseTogglableFlag) flag).getKey(), flag); } } return new ArrayList<>(flagsByKey.values()); } - public static class TogglableFlag { + public static abstract class BaseTogglableFlag { private final String key; private final boolean defaultValue; private final String description; private boolean currentValue; - TogglableFlag( + public BaseTogglableFlag( String key, boolean defaultValue, String description) { this.key = checkNotNull(key); - this.currentValue = this.defaultValue = defaultValue; + this.currentValue = this.defaultValue = getInitialValue(defaultValue); this.description = checkNotNull(description); synchronized (sLock) { - sFlags.add(this); + sFlags.add((TogglableFlag)this); } } @@ -162,14 +156,16 @@ abstract class BaseFlags { currentValue = value; } - @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE) public String getKey() { return key; } + void initialize(Context context) { currentValue = getFromStorage(context, defaultValue); } + protected abstract boolean getInitialValue(boolean value); + public void updateStorage(Context context, boolean value) { SharedPreferences.Editor editor = context.getSharedPreferences(FLAGS_PREF_NAME, Context.MODE_PRIVATE).edit(); @@ -213,7 +209,7 @@ abstract class BaseFlags { return true; } if (o instanceof TogglableFlag) { - TogglableFlag that = (TogglableFlag) o; + BaseTogglableFlag that = (BaseTogglableFlag) o; return (this.key.equals(that.getKey())) && (this.defaultValue == that.getDefaultValue()) && (this.description.equals(that.getDescription())); @@ -233,48 +229,4 @@ abstract class BaseFlags { return h$; } } - - /** - * Stores the FeatureFlag's value in Settings.Global instead of our SharedPrefs. - * This is useful if we want to be able to control this flag from another process. - */ - public static final class ToggleableGlobalSettingsFlag extends TogglableFlag { - private ContentResolver contentResolver; - - ToggleableGlobalSettingsFlag(String key, boolean defaultValue, String description) { - super(key, defaultValue, description); - } - - @Override - public void initialize(Context context) { - contentResolver = context.getContentResolver(); - contentResolver.registerContentObserver(Settings.Global.getUriFor(getKey()), true, - new ContentObserver(new Handler(Looper.getMainLooper())) { - @Override - public void onChange(boolean selfChange) { - superInitialize(context); - }}); - superInitialize(context); - } - - private void superInitialize(Context context) { - super.initialize(context); - } - - @Override - public void updateStorage(Context context, boolean value) { - if (contentResolver == null) { - return; - } - Settings.Global.putInt(contentResolver, getKey(), value ? 1 : 0); - } - - @Override - boolean getFromStorage(Context context, boolean defaultValue) { - if (contentResolver == null) { - return defaultValue; - } - return Settings.Global.getInt(contentResolver, getKey(), defaultValue ? 1 : 0) == 1; - } - } } diff --git a/src/com/android/launcher3/config/FlagTogglerPrefUi.java b/src/com/android/launcher3/config/FlagTogglerPrefUi.java index 5ecb186500..54e5322bd5 100644 --- a/src/com/android/launcher3/config/FlagTogglerPrefUi.java +++ b/src/com/android/launcher3/config/FlagTogglerPrefUi.java @@ -26,12 +26,13 @@ import android.view.MenuItem; import android.widget.Toast; import com.android.launcher3.R; -import com.android.launcher3.config.BaseFlags.TogglableFlag; import androidx.preference.PreferenceDataStore; import androidx.preference.PreferenceFragment; import androidx.preference.PreferenceGroup; import androidx.preference.SwitchPreference; +import com.android.launcher3.config.BaseFlags.BaseTogglableFlag; +import com.android.launcher3.uioverrides.TogglableFlag; /** * Dev-build only UI allowing developers to toggle flag settings. See {@link FeatureFlags}. @@ -62,7 +63,7 @@ public final class FlagTogglerPrefUi { @Override public boolean getBoolean(String key, boolean defaultValue) { - for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) { + for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) { if (flag.getKey().equals(key)) { return flag.getFromStorage(mContext, defaultValue); } @@ -83,7 +84,7 @@ public final class FlagTogglerPrefUi { // flag with a different value than the default. That way, when we flip flags in // future, engineers will pick up the new value immediately. To accomplish this, we use a // custom preference data store. - for (TogglableFlag flag : FeatureFlags.getTogglableFlags()) { + for (BaseTogglableFlag flag : FeatureFlags.getTogglableFlags()) { SwitchPreference switchPreference = new SwitchPreference(mContext); switchPreference.setKey(flag.getKey()); switchPreference.setDefaultValue(flag.getDefaultValue()); @@ -99,7 +100,7 @@ public final class FlagTogglerPrefUi { /** * Updates the summary to show the description and whether the flag overrides the default value. */ - private void updateSummary(SwitchPreference switchPreference, TogglableFlag flag) { + private void updateSummary(SwitchPreference switchPreference, BaseTogglableFlag flag) { String onWarning = flag.getDefaultValue() ? "" : "OVERRIDDEN
"; String offWarning = flag.getDefaultValue() ? "OVERRIDDEN
" : ""; switchPreference.setSummaryOn(Html.fromHtml(onWarning + flag.getDescription())); @@ -134,7 +135,7 @@ public final class FlagTogglerPrefUi { } } - private boolean getFlagStateFromSharedPrefs(TogglableFlag flag) { + private boolean getFlagStateFromSharedPrefs(BaseTogglableFlag flag) { return mDataStore.getBoolean(flag.getKey(), flag.getDefaultValue()); } diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java b/src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java new file mode 100644 index 0000000000..e875a3c465 --- /dev/null +++ b/src_ui_overrides/com/android/launcher3/uioverrides/TogglableFlag.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 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.uioverrides; + +import com.android.launcher3.config.BaseFlags.BaseTogglableFlag; + +public class TogglableFlag extends BaseTogglableFlag { + + public TogglableFlag(String key, boolean defaultValue, String description) { + super(key, defaultValue, description); + } + + @Override + public boolean getInitialValue(boolean value) { + return value; + } +} From 47144ca73ce2e888e0cd8216c7116dbae1c5fa48 Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 15 Aug 2019 16:06:58 -0700 Subject: [PATCH 29/31] Logging to catch INJECT PERMISSION problem Bug: 139498375 Change-Id: Ib7b8e1997bae9d4ff9cce7cf8690e42b6fdaaf38 --- .../tapl/com/android/launcher3/tapl/LauncherInstrumentation.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java index 34879a9eb7..9d433527da 100644 --- a/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java +++ b/tests/tapl/com/android/launcher3/tapl/LauncherInstrumentation.java @@ -882,6 +882,7 @@ public final class LauncherInstrumentation { } long movePointer(long downTime, long startTime, long duration, Point from, Point to) { + log("movePointer: " + from + " to " + to); final Point point = new Point(); long steps = duration / GESTURE_STEP_MS; long currentTime = startTime; From 2dac6f8d3065302b365c5c8c37064431058cc4db Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Fri, 16 Aug 2019 10:16:39 -0700 Subject: [PATCH 30/31] Add READ_DEVICE_CONFIG permission Bug: 138964490 Change-Id: I5e119de3d4725aaa0e9c843d1e3d65df2c6c756e --- AndroidManifest-common.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml index 5318a12edd..8db875be90 100644 --- a/AndroidManifest-common.xml +++ b/AndroidManifest-common.xml @@ -43,6 +43,7 @@ +